Example : There is a table "ID_NAME" with one column "ID" which has 2000 entries like 1,2,3.. 2000.
I've have a query
select id from ID_NAME where id < 1001;
> Result : 1 2 3 4 . .1000
My PL SQL block looks like this,
SET SERVEROUTPUT ON;
declare
var1 number;
var2 number;
var3 number;
var4 number;
var5 number;
var6 number;
var7 number;
var8 number;
var9 number;
var10 number;
begin
with set1 as (select id from ID_NAME where id < 1001)
select count(*) into var1 from table1 where id in (select * from set1);
select count(*) into var2 from table2 where id in (select * from set1);
select count(*) into var3 from table3 where id in (select * from set1);
select count(*) into var4 from table4 where id in (select * from set1);
select count(*) into var5 from table5 where id in (select * from set1);
select count(*) into var6 from table6 where id in (select * from set1);
select count(*) into var7 from table7 where id in (select * from set1);
select count(*) into var8 from table8 where id in (select * from set1);
select count(*) into var9 from table9 where id in (select * from set1);
select count(*) into var10 from table10 where id in (select * from set1);
DBMS_OUTPUT.PUT_LINE('var1,var2,var3,var4,var5,var6,var7,var8,var9,var10');
DBMS_OUTPUT.PUT_LINE(var1||','||var2||','||var3||','||var4||','||var5||','||var6||','||var7||','||var8||','||var9||','||var10);
end;
but I'm getting
PL/SQL: ORA-00942: table or view does not exist
in my sql developer.
I want to use the SET1 from my below query so that I don't have to run it again and again in the count(*) sub queries
with set1 as (select id from ID_NAME where id < 1001)
SET SERVEROUTPUT ON;
declare
var1 number;
var2 number;
var3 number;
var4 number;
var5 number;
var6 number;
var7 number;
var8 number;
var9 number;
var10 number;
begin
with set1 as (select id from ID_NAME where id < 1001)
select
(select count(*) from table1 where id in (select * from set1)),
(select count(*) from table2 where id in (select * from set1)),
..............
(select count(*) from table9 where id in (select * from set1)),
(select count(*) from table10 where id in (select * from set1))
into var1,var2,.....,var9,var10
from dual;
DBMS_OUTPUT.PUT_LINE('var1,var2,var3,var4,var5,var6,var7,var8,var9,var10');
DBMS_OUTPUT.PUT_LINE(var1||','||var2||','||var3||','||var4||','||var5||','||var6||','||var7||','||var8||','||var9||','||var10);
end;
You are building a CTE so it goes like this: For each select statement you need to join with CTE.
declare
var1 number;
var2 number;
var3 number;
var4 number;
var5 number;
var6 number;
var7 number;
var8 number;
var9 number;
var10 number;
begin
with set1 as (select emp_id from employee where emp_id < 1001)
select count(*) into var1 from employee
where emp_id in (select eno from emp_sal);
with set1 as (select emp_id from employee where emp_id < 1001)
select count(*) into var2 from employee
where emp_id in (select eno from emp_sal);
.
.
.
.
and so on
-- select count(*) into var2 from table2 where id in (select * from set1);
-- select count(*) into var3 from table3 where id in (select * from set1);
-- select count(*) into var4 from table4 where id in (select * from set1);
-- select count(*) into var5 from table5 where id in (select * from set1);
-- select count(*) into var6 from table6 where id in (select * from set1);
-- select count(*) into var7 from table7 where id in (select * from set1);
-- select count(*) into var8 from table8 where id in (select * from set1);
-- select count(*) into var9 from table9 where id in (select * from set1);
-- select count(*) into var10 from table10 where id in (select * from set1);
DBMS_OUTPUT.PUT_LINE('var1,var2,var3,var4,var5,var6,var7,var8,var9,var10');
DBMS_OUTPUT.PUT_LINE(var1||','||var2||','||var3||','||var4||','||var5||','||var6||','||var7||','||var8||','||var9||','||var10);
end;
In SQL, a with clause or Common Table Expression is part of a query. It doesn't set a program variable.
with xyz as (select blah from blahblah where something = somethingelse)
select blah from xyz;
You can't refer to xyz in other queries - it is just a clause within a single query.
Related
We are currently analyzing hundreds of queries.
E.g
SELECT a.id,
a.name,
a.hobby,
b.desc
FROM tablename a,
table2 b
WHERE a.id = b.id;
or
SELECT id,
NAME,
hobby
FROM tablename;
above these can be change like below?
SELECT tablename.id,
tablename.name,
tablename.hobby,
table2.desc
FROM tablename tablename,
table2 table2
WHERE tablename.id = table2.id;
or
SELECT tablename.id,
tablename.name,
tablename.hobby
FROM tablename tablename;
Do you know any tools or methods that have the ability to change them?
Here is the Ananymous block for another query :
declare
v_query varchar2(4000) :='SELECT a.id,
a.name,
a.hobby,
b.desc
FROM tablename a,
table2 b
WHERE a.id = b.id';
tab_list varchar2(4000);
v_newquery varchar2(4000);
v_tab_alias varchar2(100);
v_tabname varchar2(500);
v_alias varchar2(40);
tab_cnt NUMBER :=0;
begin
-- table list
select replace(REGEXP_SUBSTR(regexp_replace(v_query,'FROM|WHERE','#'),'[^#]+',1,2)||chr(10),chr(10),null)
into tab_list
from dual;
-- no of tables
select REGEXP_COUNT(TRIM(REGEXP_SUBSTR(regexp_replace(v_query,'FROM|WHERE','#'),'[^#]+',1,2)),',')+1
into tab_cnt
from dual;
For i in 1..tab_cnt
LOOP
select TRIM(REGEXP_SUBSTR(tab_list,'[^,]+',1,i))
into v_tab_alias
from dual;
-- replace alias tablename for the column list
select TRIM(REGEXP_SUBSTR(v_tab_alias,'[^ ]+',1,1))
into v_tabname
from dual;
select TRIM(REGEXP_SUBSTR(v_tab_alias,'[^ ]+',1,2))
into v_alias
from dual;
select regexp_replace(v_query,v_alias||'\.',v_tabname||'.')
into v_newquery
from dual;
v_query:= v_newquery;
-- replace alias tablename in FROM clause
select regexp_replace(v_query,v_alias||'\,',v_tabname||',')
into v_query
from dual;
END LOOP;
-- replace alias last tablename before WHERE clause
select regexp_replace(v_query,v_tab_alias,v_tabname||' '||v_tabname)
into v_query
from dual;
DBMS_OUTPUT.PUT_LINE(v_query);
END;
is it possible to define a select statement as variable, somethings like this:
Define (Select t1.id, t1.var1, t1.var2, t2.id, t2.var1, t2.var2 From
table1 t1, table2 t2 Where t1.id = t2.id) as namevariable
Thanks for your help,
Andrea
Define (Select t1.id, t1.var1, t1.var2, t2.id, t2.var1, t2.var2 From
table1 t1, table2 t2 Where t1.id = t2.id) as namevariable
You can do it as :
DECLARE
var VARCHAR2 (100);
v_emp_id number;
BEGIN
--Defining as a variable in PLSQL
var := 'Select employee_id from employee where employee_id = :1';
EXECUTE IMMEDIATE var into v_emp_id using 1 ;
--Showing the result
DBMS_OUTPUT.PUT_LINE(v_emp_id);
END;
simply with select ... into ...
DECLARE
my_id NUMBER;
my_val VARCHAR2(32);
BEGIN
SELECT t1.id, t1.val into my_id, my_val from my_table t1 where... ;
END;
I am trying to retrieve values from temporarily created tables. But the return value throws the error 'Invalid Identifier'
create or replace procedure edu_stream (input in varchar2,vals out varchar2)
as
inp varchar2(30);
valu varchar2(30);
begin
inp:=input;
if inp='secondary education' then
Execute immediate'WITH secedu as (
(SELECT "ICSE" as name FROM dual ) UNION
(SELECT "CBSE" as name FROM dual ) UNION
(SELECT "STATE BOARD" as name FROM dual)
)
SELECT name into valu from(SELECT name
FROM secedu ORDER BY DBMS_RANDOM.RANDOM)where rownum<2';
vals:=valu;
else
if inp='intermediate education' then
Execute immediate'WITH intedu as (
(SELECT "MPC" as name FROM dual ) UNION
(SELECT "BIPC" as name FROM dual ) UNION
(SELECT "MBIPC" as name FROM dual) UNION
(SELECT "CEC" as name FROM dual)
)
SELECT name into valu from(SELECT name
FROM intedu ORDER BY DBMS_RANDOM.RANDOM)where rownum<2';
vals:=valu;
else
if inp='Graduation' then
Execute immediate'WITH gedu as (
(SELECT "ECE" as name FROM dual ) UNION
(SELECT "CSE" as name FROM dual ) UNION
(SELECT "CE" as name FROM dual) UNION
(SELECT "EEE" as name FROM dual)UNION
(SELECT "ME" as name FROM dual)UNION
(SELECT "AE" as name FROM dual)UNION
(SELECT "BIOTECH" as name FROM dual)UNION
(SELECT "EIE" as name FROM dual)
)
SELECT name into valu from(SELECT name
FROM gedu ORDER BY DBMS_RANDOM.RANDOM)where rownum<2';
vals:=valu;
else
if inp='post-graduation' then
Execute immediate'WITH pgedu as (
(SELECT "MCA" as name FROM dual ) UNION
(SELECT "MTECH" as name FROM dual ) UNION
(SELECT "MSC" as name FROM dual) UNION
(SELECT "MBA" as name FROM dual)
)
SELECT name into valu from(SELECT name
FROM pgedu ORDER BY DBMS_RANDOM.RANDOM)where rownum<2';
vals:=valu;
else
if inp='phd'then
Execute immediate' WITH phdedu as (
(SELECT "Doctorate of philosophy" as name FROM dual ) UNION
(SELECT "doctorate of medicine" as name FROM dual ) UNION
(SELECT "doctorate of science" as name FROM dual) UNION
(SELECT "Doctorate of computer sciences" as name FROM dual)
)
SELECT name into valu from(SELECT name
FROM phdgedu ORDER BY DBMS_RANDOM.RANDOM)where rownum<2';
vals:=valu;
end if;
end if;
end if;
end if;
end if;
end;
Execution:
declare
value1 varchar2(30);
cv varchar2(30);
begin
cv:='secondary education';
edu_stream(cv,value1);
dbms_output.put_line('val is'||value1);
end;
Error report:
Error starting at line 2 in command: declare value1 varchar2(30); cv
varchar2(30); begin cv:='secondary education'; edu_stream(cv,value1);
dbms_output.put_line('val is'||value1); end; Error report: ORA-00904:
"ICSE": invalid identifier ORA-06512: at "DATAFOCUS_GROUP.EDU_STREAM",
line 9 ORA-06512: at line 6
00904. 00000 - "%s: invalid identifier"
*Cause:
*Action:
if I use 'ICSE'instead of "ICSE"
ERROR SHOWS-
PLS-00103: Encountered the symbol "ICSE" when expecting one of the
following:
ERROR 103 * & = - + ; < / > at in is mod remainder not rem
return
returning <> or != or ~= >= <= <> and or
like like2 like4 likec between into using || multiset bulk
member submultiset
You can avoid dynamic SQL; also, probably due to confusion created by dynamic sql, you are using " instead of '.
You can re-write your code as:
CREATE OR REPLACE PROCEDURE edu_stream(input IN VARCHAR2, vals OUT VARCHAR2) AS
inp VARCHAR2(30);
valu VARCHAR2(30);
BEGIN
inp := input;
IF inp = 'secondary education'
THEN
WITH secedu AS
((SELECT 'ICSE' AS name FROM DUAL)
UNION
(SELECT 'CBSE' AS name FROM DUAL)
UNION
(SELECT 'STATE BOARD' AS name FROM DUAL))
SELECT name
INTO valu
FROM ( SELECT name
FROM secedu
ORDER BY DBMS_RANDOM.RANDOM)
WHERE ROWNUM < 2;
vals := valu;
ELSE
IF inp = 'intermediate education'
THEN
WITH intedu AS
((SELECT 'MPC' AS name FROM DUAL)
UNION
(SELECT 'BIPC' AS name FROM DUAL)
UNION
(SELECT 'MBIPC' AS name FROM DUAL)
UNION
(SELECT 'CEC' AS name FROM DUAL))
SELECT name
INTO valu
FROM ( SELECT name
FROM intedu
ORDER BY DBMS_RANDOM.RANDOM)
WHERE ROWNUM < 2;
vals := valu;
ELSE
IF inp = 'Graduation'
THEN
WITH gedu AS
((SELECT 'ECE' AS name FROM DUAL)
UNION
(SELECT 'CSE' AS name FROM DUAL)
UNION
(SELECT 'CE' AS name FROM DUAL)
UNION
(SELECT 'EEE' AS name FROM DUAL)
UNION
(SELECT 'ME' AS name FROM DUAL)
UNION
(SELECT 'AE' AS name FROM DUAL)
UNION
(SELECT 'BIOTECH' AS name FROM DUAL)
UNION
(SELECT 'EIE' AS name FROM DUAL))
SELECT name
INTO valu
FROM ( SELECT name
FROM gedu
ORDER BY DBMS_RANDOM.RANDOM)
WHERE ROWNUM < 2;
vals := valu;
ELSE
IF inp = 'post-graduation'
THEN
WITH pgedu AS
((SELECT 'MCA' AS name FROM DUAL)
UNION
(SELECT 'MTECH' AS name FROM DUAL)
UNION
(SELECT 'MSC' AS name FROM DUAL)
UNION
(SELECT 'MBA' AS name FROM DUAL))
SELECT name
INTO valu
FROM ( SELECT name
FROM pgedu
ORDER BY DBMS_RANDOM.RANDOM)
WHERE ROWNUM < 2;
vals := valu;
ELSE
IF inp = 'phd'
THEN
WITH phdedu AS
((SELECT 'Doctorate of philosophy' AS name FROM DUAL)
UNION
(SELECT 'doctorate of medicine' AS name FROM DUAL)
UNION
(SELECT 'doctorate of science' AS name FROM DUAL)
UNION
(SELECT 'Doctorate of computer sciences' AS name FROM DUAL))
SELECT name
INTO valu
FROM ( SELECT name
FROM phdgedu
ORDER BY DBMS_RANDOM.RANDOM)
WHERE ROWNUM < 2;
vals := valu;
END IF;
END IF;
END IF;
END IF;
END IF;
END;
Also, please notice that the variables inp and valu are not strictly necessary: you can simply use the parameters to check the input value and build the output parameter.
In case you need do use dynamic SQL (not here, but maybe in the future) the right way is something like:
declare
a number;
begin
execute immediate 'select 1 from dual' into a;
end;
As an alternative answer sticking with your dynamic SQL.
personal preference: i´d allways end a line with ' ||, to make it clear you are not missing a whitespace (even though it should just execute fine).
remove the into valu from the dynamic sql and make it a execute immediate 'query' into vals clause.
As an example i´m just using your first query:
Execute immediate 'WITH secedu as ( ' ||
'(SELECT ''ICSE'' as name FROM dual ) UNION ' ||
'(SELECT ''CBSE'' as name FROM dual ) UNION ' ||
'(SELECT ''STATE'' BOARD" as name FROM dual) ' ||
') ' ||
'SELECT name from(SELECT name ' ||
'FROM secedu ORDER BY DBMS_RANDOM.RANDOM)where rownum<2'
into vals;
You might have your own learning objectives but when those put aside the code is simply awful and unnecessary complex PL/SQL. Here is a partial but completely functional rewrite with references to relevant Oracle PL/SQL documentation. Hope you'll find the presented ideas useful !
-- blocks: http://docs.oracle.com/database/121/LNPLS/overview.htm#LNPLS141
declare
-- nested tables: http://docs.oracle.com/database/121/LNPLS/composites.htm#LNPLS99981
type str_list_t is table of varchar2(32767);
-- subprograms: http://docs.oracle.com/database/121/LNPLS/subprograms.htm#LNPLS008
-- common parts of f() refactored to r()
function r(p_list in str_list_t) return varchar2 is
begin
return p_list(floor(dbms_random.value(1, p_list.count + 1)));
end;
function f(p_edu_level in varchar2) return varchar2 is
begin
return
-- simple case: http://docs.oracle.com/database/121/LNPLS/controlstatements.htm#LNPLS394
case p_edu_level
when 'secondary' then r(str_list_t('ICSE', 'CBSE', 'STATE BOARD'))
when 'intermediate' then r(str_list_t('MPC', 'BIPC', 'MIPC', 'CEC'))
-- add here your other education levels, you should see the pattern ...
else null
end;
end;
begin
-- for loop: http://docs.oracle.com/database/121/LNPLS/controlstatements.htm#LNPLS411
for i in 1 .. 10
loop
dbms_output.put_line('secondary: ' || f('secondary'));
dbms_output.put_line('intermediate: ' || f('intermediate'));
end loop;
dbms_output.put_line('batman: ' || f('batman'));
end;
/
I would like to have pl-sql like the following:
SELECT ID FROM some-table WHERE
(SELECT MAX(some-expression) FROM another-table = 1) OR
(some-table.ID IN SELECT (SELECT ID FROM one-more-table))
This pseudo-query would select all IDs from some-table if maximum value of some-expression equals 1 (or filter IDs by one-more-table values otherwise)
How do I properly implement this in PL-SQL ?
Thank you in advance!
Please find the below pl-sql:
DECLARE
v_Column1 NUMBER(4);
v_deptno NUMBER(2);
BEGIN
SELECT MAX(A.DEPTNO)
INTO v_deptno
FROM (SELECT DEPTNO FROM DEPT) A;
SELECT A.EMPNO
INTO v_Column1
FROM EMP A
WHERE A.DEPTNO=v_deptno
OR
A.EMPNO IN ( SELECT EMPNO FROM EMP_2);
END;
/
I'm having some troubles with putting a variable in a HAVING clause, the problem is that I need COUNT(*) to be greater than the variable.
I'm using ORACLE Database XE 11.2
DECLARE
cnt1 NUMBER;
cnt2 NUMBER;
res NUMBER;
BEGIN
SELECT COUNT(*)
INTO cnt1
FROM BESTELLING;
SELECT COUNT(*)
INTO cnt2
FROM ARTIKEL;
res := cnt1 / cnt2;
END;
/
SELECT A.Naam, COUNT(*) AS HOEVEEL_VERKOCHT
FROM Artikel A, Winkelwagen W
WHERE A.Artikel_ID = W.Artikel_ID
AND W.Datum_Besteld IS NOT NULL
GROUP BY A.Naam
HAVING COUNT(*) > ?res?
ORDER BY COUNT(*) DESC;
Place queries from PL/SQL directly in your main query, as subqueries:
.......
HAVING COUNT(*) >
( SELECT COUNT(*) FROM BESTELLING ) /
( SELECT COUNT(*) FROM ARTIKEL )
ORDER BY COUNT(*) DESC;
such way wont work ?
DECLARE
cnt1 NUMBER;
cnt2 NUMBER;
result NUMBER;
BEGIN
SELECT COUNT(*)
INTO cnt1
FROM BESTELLING;
SELECT COUNT(*)
INTO cnt2
FROM ARTIKEL;
result := cnt1 / cnt2;
SELECT A.Naam, res, COUNT(*) AS HOEVEEL_VERKOCHT
FROM Artikel A, Winkelwagen W
WHERE A.Artikel_ID = W.Artikel_ID
AND W.Datum_Besteld IS NOT NULL
GROUP BY A.Naam, res
HAVING COUNT(*) > result
ORDER BY COUNT(*) DESC;
END;
/
I change variable res to result , because it seems you have column called res