I would like to run below query:
SELECT
*
FROM
TABLE1
WHERE
COL1 = :DynamicValue1
AND COL2 = :DynamicValue2
USING
USERENTEREDVALUE1, USERENTEREDVALUE2;
I don't want to use EXECUTE IMMEDIATE.
How can I use using keyword in select query?
When I run this I get pop up to enter value but it gives error
Ora-00933
You may use substitution variables
DEFINE lname = 'Rogers'
DEFINE mgrid = 122
SELECT *
FROM employees
WHERE last_name = '&lname'
AND manager_id = '&mgrid';
When you run this in SQL developer or SQL* Plus, you get
old:SELECT *
FROM employees
WHERE last_name = '&lname'
AND manager_id = &mgrid
new:SELECT *
FROM employees
WHERE last_name = 'Rogers'
AND manager_id = 122
EMPLOYEE_ID FIRST_NAME LAST_NAME EMAIL PHONE_NUMBER HIRE_DAT JOB_ID SALARY COMMISSION_PCT MANAGER_ID DEPARTMENT_ID
----------- -------------------- ------------------------- ------------------------- -------------------- -------- ---------- ---------- -------------- ---------- -------------
134 Michael Rogers MROGERS 650.127.1834 26-08-06 ST_CLERK 2900 122 50
Or use Bind variables
VARIABLE lname VARCHAR2(40)
VARIABLE mgrid NUMBER
EXEC :lname := 'Rogers'
EXEC :mgrid := 122
VARIABLE x REFCURSOR
BEGIN
OPEN :x FOR SELECT *
FROM employees
WHERE last_name =:lname
AND manager_id =:mgrid;
END;
/
PRINT x
Result
PL/SQL procedure successfully completed.
PL/SQL procedure successfully completed.
PL/SQL procedure successfully completed.
EMPLOYEE_ID FIRST_NAME LAST_NAME EMAIL PHONE_NUMBER HIRE_DAT JOB_ID SALARY COMMISSION_PCT MANAGER_ID DEPARTMENT_ID
----------- -------------------- ------------------------- ------------------------- -------------------- -------- ---------- ---------- -------------- ---------- -------------
134 Michael Rogers MROGERS 650.127.1834 26-08-06 ST_CLERK 2900 122 50
I'm not sure if you're doing pl/sql, but if you do, you can simply add variables to you query:
declare
USERENTEREDVALUE1 VARCHAR2(100) := 'value1';
USERENTEREDVALUE2 VARCHAR2(100) := 'value2';
RESULTVALUE VARCHAR2(100);
begin
SELECT COL3
INTO RESULTVALUE
FROM (
SELECT 'value1' COL1, 'value2' COL2, 'Ok' COL3 FROM dual UNION ALL
SELECT 'value3' COL1, 'value4' COL2, 'NOK' COL3 FROM dual
) TABLE1
WHERE COL1 = USERENTEREDVALUE1
AND COL2 = USERENTEREDVALUE2;
dbms_output.put_line('RESULTVALUE: ' || RESULTVALUE);
end;
Related
I have code in my Oracle stored procedure like this:
SELECT COUNT(EMP_ID) INTO A_VARIABLE
FROM STUDENT;
IF (A_VARIABLE > 0) THEN
SELECT * FROM DEPARTMENT1;
ELSE
SELECT * FROM DEPARTMENT2;
END IF;
Basically I have to do this same filtration of rows in my SQL query (and not in the procedure or script).
Can anyone help with this Oracle query?
I have tried multiple solutions, but I'm not getting the desired output.
For 19c (19.7 and above) you may use SQL_MACRO(table) feature and inline function declaration.
But different output structure of the same query is somewhat misleading, so I would recommend to use union all approach and align columns of two tables.
Below is an example for SQL Macro.
Setup:
create table table1
as
select
level as id,
level as val
from dual
connect by level < 5
create table table2
as
select
level as id,
lpad(level, 4, '0') as val,
dbms_random.string('x', 5) as str2
from dual
connect by level < 4
create table decision
as
select 'Y' as res
from dual
Run 1:
with function f_decide_table
return varchar2
sql_macro(table)
as
l_res varchar2(100);
begin
select
coalesce (
max(q'[select * from table1]'),
q'[select * from table2]'
)
into l_res
from decision;
return l_res;
end;
select *
from f_decide_table()
order by 1
ID
VAL
1
1
2
2
3
3
4
4
Run 2:
truncate table decision
with function f_decide_table
return varchar2
sql_macro(table)
as
l_res varchar2(100);
begin
select
coalesce (
max(q'[select * from table1]'),
q'[select * from table2]'
)
into l_res
from decision;
return l_res;
end;
select *
from f_decide_table()
order by 1
ID
VAL
STR2
1
0001
DGNY9
2
0002
UHFYH
3
0003
EU12B
fiddle
Sample student table; depending on course students take, main query will return data from one table (or another).
SQL> select * from student;
ID NAME COURSE
1 Little Web
2 Foot Web
SQL> select * from department1;
DEPTNO DNAME LOC
---------- -------------- -------------
10 ACCOUNTING NEW YORK
20 RESEARCH DALLAS
SQL> select * from department2;
DEPTNO DNAME LOC
---------- -------------- -------------
30 SALES CHICAGO
40 OPERATIONS BOSTON
SQL>
Query uses a CTE that counts rows in student table; it is then used in exists subquery for two similar select statements which fetch rows from one of departments tables.
Currently, nobody is in IT so departments2 table it is:
SQL> with temp as
2 (select count(*) cnt
3 from student
4 where course = 'IT')
5 --
6 select * from department1
7 where exists (select null from temp
8 where cnt > 0
9 )
10 union all
11 select * from department2
12 where exists (select null from temp
13 where cnt = 0
14 );
DEPTNO DNAME LOC
---------- -------------- -------------
30 SALES CHICAGO
40 OPERATIONS BOSTON
SQL>
However, if someone studies IT, department1 will provide data:
SQL> update student set course = 'IT' where id = 1;
1 row updated.
SQL> select * from student;
ID NAME COURSE
---------- ------ ----------
1 Little IT
2 Foot Web
SQL> with temp as
2 (select count(*) cnt
3 from student
4 where course = 'IT')
5 --
6 select * from department1
7 where exists (select null from temp
8 where cnt > 0
9 )
10 union all
11 select * from department2
12 where exists (select null from temp
13 where cnt = 0
14 );
DEPTNO DNAME LOC
---------- -------------- -------------
10 ACCOUNTING NEW YORK
20 RESEARCH DALLAS
SQL>
Closest thing to what you want to do (using just sql) would mean that you need to know all the column names and datatypes in both tables.
Next, you would have to do the datatype conversion for one union query as you have to select same number of columns with same datatypes.
The result would have all that you need but with some empty columns (those that do exist in other table but not in one you are selecting from).
Depending on total number of columns and on differences in names and types this coulld becomee too complicated and you realy shoud think about some function and reference queries.
Anyway, lets create some sample data to work with:
WITH -- sample data
students (ID, A_NAME) AS
(
Select 1, 'Mark' From Dual
),
dept_1 (ID, DEPT_NAME, DEPT_CITY) AS
(
Select '10', 'HR', 'NEW_YORK' From Dual Union All
Select '20', 'IT', 'BOSTON' From Dual
),
dept_2 (ID, DEPARTMENT) AS
(
Select 30, 'SALES' From Dual Union All
Select 40, 'PRODUCTION' From Dual
),
-- dept_1 has 3 columns (ID VARCHAR) - same column name different datatype
-- dept_2 has 2 columns (ID NUMBER)
-- The rest of the columns have different names and same datatype
create cte (namings) - forcing union of rows for all columns from both tables - dummy filling non existant and converting To_Char(ID) to get same datatype (this is needed for union to work)
-- here are total of 5 columns coded - it can be widen more if needed, this is just a sample to show handling of extra columns
namings AS
(
SELECT ROWNUM "RN", 'dept_1' "TABLE_NAME", Count(*) "CNT", To_Char(ID) "V1", DEPT_NAME "V2", DEPT_CITY "V3", 'X' "V4", 'X' "V5", 'ID' "C1", 'DEPT_NAME' "C2", 'DEPT_CITY' "C3", 'COL_X4' "C4", 'COL_X5' "C5"
From dept_1
Where CASE WHEN (Select Count(*) "CNT" From students Where ID = 999) > 0 THEN 1 ELSE 0 END = 1
Group By ROWNUM, ID, DEPT_NAME, DEPT_CITY
Union All
SELECT ROWNUM "RN", 'dept_2' "TABLE_NAME", Count(*) "CNT", To_Char(ID) "V1", DEPARTMENT "V2", 'X' "V3", 'X' "V4", 'X' "V5", 'ID' "C1", 'DEPARTMENT' "C2", 'COL_X3' "C3", 'COL_X4' "C4", 'COL_X5' "C5"
From dept_2
Where CASE WHEN (Select Count(*) "CNT" From students Where ID = 999) > 0 THEN 1 ELSE 0 END = 0
Group By ROWNUM,ID, DEPARTMENT
),
R e s u l t when count from students = 0 (filtered out with where clause)
RN TABLE_NAME CNT V1 V2 V3 V4 V5 C1 C2 C3 C4 C5
---------- ---------- ---------- ---------------------------------------- ---------- -------- -- -- -- ---------- --------- ------ ------
2 dept_2 1 40 PRODUCTION X X X ID DEPARTMENT COL_X3 COL_X4 COL_X5
1 dept_2 1 30 SALES X X X ID DEPARTMENT COL_X3 COL_X4 COL_X5
R e s u l t when count from students > 0
RN TABLE_NAME CNT V1 V2 V3 V4 V5 C1 C2 C3 C4 C5
---------- ---------- ---------- ---------------------------------------- ---------- -------- -- -- -- ---------- --------- ------ ------
1 dept_1 1 10 HR NEW_YORK X X ID DEPT_NAME DEPT_CITY COL_X4 COL_X5
2 dept_1 1 20 IT BOSTON X X ID DEPT_NAME DEPT_CITY COL_X4 COL_X5
create another cte (transposed) to unpivot the above data
transposed AS
( SELECT * FROM namings
UNPIVOT ( (NAMES, VALS) For COL_NAME IN( (C1, V1), (C2, V2), (C3, V3), (C4, V4), (C5, V5) ) )
WHERE VALS <> 'X'
)
R e s u l t when count from students = 0
RN TABLE_NAME CNT COL_NAME NAMES VALS
---------- ---------- ---------- -------- ---------- ----------------------------------------
2 dept_2 1 C1_V1 ID 40
2 dept_2 1 C2_V2 DEPARTMENT PRODUCTION
1 dept_2 1 C1_V1 ID 30
1 dept_2 1 C2_V2 DEPARTMENT SALES
R e s u l t when count from students > 0
RN TABLE_NAME CNT COL_NAME NAMES VALS
---------- ---------- ---------- -------- ---------- ----------------------------------------
1 dept_1 1 C1_V1 ID 10
1 dept_1 1 C2_V2 DEPT_NAME HR
1 dept_1 1 C3_V3 DEPT_CITY NEW_YORK
2 dept_1 1 C1_V1 ID 20
2 dept_1 1 C2_V2 DEPT_NAME IT
2 dept_1 1 C3_V3 DEPT_CITY BOSTON
Main sql - pivoting data to columns from both tables
SELECT DISTINCT
RN,
TABLE_NAME,
MAX(ID_V) OVER(Partition By RN) "ID",
MAX(DEPT_NAME_V) OVER(Partition By RN) "DEPT_NAME",
MAX(DEPT_CITY_V) OVER(Partition By RN) "DEPT_CITY",
MAX(DEPARTMENT_V) OVER(Partition By RN) "DEPARTMENT"
FROM (
SELECT * FROM transposed
PIVOT (
COUNT(NAMES), MAX(VALS) "V" FOR NAMES IN('ID' "ID", 'DEPT_NAME' "DEPT_NAME", 'DEPT_CITY' "DEPT_CITY", 'DEPARTMENT' "DEPARTMENT")
)
)
ORDER BY RN
R e s u l t when count from students = 0
RN TABLE_NAME ID DEPT_NAME DEPT_CITY DEPARTMENT
---------- ---------- ---------------------------------------- ---------------------------------------- ---------------------------------------- ----------------------------------------
1 dept_2 30 SALES
2 dept_2 40 PRODUCTION
R e s u l t when count from students > 0
RN TABLE_NAME ID DEPT_NAME DEPT_CITY DEPARTMENT
---------- ---------- ---------------------------------------- ---------------------------------------- ---------------------------------------- ----------------------------------------
1 dept_1 10 HR NEW_YORK
2 dept_1 20 IT BOSTON
I want to count "Yes" and "No" from the below table data irrespective of the columns.
Oracle DB Table:
Intended Output:
It doesn't matter from which column it is coming. I just want to calculate the total count of Yes and No.
I tried with pivot but couldn't find a way how to use that for multiple columns.
Please help.
If it has to be dynamic, then ... it has to be dynamic, which means that PL/SQL is an option to do what you want. Here's an example:
Function that loops through all columns in a table whose name is passed as a parameter and calculates number of a value passed as the second parameter:
SQL> create or replace function f_yes_no
2 (par_table_name in varchar2, par_yes_no in varchar2)
3 return number
4 is
5 l_cnt number;
6 retval number := 0;
7 begin
8 for cur_r in (select column_name from user_tab_columns
9 where table_name = dbms_assert.sql_object_name(par_table_name)
10 and data_type like '%CHAR%'
11 )
12 loop
13 execute immediate
14 'select count(*) from ' || dbms_assert.sql_object_name(par_table_name) ||
15 ' where ' || cur_r.column_name || ' = ' ||
16 dbms_assert.enquote_literal(par_yes_no)
17 into l_cnt;
18 retval := retval + l_cnt;
19 end loop;
20 return retval;
21 end;
22 /
Function created.
SQL>
Testing: sample table:
For a sample table:
SQL> select * from test;
ZING PLING COL3 BOING
----- ----- ----- -----
Yes No Yes No
Yes No No No
No No Yes No
SQL> select f_yes_no('TEST', 'Yes') cnt_yes,
2 f_yes_no('TEST', 'No' ) cnt_no
3 from dual;
CNT_YES CNT_NO
---------- ----------
4 8
SQL>
What's nice with it? You can reuse the function for other strings in another tables, e.g. how many MANAGERs are there in Scott's EMP table?
SQL> select ename, job from emp order by job;
ENAME JOB
---------- ---------
SCOTT ANALYST
FORD ANALYST
MILLER CLERK
JAMES CLERK
SMITH CLERK
ADAMS CLERK
BLAKE MANAGER
JONES MANAGER
CLARK MANAGER
KING PRESIDENT
TURNER SALESMAN
MARTIN SALESMAN
WARD SALESMAN
ALLEN SALESMAN
14 rows selected.
SQL> select f_yes_no('EMP', 'MANAGER') cnt_mgr from dual;
CNT_MGR
----------
3
SQL>
The UNPIVOT clause?
SELECT
SUM(DECODE(v, 'Yes', 1)) "Yes",
SUM(DECODE(v, 'No', 1)) "No"
FROM t
UNPIVOT (
v FOR value_type IN (c1, c2, c3, c4, c5)
);
db<>fiddle
More generic way:
SELECT
SUM(DECODE(yes_no, 'Yes', 1)) "Yes",
SUM(DECODE(yes_no, 'No', 1)) "No"
FROM (
SELECT
x.yes_no.EXTRACT(c.column_name || '/text()').getStringVal() yes_no
FROM
XMLTABLE ('/ROWSET/ROW'
PASSING XMLTYPE(dbms_xmlgen.getxml('SELECT * FROM t'))
COLUMNS
yes_no XMLTYPE PATH '*[text() = ("Yes", "No")]') x
CROSS JOIN user_tab_columns c
WHERE
c.table_name = 'T' AND
column_name LIKE 'C%'
) t;
db<>fiddle
All credit must go to https://stackoverflow.com/a/45866854/3350428.
One method would use a lateral join:
select sum(case when col = 'Yes' then 1 else 0 end) as num_yes,
sum(case when col = 'No' then 1 else 0 end) as num_no
from t cross join lateral
(select t.column1 as col from dual union all
select t.column2 from dual union all
select t.column3 from dual union all
select t.column4 from dual union all
select t.column5 from dual
) t
I'm trying to use the SQL queries stored in a table, in a insert statement inside the procedure.
Below is the statement_table,
STMT_ID STATMENT1 STATEMENT2
S001 INSERT INTO TABLE1 (S_ID, REQUEST_NUM,CASE_ID,C1,C2) select min(s_id) s_id, REQUEST_NUM, CASE_ID, trim(c1),
ABS(max(case when source = 'S1' then c2 end) +
max(case when source = 'S2' then -c2 end))
from TABLE2 where REQUEST_NUM =REQUEST_IN
group by REQUEST_NUM , CASE_ID, trim(c1)
order by S_ID
Below is the procedure block,
execute immediate 'select '||STATEMENT1||'+'||STATEMENT2||' FROM statement_table where stmt_id='S001';
The result that I am trying to get is,
INSERT INTO TABLE1 (S_ID, REQUEST_NUM,CASE_ID,C1,C2)
select min(s_id) s_id, REQUEST_NUM, CASE_ID, trim(c1),
ABS(max(case when source = 'S1' then c2 end) +
max(case when source = 'S2' then -c2 end))
from TABLE2 where REQUEST_NUM =REQUEST_IN
group by REQUEST_NUM , CASE_ID, trim(c1)
order by S_ID
Please help.
Here's how.
First, your (actually, my) statements. I'm going to insert a row into Scott's DEPT table.
SQL> select * from test;
ID
----------
ST1
--------------------------------------------------------------------------------
ST2
--------------------------------------------------------------------------------
1
insert into dept (deptno, dname, loc)
select max(deptno) + 1, 'stack', 'zoom' from dept order by 1
SQL> select * From dept;
DEPTNO DNAME LOC
---------- -------------- -------------
10 ACCOUNTING NEW YORK
20 RESEARCH DALLAS
30 SALES CHICAGO
40 OPERATIONS BOSTON
1 x y
Code; DBMS_OUTPUT is used to verify whether the statement is correct or not.
SQL> set serveroutput on
SQL> declare
2 l_st1 test.st1%type;
3 l_st2 test.st2%type;
4 l_str varchar2(1000);
5 begin
6 select st1, st2
7 into l_st1, l_st2
8 from test
9 where id = 1;
10
11 l_str := l_st1 ||' '|| l_st2;
12 dbms_output.put_line(l_str);
13 execute immediate l_str;
14 end;
15 /
insert into dept (deptno, dname, loc) select max(deptno) + 1, 'stack', 'zoom'
from dept order by 1
PL/SQL procedure successfully completed.
Result:
SQL> select * from dept;
DEPTNO DNAME LOC
---------- -------------- -------------
10 ACCOUNTING NEW YORK
20 RESEARCH DALLAS
30 SALES CHICAGO
40 OPERATIONS BOSTON
41 stack zoom --> this was inserted
1 x y
6 rows selected.
SQL>
Is any way to select all columns in a record where fields are not null or NVL the null fields to ''?
Im working on ORACLE
Something like this
SELECT * IS NOT NULL
FROM table
WHERE id_table ='001'
or like this
SELECT NVL(*,'')
FROM table
WHERE id_table ='001'
Just reverse the NULL logic in the demonstration about Find all columns having at least a NULL value from all tables in the schema.
For example,
FIND_NULL_COL is a simple user defined function(UDF) which will return 1 for the column which has at least one NULL value :
SQL> CREATE OR REPLACE
2 FUNCTION FIND_NULL_COL(
3 TABLE_NAME VARCHAR2,
4 COLUMN_NAME VARCHAR2)
5 RETURN NUMBER
6 IS
7 cnt NUMBER;
8 BEGIN
9 CNT :=1;
10 EXECUTE IMMEDIATE 'select count(1) from '
11 ||TABLE_NAME||' where ' ||COLUMN_NAME||' is not null
12 and deptno = 20' INTO cnt;
13 RETURN
14 CASE
15 WHEN CNT=0 THEN
16 1
17 ELSE
18 0
19 END;
20 END;
21 /
Function created.
Call the function in SQL to get the NULL status of all the column of any table :
SQL> SET pagesize 1000
SQL> column owner format A10;
SQL> column column_name format A20;
SQL> COLUMN TABLE_NAME FORMAT A20;
SQL> column n format A1;
SQL> SELECT c.OWNER,
2 c.TABLE_NAME,
3 c.COLUMN_NAME,
4 C.NULLABLE,
5 FIND_NULL_COL(c.TABLE_NAME,c.COLUMN_NAME) null_status
6 FROM all_tab_columns c
7 WHERE C.OWNER =USER
8 AND c.TABLE_NAME = 'EMP'
9 ORDER BY C.OWNER,
10 C.TABLE_NAME,
11 C.COLUMN_ID
12 /
OWNER TABLE_NAME COLUMN_NAME N NULL_STATUS
---------- -------------------- -------------------- - -----------
SCOTT EMP EMPNO N 0
SCOTT EMP ENAME Y 0
SCOTT EMP JOB Y 0
SCOTT EMP MGR Y 0
SCOTT EMP HIREDATE Y 0
SCOTT EMP SAL Y 0
SCOTT EMP COMM Y 1
SCOTT EMP DEPTNO Y 0
8 rows selected.
SQL>
So, NULL_STATUS "1" is the column which has NULL value(s).
i want to convert rows into columns using PIVOT function.
Example is below
Table
EMP No EMP Name
------- --------
1 ABC
2 PQR
Output should be
Col1 Col2
---- ----
Emp No 1
Emp Name ABC
EMP No 2
Emp Name PQR
I am ok with loop and all however we should have used PIVOT, have serached google however has not got anything matching.
Please suggest and send some sample code.
Actually for you requirement, you need unpivot, not pivot. But for that, datatype of both columns should be same, character in this case
with tab(emp_no, emp_name) as (
select '1' ,'abc' from dual union all
select '2' ,'PQR' from dual)
----
--End of Data Perparation
----
select *
from tab
unpivot (col2 for col1 in ( emp_no as 'EMP No', emp_name as 'Emp Name'));
Output
| COL1 | COL2 |
|----------|------|
| EMP No | 1 |
| Emp Name | abc |
| EMP No | 2 |
| Emp Name | PQR |
I'm not sure if this can be done using PIVOT. You can select the columns separately and UNION them.
select 'Emp No' col1, emp_no col2 from tab
union all
select 'Emp Name', emp_name from tab;
Note that, both the columns should be of same datatype. Else you need to cast/convert one of them.
Also, the result may not be in the order you want. You need to sepecify the order by clause explicitly.
select col1, col2 from(
select 'Emp No' col1, emp_no col2, emp_no from tab
union all
select 'Emp Name', emp_name, emp_no from tab
)
order by emp_no, case col1 when 'Emp No' then 1 else 2 end;
sqlfidle.