Dynamic select in Oracle - oracle

I want to do something like this:
sql_str := 'select ';
if (user_input = 1) then
sql_str := sql_str || 'a.col1 from tb1 a';
else
sql_str := sql_str || 'a.col1, b.col2, b.col3 from tb1 a, tb2 b';
execute sql_str
I don't have much, not to say any, experience with Oracle's procedures, functions, etc.
I'm having trouble to find out how to create a procedure (or function) in Oracle to perform the above code.
Any help is appreciated. Thank you.

As you are not returning any value we have to go for procedure. Although use case is not clear.
CREATE PROCEDURE dyn_sql_query (user_input IN NUMBER)
IS
sql_str VARCHAR2 (500) := 'SELECT ';
BEGIN
IF (user_input = 1)
THEN sql_str := sql_str || 'a.col1 from tb1 a';
ELSE sql_str := sql_str || 'a.col1, b.col2, b.col3 from tb1 a, tb2 b';
END IF;
EXECUTE IMMEDIATE sql_query;
END;
Here is very basic script for function (notice RETURN) that accepts table name and returns number of rows.
CREATE FUNCTION count_rows (table_name IN VARCHAR2)
RETURN PLS_INTEGER //
IS
sql_query VARCHAR2 (500) := 'SELECT COUNT(*) FROM ' || table_name;
ret_val PLS_INTEGER;
BEGIN
EXECUTE IMMEDIATE sql_query INTO ret_val;
RETURN ret_val;
END;

Using Your Example, Here is One Approach to Dynamic SQL
As others have indicated, there are many examples of dynamic sql on Stack Exchange.
The documentation is very good on this subject. I like the using clause which makes the dynamic sql more extensible.
In practice, the dynamic sql does something: select ... into, a procedural call, dml, dcl.
SCOTT#dev>declare
2 user_input number(1) :=1;
3 sql_str varchar2(1000);
4 begin
5
6 sql_str := 'select ';
7 if (user_input = 1) then
8 -- sql_str := sql_str || 'a.col1 from tb1 a';
9 sql_str := sql_str || '''1'' from dual';
10 dbms_output.put_line(sql_str);
11 else
12 -- sql_str := sql_str || 'a.col1, b.col2, b.col3 from tb1 a, tb2 b';
13 sql_str := sql_str || '''2'' from dual';
14 dbms_output.put_line(sql_str);
15 end if;
16 execute immediate sql_str;
17 end;
18 /
select '1' from dual
PL/SQL procedure successfully completed.
SCOTT#dev>declare
2 user_input number(1) :=2;
3 sql_str varchar2(1000);
4 begin
5
6 sql_str := 'select ';
7 if (user_input = 1) then
8 -- sql_str := sql_str || 'a.col1 from tb1 a';
9 sql_str := sql_str || '''1'' from dual';
10 dbms_output.put_line(sql_str);
11 else
12 -- sql_str := sql_str || 'a.col1, b.col2, b.col3 from tb1 a, tb2 b';
13 sql_str := sql_str || '''2'' from dual';
14 dbms_output.put_line(sql_str);
15 end if;
16 execute immediate sql_str;
17 end;
18 /
select '2' from dual
PL/SQL procedure successfully completed.
With my example as people have commented, a simple select statement usually does not make sense (no one does this in practice).
One can see that my dynamic sql is parsed by looking at v$sql which shows statistics on the shared sql area:
APPS#dev>SELECT
2 sql_id
3 FROM
4 v$sql
5 WHERE
6 1 = 1
7 AND (
8 sql_text = 'select ''1'' from dual'
9 OR
10 sql_text = 'select ''2'' from dual'
11 ) AND
12 parsing_schema_name = 'SCOTT';
SQL_ID
-------------
27q1fj58cnz0k
c9bw73fh2ay8d
addendum based on comments
As Alex cited, the documentation indicates that a select statement without an into clause does not get executed. It is at least parsed and can be seen in the shared sql area, v$sql.
Here is my example with the into clause.
APPS#dev>DECLARE
2 user_input NUMBER(1) := 1;
3 sql_str VARCHAR2(1000);
4 v_val VARCHAR2(1);
5 BEGIN
6 sql_str := 'select ';
7 IF
8 ( user_input = 1 )
9 THEN
10 -- sql_str := sql_str || 'a.col1 from tb1 a';
11 sql_str := sql_str || '''1'' from dual';
12 ELSE
13 -- sql_str := sql_str || 'a.col1,b.col2,b.col3 from tb1 a,tb2 b';
14 sql_str := sql_str || '''2'' from dual';
15 END IF;
16
17 EXECUTE IMMEDIATE sql_str INTO
18 v_val;
19 dbms_output.put_line(sql_str || ' => ' || v_val);
20 END;
21 /
select '1' from dual => 1
PL/SQL procedure successfully completed.

I am not sure if it helps you but you can create a procedure something like below
CREATE OR REPLACE PROCEDURE test_Ali (user_input IN VARCHAR2(2))
IS
sql_str VARCHAR2(1000):= 'select ';
user_input VARCHAR2(2) := '1';
BEGIN
IF user_input = '1' THEN
BEGIN
sql_str := sql_str||'a.col1 from tb1 a';
EXECUTE IMMEDIATE sql_str;
dbms_output.put_line (sql_str) ;
END;
ELSE
BEGIN
sql_str := sql_str||'a.col1, b.col2, b.col3 from tb1 a, tb2 b';
EXECUTE IMMEDIATE sql_str;
dbms_output.put_line (sql_str) ;
END;
END IF;
END;

Related

How to create dynamic cursor in PLSQL - Oracle

I cannot create this cursor dynamically, I only have to modify the name of the table in the statement. But it returns me error.
What am I doing wrong or what am I missing to create the dynamic cursor?
The dynamic statement is in the Lv_SQL variable and I call the cursor C_DATOS but it does not recognize it.
PROCEDURE PROC_CAB_DET(Pv_corte VARCHAR2, Pv_MsjError IN OUT VARCHAR2) IS
Lv_Table VARCHAR2(100);
Lv_SQL VARCHAR2(5000);
C_DATOS SYS_REFCURSOR;
BEGIN
Lv_Table := NULL;
IF (Pv_corte IN ('02', '03')) THEN
Lv_Table := 'TABLE_TMP_MOV';
ELSIF (Pv_corte IN ('14', '15')) THEN
Lv_Table := 'TABLE_TMP_FIX';
ELSE
Lv_Table := 'TABLE_TMP_CMF';
END IF;
Lv_SQL := 'SELECT cuenta, campo_2 RUBRO
FROM ' || Lv_Table || '
WHERE codigo = 1
AND CAMPO_3 != "000"
AND (campo_2 NOT IN (SELECT RUBRO FROM GSI_QC_RUBROS_CABECERA)
AND upper(campo_2) NOT LIKE "NAN%")
MINUS
SELECT cuenta, campo_2 RUBRO
FROM ' || Lv_Table || '
WHERE codigo=4
AND campo_2 != "ICE (12%)"';
OPEN C_DATOS FOR Lv_SQL;
FOR I IN C_DATOS LOOP
INSERT INTO GSI_QC_CBS_CASOS_ERROR(CUENTA, ID_ESCENARIO, DATO_TMP_1)
VALUES(I.CUENTA, 'IdEscenario', 'DATA');
END LOOP;
COMMIT;
CLOSE C_DATOS;
EXCEPTION
WHEN OTHERS THEN
Pv_MsjError := SQLERRM;
END PROC_CAB_DET;
PLS-00221: C_DATOS is not a procedure or is undefined
You can't enclose strings into double quotes; have to be single ones. To make it simpler, use the q-quoting mechanism. Also, you wrongly looped through refcursor.
I created dummy tables to make that procedure compile; I don't know whether code does what you planned.
SQL> create or replace
2 PROCEDURE PROC_CAB_DET(Pv_corte VARCHAR2, Pv_MsjError IN OUT VARCHAR2) IS
3 Lv_Table VARCHAR2(100);
4 Lv_SQL VARCHAR2(5000);
5 C_DATOS SYS_REFCURSOR;
6 --
7 l_cuenta table_tmp_mov.cuenta%type;
8 l_rubro table_tmp_mov.campo_2%type;
9 BEGIN
10 Lv_Table := NULL;
11 IF (Pv_corte IN ('02', '03')) THEN
12 Lv_Table := 'TABLE_TMP_MOV';
13 ELSIF (Pv_corte IN ('14', '15')) THEN
14 Lv_Table := 'TABLE_TMP_FIX';
15 ELSE
16 Lv_Table := 'TABLE_TMP_CMF';
17 END IF;
18
19 Lv_SQL := 'SELECT cuenta, campo_2 RUBRO
20 FROM ' || Lv_Table || q'[
21 WHERE codigo = 1
22 AND CAMPO_3 != '000'
23 AND (campo_2 NOT IN (SELECT RUBRO FROM GSI_QC_RUBROS_CABECERA)
24 AND upper(campo_2) NOT LIKE 'NAN%')
25 MINUS
26 SELECT cuenta, campo_2 RUBRO
27 FROM ]' || Lv_Table || q'[
28 WHERE codigo=4
29 AND campo_2 != 'ICE (12%)']';
30
31 OPEN C_DATOS FOR Lv_SQL;
32
33 loop
34 fetch c_datos into l_cuenta, l_rubro;
35 exit when c_datos%notfound;
36
37 INSERT INTO GSI_QC_CBS_CASOS_ERROR(CUENTA, ID_ESCENARIO, DATO_TMP_1)
38 VALUES(l_CUENTA, 'IdEscenario', 'DATA');
39 END LOOP;
40 COMMIT;
41
42 CLOSE C_DATOS;
43
44 EXCEPTION
45 WHEN OTHERS THEN
46 Pv_MsjError := SQLERRM;
47 END PROC_CAB_DET;
48 /
Procedure created.
Let's run it:
SQL> set serveroutput on;
SQL> declare
2 l_err varchar2(200);
3 begin
4 proc_cab_det('02', l_err);
5 dbms_output.put_line('error = ' || l_err);
6 end;
7 /
error =
PL/SQL procedure successfully completed.
SQL>
Replace " inside your lv_SQL string with doubled single quotes, ''

Oracle PL/SQL issue: PLS-00306 : wrong number or types of arguments in call to

Today I have code I get error
PLS-00306: wrong number or types of arguments in call to
and I make sure the code working fine but when I use in dynamic code not worked
CREATE OR REPLACE PROCEDURE TB_DATA(P_TB_NAME VARCHAR2)
IS
V_COLUMNS VARCHAR2(32000) := GET_ALL_COLUMNS(P_TB_NAME) ;
V_COLUMNS_IN_LOOP VARCHAR2(32000) := 'I.'||REPLACE ( GET_ALL_COLUMNS(P_TB_NAME) , ',' , '||'',''||I.') ;
V_FILE UTL_FILE.FILE_TYPE ;
BEGIN
EXECUTE IMMEDIATE 'DECLARE
CURSOR C1 IS
SELECT '||V_COLUMNS || '
FROM '||P_TB_NAME || ';
BEGIN
' ||V_FILE ||' := UTL_FILE.FOPEN ( ''MY_DIR'' , ''TASK9.CSV'' , ''W'' ) ;
UTL_FILE.PUT_LINE ( '||V_FILE ||' , '|| V_COLUMNS||');
FOR I IN C1 LOOP
UTL_FILE.PUT_LINE ( '||V_FILE ||', '|| V_COLUMNS_IN_LOOP||') ;
END LOOP ;
END ;';
END ;
Function:
CREATE OR REPLACE FUNCTION HR.GET_ALL_COLUMNS (P_TABLE VARCHAR2)
RETURN VARCHAR2
IS
CURSOR C IS
SELECT *
FROM USER_TAB_COLUMNS
WHERE TABLE_NAME = P_TABLE ;
CURSOR C1 IS
SELECT *
FROM TAB
WHERE TNAME = P_TABLE ;
V_COLS VARCHAR2(32000);
V_COLS2 VARCHAR2(32000);
BEGIN
FOR I IN C LOOP
V_COLS := V_COLS ||','|| I.COLUMN_NAME ;
END LOOP ;
FOR V IN C1 LOOP
V_COLS2 := V_COLS2 ||','|| P_TABLE ;
END LOOP ;
RETURN LTRIM( V_COLS , ',') ;
END ;
I just need to know where is my mistake or what is missing.
The function is OK; it is procedure that fails because you have to declare V_FILE within the dynamic SQL part of code, not outside of it. Something like this:
SQL> CREATE OR REPLACE PROCEDURE TB_DATA (P_TB_NAME VARCHAR2)
2 IS
3 V_COLUMNS VARCHAR2 (32000) := GET_ALL_COLUMNS (P_TB_NAME);
4 V_COLUMNS_IN_LOOP VARCHAR2 (32000)
5 := 'I.' || REPLACE (GET_ALL_COLUMNS (P_TB_NAME), ',', '||'',''||I.');
6 L_STR VARCHAR2 (10000);
7 BEGIN
8 L_STR :=
9 'DECLARE
10 V_FILE UTL_FILE.FILE_TYPE;
11 CURSOR C1 IS
12 SELECT '
13 || V_COLUMNS
14 || '
15 FROM '
16 || P_TB_NAME
17 || ';
18 BEGIN
19 V_FILE := UTL_FILE.FOPEN ( ''MY_DIR'' , ''TASK9.CSV'' , ''W'' ) ;
20 FOR I IN C1 LOOP
21 UTL_FILE.PUT_LINE ( V_FILE, '
22 || V_COLUMNS_IN_LOOP
23 || ') ;
24 END LOOP ;
25 UTL_FILE.FCLOSE(V_FILE);
26 END ;';
27
28 EXECUTE IMMEDIATE L_STR;
29 END;
30 /
Procedure created.
Testing:
SQL> EXEC TB_DATA('DEPT');
PL/SQL procedure successfully completed.
SQL>

Can we use collection variable as a table in execute immediate?

Declare
Type t_approved_node is record( node_rowid Hr
node_rowid%type, Node_+type hr.node_type%type);
Type t_val is table of t_approved_node Index by pls_integer;
V_node t_val;
V_tab varchar2(20);
V_col varchar2(400);
V_nrf_flg hr.hr_flag%type;
V_ubrf_flg hr.hr_flag%type := 3;
V_col_str varchar2(4000);
Begin
Begin
Select hr_flag into v_nrf_flg from hr;
End;
Begin
Select h.node_rowid, h.node_type bulk collect into v_node
from hr h, hr_attr_wfm haw
Where h.hr_relation_id = haw.uc_hr_relation_id
And h.node_type = 'UBR';
Begin
V_tab := 'UC_UBR';
Select listagg(column_name, ',' within group(order by
column_id)
Into v_col from user_tab_columns where table_name = v_tab;
End;
V_col_str := regex_replace( v_col, 'HR_FLAG', v_ubrf_flg);
Execute immediate ' insert into ' || v_tab || '( ' ||
V_col || ') ' || ' select '|| v_col_str || ' from ' ||
V_tab || 'R ' || q' [ where node_type = ' UBR' a
and hr_flag =:1 and exists( ] ' || ' select 1 ' || ' from table( ' ||
v_node || ')y' || q' [ where y.node_rowid = R.node_rowid ] )'
Using v_nrf_flag;
End;
End;
I was trying to execute above block getting below error.
Wrong number or types of arguments in call to ||
Final query should be like
insert into UC_UBR ( v_col)/*3 columns into v_col variable*/
select v_col_str /* 3 columns in v_col_str variable*/ from UC_UBR R where hr_flag =:1
and exists
(select 1 from table(v_node) /*collection variable*/ y
where y.node_rowid = r.node_rowod;
Can anyone help on this?
Your sample code is full of errors and does not make any sense at all. But if I focus on your question, then the answer is "yes". See this example:
CREATE OR REPLACE TYPE t_app AS OBJECT( nodeid NUMBER, Nodetype VARCHAR2(100));
CREATE OR REPLACE TYPE t_val IS TABLE OF t_app;
DECLARE
V_node t_val;
V_result t_val;
V_app t_app;
V_count NUMBER;
Sql_stmt VARCHAR2(100);
nodeid NUMBER;
Nodetype VARCHAR2(100);
BEGIN
SELECT t_app(nodeid, Nodetype) BULK COLLECT INTO V_node FROM HR;
Sql_stmt := 'SELECT count(*) FROM TABLE(:t)';
EXECUTE IMMEDIATE Sql_stmt INTO V_count USING V_node;
DBMS_OUTPUT.PUT_LINE ( 'V_count = ' || V_count );
Sql_stmt := 'SELECT nodeid, Nodetype FROM TABLE(:t) WHERE ROWNUM = 1';
EXECUTE IMMEDIATE Sql_stmt INTO nodeid, Nodetype USING V_node;
DBMS_OUTPUT.PUT_LINE ( 'nodeid = ' || nodeid );
DBMS_OUTPUT.PUT_LINE ( 'Nodetype = ' || Nodetype );
Sql_stmt := 'SELECT t_app(nodeid, Nodetype) FROM TABLE(:t) WHERE ROWNUM = 1';
EXECUTE IMMEDIATE Sql_stmt INTO V_app USING V_node;
DBMS_OUTPUT.PUT_LINE ( 'V_app = ' || XMLTYPE(V_app).getClobVal() );
Sql_stmt := 'SELECT t_app(nodeid, Nodetype) FROM TABLE(:t)';
EXECUTE IMMEDIATE Sql_stmt BULK COLLECT INTO V_result USING V_node;
END;
It would help if you posted real code you used, because this is full of syntax errors (missing sql_stmt local variable declaration, put.line (?)).
I have no idea what you plan to do with such a select statement as you can't execute it, it doesn't make any sense but - here you go; see line #20.
SQL> set serveroutput on
SQL>
SQL> DECLARE
2 TYPE t_app IS RECORD
3 (
4 nodeid NUMBER,
5 Nodetype VARCHAR2 (20)
6 );
7
8 TYPE t_val IS TABLE OF t_app
9 INDEX BY PLS_INTEGER;
10
11 V_node t_val;
12 V_tab VARCHAR2 (20);
13
14 sql_stmt VARCHAR2 (200);
15 BEGIN
16 SELECT empno, ename
17 BULK COLLECT INTO v_node
18 FROM emp;
19
20 Sql_stmt := 'select 1 from (' || v_node (1).nodeid || 'Y)';
21
22 DBMS_OUTPUT.put_line (sql_stmt);
23 END;
24 /
select 1 from (7369Y)
PL/SQL procedure successfully completed.
SQL>

how to get the field name and value from a record dynamically

I have a procedure which receive as input parameter a record with 170 columns (it is based on the structure of a table).
In the procedure I want to call a debugging procedure one of whose parameters is a text string containing all the field names and values of this record.
For example:
CREATE OR REPLACE PROCEDURE xxx (pi_record IN table_name%ROWTYPE) as
text VARCHAR2(10000) := NULL;
BEGIN
...
text := 'pi_record.column1 = ' || pi_record.column1 || CHR(13) ||
'pi_record.column2 = ' || pi_record.column2 || CHR(13) ||
...
'pi_record.column170 = ' || pi_record.column170;
logging_procedure (text);
...
END;
Is there any simple way to achieve this in a dynamic way (looping through record fields names and values) without enumerating all of them?
Maybe something like this:
CREATE OR REPLACE PROCEDURE xxx (pi_record IN table_name%ROWTYPE) as
text VARCHAR2(10000) := NULL;
BEGIN
...
LOOP in pi_record.columns
text := text || CHR(13) || pi_record.column.name || ' : ' || pi_record.column.value
END LOOP
logging_procedure (text);
...
END;
Many thanks,
Here's one way to do that. A package spec contains a variable whose type matches the one we'll use in a procedure.
SQL> set serveroutput on
SQL> create or replace package pkg_xxx
2 as
3 dept_rec dept%rowtype;
4 end;
5 /
Package created.
SQL> create or replace procedure xxx (pi_record in dept%rowtype)
2 as
3 text varchar2 (10000) := null;
4 l_str varchar2 (200);
5 l_var varchar2 (200);
6 begin
7 pkg_xxx.dept_rec := pi_record;
8
9 for cur_r in ( select column_name
10 from user_tab_columns
11 where table_name = 'DEPT'
12 order by column_id)
13 loop
14 l_str :=
15 'begin '
16 || ':x := to_char(pkg_xxx.dept_rec.'
17 || cur_r.column_name
18 || '); '
19 || 'end; ';
20
21 execute immediate l_str using out l_var;
22
23 text := text || chr (10) || cur_r.column_name || ' = ' || l_var;
24 end loop;
25
26 dbms_output.put_line (text);
27 end;
28 /
Procedure created.
Now, let's pass something to the procedure and see what happens:
SQL> declare
2 cursor c1
3 is
4 select *
5 from dept
6 where deptno = 10;
7
8 c1r c1%rowtype;
9 begin
10 open c1;
11 fetch c1 into c1r;
12 close c1;
13
14 xxx (c1r);
15 end;
16 /
DEPTNO = 10
DNAME = ACCOUNTING
LOC = NEW YORK
PL/SQL procedure successfully completed.
SQL>
Huh, kind of works (if that's what you asked). Of course, it is just an example, you'll have to modify it if you want to get something really smart (hint: DATE columns).
The only idea I have is to insert the record into a TEMP table:
CREATE OR REPLACE PROCEDURE xxx (pi_record IN TABLE_NAME%ROWTYPE) AS
TEXT VARCHAR2(10000) := NULL;
item VARCHAR2(1000);
TABLE_DOES_NOT_EXIST EXCEPTION;
PRAGMA EXCEPTION_INIT(TABLE_DOES_NOT_EXIST, -942);
BEGIN
BEGIN
EXECUTE IMMEDIATE 'DROP TABLE TABLE_NAME_TMP';
EXCEPTION
WHEN TABLE_DOES_NOT_EXIST then null;
END;
EXECUTE IMMEDIATE 'CREATE GLOBAL TEMPORARY TABLE TABLE_NAME_TMP AS SELECT * FROM TABLE_NAME WHERE ROWNUM = 0';
DELETE FROM TABLE_NAME_TMP;
INSERT INTO TABLE_NAME_TMP VALUES pi_record;
FOR aCol IN (SELECT COLUMN_NAME FROM ALL_TAB_COLUMNS WHERE table_name = 'TABLE_NAME' ORDER BY COLUMN_ID) LOOP
EXECUTE IMMEDIATE 'SELECT '||aCol.COLUMN_NAME||' FROM TABLE_NAME_TMP' INTO item;
TEXT := TEXT || CHR(13) || aCol.COLUMN_NAME || ' : ' || item;
END LOOP;
DBMS_OUTPUT.PUT_LINE ( TEXT );
END;
In case table TABLE_NAME has static attributes then you should skip dynamic DROP TABLE ... and CREATE GLOBAL TEMPORARY TABLE ... and create the TEMP table only once.
everyone!
I got a different approach to get the difference between records dynamically:
You just have to create the global variables on the package header as bellow:
v_NAME_OF_TABLE_new NAME_OF_TABLE%rowtype;
v_NAME_OF_TABLE_old NAME_OF_TABLE%rowtype;
then create the function on your pkg body that return a boolean even if a field is different:
function is_different(p_old NAME_OF_TABLE%rowtype, p_new NAME_OF_TABLE%rowtype)
return boolean
is
cursor cols is
select tb.COLUMN_NAME
from all_tab_columns tb
where tb.OWNER = 'DW'
and tb.TABLE_NAME = 'NAME_OF_TABLE'
order by tb.COLUMN_ID;
l_sql varchar2(4000);
l_new varchar2(4000);
l_old varchar2(4000);
begin
pkg_NAME.v_NAME_OF_TABLE_new := p_new;
pkg_NAME.v_NAME_OF_TABLE_old := p_old;
for reg in cols loop
l_sql := '
begin
:x := pkg_NAME.v_NAME_OF_TABLE_new.'||reg.COLUMN_NAME||';'||'
end;';
execute immediate l_sql using out l_new;
l_sql := '
begin
:x := pkg_NAME.v_NAME_OF_TABLE_old.'||reg.COLUMN_NAME||';'||'
end;';
execute immediate l_sql using out l_old;
--- dbms_output.put_line(l_new||' - '||l_old);
if nvl(l_new,'NULO') <> nvl(l_old,'NULO') then
return true;
end if;
end loop;
return false;
end;
Atention: This can turn your process heavier and slower.
That's all!
Hope this can be helpful!

pl/sql block code issue with multiple records return

can't make this work... have a multiple tables names which i need to pass into select. Each select will return multiple records. Resultset should be printed to the user on a screen .
SQL> set serveroutput on;
SQL> DECLARE
vs_statement VARCHAR2 (1000);
my_var1 VARCHAR2(100);
my_var2 VARCHAR2(100);
CURSOR c1 IS
SELECT table_name
FROM all_tables
WHERE table_name LIKE Upper('redit_1%');
BEGIN
FOR table_rec IN c1 LOOP
vs_statement :=
'select a.userinfo, a.userstatus into my_var1, my_var12 from '
|| table_rec.table_name
|| ' A, FILES b where A.objectid = B.id order by 1';
EXECUTE IMMEDIATE vs_statement INTO my_var1,
my_var2;
dbms_output.Put_line(my_var1
||' '
|| my_var2);
END LOOP;
END;
/
This line should look like the following (i.e. remove INTO clause):
vs_statement :=
'select a.userinfo, a.userstatus from '
|| table_rec.table_name
|| ' A, FILES b where A.objectid = B.id order by 1';
Also, make sure that this SELECT returns only 1 row, otherwise you'll end up with the TOO-MANY-ROWS error.
Other than that, I guess it should work.
[EDIT, regarding fear of TOO-MANY-ROWS]
Huh, I'd create a whole new PL/SQL BEGIN-END block, containing a loop which would do the job, displaying all rows returned by SELECT statement.
As I don't have your tables, I used HR's. Have a look:
SQL> DECLARE
2 vs_statement VARCHAR2 (1000);
3 my_var1 VARCHAR2(100);
4 my_var2 VARCHAR2(100);
5 CURSOR c1 IS
6 SELECT table_name
7 FROM all_tables
8 WHERE table_name LIKE Upper('%departments%');
9 BEGIN
10 FOR table_rec IN c1 LOOP
11 vs_statement := 'begin for cur_r in ( '
12 || Chr(10)
13 || 'select distinct a.department_id, a.department_name from '
14 || Chr(10)
15 || table_rec.table_name
16 ||
17 ' A, employees b where A.department_id = B.department_id order by 1) loop'
18 || Chr(10)
19 || ' dbms_output.put_line(cur_r.department_name); '
20 || Chr(10)
21 || ' end loop; end;';
22
23 EXECUTE IMMEDIATE vs_statement; -- into my_var1, my_var2;
24 END LOOP;
25 END;
26 /
Administration
Marketing
Purchasing
Human Resources
Shipping
IT
Public Relations
Sales
Executive
Finance
Accounting
PL/SQL procedure successfully completed.
SQL>
"Each select will return multiple records...Resultset should be printed to the user on a screen"
Open a ref cursor for each generated statement. Loop round that and display the values.
DECLARE
rc sys_refcursor;
vs_statement VARCHAR2 (1000);
my_var1 VARCHAR2(100);
my_var2 VARCHAR2(100);
CURSOR c1 IS
SELECT table_name
FROM all_tables
WHERE table_name LIKE Upper('redit_1%');
BEGIN
<< tab_loop >>
FOR table_rec IN c1 LOOP
vs_statement :=
'select a.userinfo, a.userstatus from '
|| table_rec.table_name
|| ' A, FILES b where A.objectid = B.id order by 1';
open rc for vs_statement;
dbms_output.put_line('records for '||table_rec.table_name);
<< rec_loop >>
loop
fetch rc into my_var1,my_var2;
exit when rc%notfound;
dbms_output.Put_line(my_var1
||' '
|| my_var2);
end loop rec_loop;
close rc;
END LOOP tab_loop;
END;
/

Resources