Multiple table outputs based on one query - sql

I have one table that has 12 conditions (months). I need to produce 12 outputs (tables) for select statements where the only thing that changes is that one condition (month).
Example:
SELECT * FROM table WHERE month = 01;
SELECT * FROM table WHERE month = 02;
SELECT * FROM table WHERE month = 03;
etc.
In reality, the code is pretty large and chunky, I don't feel like copy pasting it numerous times just to change one condition.
Is there a way to write one statement to produce different outputs based on changing condition?
It looks pretty basic to me, but I can't find the answer.

It doesn't sound like a good approach, but without a fuller picture of the task it's hard to say.
What you can do is generate a list of numbers and use it to produce your required statements, such as:
with months as (
select 1 m
union all
select m + 1 from months
where m<12
)
select Concat('select * from table where month = ', m, ';')
from months
Depending on your requirements and RDBMS you can either use them directly in your IDE or dynamically execute.

In Oracle, you could use hierarchical query to generate months; something like this:
SQL> select empno,
2 ename,
3 job,
4 to_char(hiredate, 'fmMonth', 'nls_date_language = english') month
5 from emp
6 where extract(month from hiredate) in (select level from dual
7 connect by level <= 12
8 )
9 order by extract (month from hiredate);
EMPNO ENAME JOB MONTH
---------- ---------- --------- ------------------------------------
7876 ADAMS CLERK January
7934 MILLER CLERK January
7499 ALLEN SALESMAN February
7521 WARD SALESMAN February
7566 JONES MANAGER April
7698 BLAKE MANAGER May
7782 CLARK MANAGER June
7844 TURNER SALESMAN September
7654 MARTIN SALESMAN September
7839 KING PRESIDENT November
7788 SCOTT ANALYST December
7369 SMITH CLERK December
7900 JAMES CLERK December
7902 FORD ANALYST December
14 rows selected.
SQL>

Can be as simple as left/right join to cte months
declare #table table (mm smallint,somedata varchar(20))
insert into #table
values
(1,'some data for 1')
,(3,'some data for 3')
,(5,'some data for 5')
;with cte_months as (
select 1 mm
union all
select mm + 1 from cte_months
where mm<12
)
select c.mm,t.somedata from #table t
right join cte_months c on t.mm = c.mm

Related

Ignore column in the WHERE clause if the parameter is null, else use IN clause to filter the column in WHERE clause

I need to write a query where I should Ignore any filter on that column if the respective parameter is Null, but should filter with IN clause if the said parameter is not null. I am trying to use the below query but I am not able to make it work. It is the HR DB and Employees table in Oracle 11 XE and I am trying to pass Job ID as a param and this param could be null or it could contain multiple values.
What I have done so far -
SELECT * FROM HR.EMPLOYEES
WHERE
CASE WHEN NVL(:PARAM_JOB_ID,'NONE')= 'NONE' THEN 'NONE' ELSE JOB_ID END IN NVL(:PARAM_JOB_ID,'NONE');
Please guide.
I would use IS NULL logic here:
SELECT *
FROM HR.EMPLOYEES
WHERE JOB_ID IN (:PARAM_JOB_ID) OR :PARAM_JOB_ID IS NULL;
You'll have to split values in :PARAM_JOB_ID into rows. Something like this (Scott's sample schema and its EMP table):
select job, ename
from emp
where ( job in (select trim(regexp_substr(:param_job_id, '[^,]+', 1, level))
from dual
connect by level <= regexp_count(:param_job_id, ',') + 1
)
or :param_job_id is null
)
order by job, ename;
Demonstration in SQL*Plus:
SQL> select job, ename
2 from emp
3 where ( job in (select trim(regexp_substr('&&param_job_id', '[^,]+', 1, level))
4 from dual
5 connect by level <= regexp_count('&&param_job_id', ',') + 1
6 )
7 or '&&param_job_id' is null
8 )
9 order by job, ename;
Enter value for param_job_id: --> empty parameter returns all rows
JOB ENAME
--------- ----------
ANALYST FORD
ANALYST SCOTT
CLERK ADAMS
CLERK JAMES
CLERK MILLER
CLERK SMITH
MANAGER BLAKE
MANAGER CLARK
MANAGER JONES
PRESIDENT KING
SALESMAN ALLEN
SALESMAN MARTIN
SALESMAN TURNER
SALESMAN WARD
14 rows selected.
SQL> undefine param_job_id
SQL> /
Enter value for param_job_id: CLERK, PRESIDENT
JOB ENAME
--------- ----------
CLERK ADAMS
CLERK JAMES
CLERK MILLER
CLERK SMITH
PRESIDENT KING
SQL>

Convert String to char in oracle

Hi i have the following data '1,2,3' and i need to convert this into this '1','2','3' that i will use in this
Select * from dual where to_chat(month) in ('1','2','3')
i cannot use query straight like that because of the quater
Quater no. Month
1 1,2,3
2 4,5,6
...
so i must use case like this but case statement return on format like this '1','2','3'
Select * from dual
where to_chat(month) in (
select
case quarter
when 1 then '1','2','3'
when 2 then '4','5','6'
end
from dual )
input
'1,2,3'
expected output
'1','2','3'
You can use regexp_like():
where regexp_like(<whatever>, replace('1,2,3', ',', '|'))
Putting single quotes in the string still won't enable you to do what you want with like. It will still be a single string, but one that has single quotes and commas in it.
How about such an approach? Example is based on Scott's EMP table. I'd like to fetch employees which were hired in certain months.
Sample data:
SQL> select deptno, ename, job, hiredate, to_char(hiredate, 'mm') mon from emp order by mon;
DEPTNO ENAME JOB HIREDATE MO
---------- ---------- --------- ---------- --
20 ADAMS CLERK 12.01.1983 01
10 MILLER CLERK 23.01.1982 01
30 ALLEN SALESMAN 20.02.1981 02 -- suppose I want to select employees
30 WARD SALESMAN 22.02.1981 02 -- hired in February,
20 JONES MANAGER 02.04.1981 04 -- April and
30 BLAKE MANAGER 01.05.1981 05 -- May
10 CLARK MANAGER 09.06.1981 06
30 TURNER SALESMAN 08.09.1981 09
30 MARTIN SALESMAN 28.09.1981 09
10 KING PRESIDENT 17.11.1981 11
20 SCOTT ANALYST 09.12.1982 12
20 SMITH CLERK 17.12.1980 12
30 JAMES CLERK 03.12.1981 12
20 FORD ANALYST 03.12.1981 12
14 rows selected.
Query - which splits input search string into rows (so that you could use it in IN clause) would then be:
SQL> with src as
2 (select &par_month src_month from dual)
3 select deptno, ename, job, hiredate
4 from emp
5 where to_number(to_char(hiredate, 'mm')) in
6 (select regexp_substr(src_month, '[^,]+', 1, level)
7 from src
8 connect by level <= regexp_count(src_month, ',') + 1
9 )
10 order by to_char(hiredate, 'mm');
Enter value for par_month: '2,4,5'
DEPTNO ENAME JOB HIREDATE
---------- ---------- --------- ----------
30 ALLEN SALESMAN 20.02.1981
30 WARD SALESMAN 22.02.1981
20 JONES MANAGER 02.04.1981
30 BLAKE MANAGER 01.05.1981
SQL>

Oracle- sql query to print odd number of rows when we do not have number data type columns

I was trying to print odd numbers of rows from my table without taking taking help of my numeric cloumns
when I try to execute this query I was getting only first row.
select * from emp3 where mod(rownum,2)=1;
emp3 is my table name.
and when I use my one of the numeric columns in place of rownum I was getting desired output.
select * from emp3 where mod(eid,2)=1 order by eid;
where eid is a numeric column in the table.
But what if do not have a numeric column and I want to print only odd number of rows from the table?
Help me!
Try to execute the below query
select * from (select rownum rn ,column from column_name) where mod(rn,2) <> 0
and please refer to this link for better understanding the concept of rownum https://www.youtube.com/watch?v=QMyw1jumGyQ
If the EID column isn't numeric, then use something that is. For example, ROW_NUMBER gives such an information:
SQL> with temp as
2 (select empno, ename, job sal,
3 row_number() over (order by null) rn
4 from emp
5 )
6 select *
7 from temp
8 where mod(rn, 2) = 1;
EMPNO ENAME SAL RN
---------- ---------- --------- ----------
7369 SMITH CLERK 1
7521 WARD SALESMAN 3
7654 MARTIN SALESMAN 5
7782 CLARK MANAGER 7
7839 KING PRESIDENT 9
7876 ADAMS CLERK 11
7902 FORD ANALYST 13
7 rows selected.
SQL>
Or even ROWNUM you already tried to use:
SQL> with temp as
2 (select empno, ename, job sal,
3 rownum rn
4 from emp
5 )
6 select *
7 from temp
8 where mod(rn, 2) = 1;
EMPNO ENAME SAL RN
---------- ---------- --------- ----------
7369 SMITH CLERK 1
7521 WARD SALESMAN 3
7654 MARTIN SALESMAN 5
7782 CLARK MANAGER 7
7839 KING PRESIDENT 9
7876 ADAMS CLERK 11
7902 FORD ANALYST 13
7 rows selected.
SQL>

Oracle, Connect By rownum

I tried to find some informations about connect by "engine".
I found this post: Confusion with Oracle CONNECT BY
User krokodilko answered and says:
The analyze of the last query:
select level from dual connect by rownum<10;
I leave to you as a homework assignment.
So i tried to do exactly as described to query
Select rownum from dual connect by rownum < 3
And here's my "work":
CREATE TABLE step1 AS
SELECT 1 "LEVEL" FROM dual;
SELECT * FROM step1;
create table step2 as
SELECT 2 "LEVEL" from dual
JOIN step1 "PRIOR" on rownum <=3;
SELECT * FROM step2;
create table step3 as
select 3 "LEVEL" from dual
join step2 "PRIOR" on rownum <=3;
SELECT * FROM step3;
create table step4 as
select 4 "LEVEL" from dual
join step3 "PRIOR" on rownum <=3;
SELECT * FROM step4;
But last SELECT still returns rows. Am I misunderstood something? Every time i Select LEVEL + 1 "LEVEL" it has rownum = 1 so it's always true. So am i failed steps?
The explanation in Krokodilko's answer is simply wrong. You may disregard the "Correct Answer" mark and the numerous upvotes, it's still wrong. It is interesting that he left as an exercise exactly the case that proves the explanation is wrong.
A CONNECT BY query doesn't work "as if" new tables (or new output rowsets of SELECT statements, anyway) are generated at each step. This is the mistake in the argument.
Rather, there is only one rowset generated overall (across all steps). It is true that new rows are added based on the rows generated at the previous step; but the rowset itself is one, and growing, not separate rowsets.
This is particularly relevant with regard to ROWNUM. ROWNUM is assigned to rows in a single "result" rowset, starting with 1. In a CONNECT BY query, there is only one rowset, and ROWNUM goes from 1 to n in an increasing sequence.
If Krokodilko's answer were correct, then ROWNUM would restart at 1 at each step. This is clearly not the case: let's try it on a "standard" hierarchical query.
select empno, ename, mgr, level, rownum
from scott.emp
start with mgr is null
connect by prior empno = mgr
;
EMPNO ENAME MGR LEVEL ROWNUM
---------- ---------- ---------- ---------- ----------
7839 KING 1 1
7566 JONES 7839 2 2
7788 SCOTT 7566 3 3
7876 ADAMS 7788 4 4
7902 FORD 7566 3 5
7369 SMITH 7902 4 6
7698 BLAKE 7839 2 7
7499 ALLEN 7698 3 8
7521 WARD 7698 3 9
7654 MARTIN 7698 3 10
7844 TURNER 7698 3 11
7900 JAMES 7698 3 12
7782 CLARK 7839 2 13
7934 MILLER 7782 3 14

Oracle: Overwrite values in a column with the longest string

I’m running into a problem.
Say, I have columns called “C1, C2, C3....” in a table. I’d like to use the longest string in C1 to replace every other cells in C1 column without disturbing other columns.
I tired several ways but I cannot get my Oracle code run. Could someone please show me a sample code to do this problem? I typed my question using a cellphone so I apologize for not showing you my code. But I think my description is fine... Thank you!
I would use window functions. Oracle has a very convenient functionality with keep:
select max(col1) keep (dense_rank first order by len(col1) desc) over () as col1,
col2, col3, . . .
from t;
You can incorporate this into an update:
update t
set col1 = (select select max(col1) keep (dense_rank first order by len(col1) desc) over () as col1
from t
);
For example:
SQL> select * from test;
DEPTNO DNAME LOC
---------- -------------- -------------
10 ACCOUNTING NEW YORK
20 RESEARCH DALLAS
30 SALES CHICAGO
40 OPERATIONS BOSTON
SQL> update test set
2 dname = (select max(dname) --> MAX fixes TOO-MANY-ROWS because ACCOUNTING
3 from test -- and OPERATIONS have same length
4 where length(dname) = (select max(length(dname))
5 from test
6 )
7 );
4 rows updated.
SQL> select * from test;
DEPTNO DNAME LOC
---------- -------------- -------------
10 OPERATIONS NEW YORK
20 OPERATIONS DALLAS
30 OPERATIONS CHICAGO
40 OPERATIONS BOSTON
SQL>
[EDIT, GROUP BY]
Another example is based on a different table, which reflects what you described in a comment. The DEPTNO (department number) is used to "group" employees, and I'm going to update the JOB column value to the longest job name within that department.
Query is similar to the previous one; it just joins appropriate columns (DEPTNO) throughout code.
Sample data:
SQL> select * from test order by deptno, ename;
DEPTNO ENAME JOB
---------- ---------- ---------
10 CLARK MANAGER
KING PRESIDENT --> the longest in DEPTNO = 10
MILLER CLERK
20 ADAMS CLERK
FORD ANALYST
JONES MANAGER --> as long as ANALYST, but MAX(JOB) will return this value
SCOTT ANALYST
SMITH CLERK
30 ALLEN SALESMAN --> the longest in DEPTNO = 30
BLAKE MANAGER
JAMES CLERK
MARTIN SALESMAN
TURNER SALESMAN
WARD SALESMAN
Update and the result:
SQL> update test t set
2 t.job = (select max(t1.job)
3 from test t1
4 where t1.deptno = t.deptno
5 and length(t1.job) = (select max(length(t2.job))
6 from test t2
7 where t2.deptno = t1.deptno
8 )
9 );
14 rows updated.
SQL> select * from test order by deptno, ename;
DEPTNO ENAME JOB
---------- ---------- ---------
10 CLARK PRESIDENT
KING PRESIDENT
MILLER PRESIDENT
20 ADAMS MANAGER
FORD MANAGER
JONES MANAGER
SCOTT MANAGER
SMITH MANAGER
30 ALLEN SALESMAN
BLAKE SALESMAN
JAMES SALESMAN
MARTIN SALESMAN
TURNER SALESMAN
WARD SALESMAN