PL/SQL Procedure Use String Select Statement in for loop - sql

I am building a procedure, where I`m first creating a select statement and store it in an VARCAHR variable.
I now want to execute that query and store the whole result set in an variable to loop through it or use directly in a for loop.
I only find examples where the Select is hard written in the for loop definition.
How do i exchange the Select statement with my variable that holds my select statement?
for r IN (SELECT ... FROM ...)
loop
--do sth;
end loop;
how i want to use it :
statement := 'SELECT .... FROM ...';
for r IN (statement) -- HOW TO DO THIS
loop
--do sth;
end loop;

For a dynamic ref cursor, you need to define everything explicitly:
declare
sqlstring long := 'select 123 as id, ''demo'' as somevalue from dual where dummy = :b1';
resultset sys_refcursor;
type demo_rectype is record
( id integer
, somevalue varchar2(30) );
demorec demo_rectype;
begin
open resultset for sqlstring using 'X';
loop
fetch resultset into demorec;
exit when resultset%notfound;
dbms_output.put_line('id=' || demorec.id || ' somevalue=' || demorec.somevalue);
end loop;
close resultset;
end;
You can parse the cursor and figure out the column names and datatypes with DBMS_SQL. Example here: www.williamrobertson.net/documents/refcursor-to-csv.shtml

Related

Use Variabel for 'ORDER BY ' Declartion in a FOR IN LOOP Oralce

In ORACLE please.
Is it possible to have a variable in the 'ORDER BY' Statment?
So iam currenty creating a procedure in which I need to have a dynamic Order by.
Is there any way to do this ?
CREATE OR REPLACE PROCEDURE TEST1
vorder varchar(250);
...
vOrder := 'number';
FOR o IN (SELECT * FROM TABLENAME order by vOrder)
LOOP
-- Some stuff ---
END LOPP;
....
The only way to really have a dynamic order by clause instead of just having a list of predefined options as suggested by Alex, would be to use a dynamic sql cursor.
TYPE curType IS REF CURSOR;
vCur curType;
vRec tablename%ROWTYPE;
vOrd VARCHAR2(250) := 'column';
BEGIN
OPEN vCur FOR 'SELECT * FROM tablename ORDER BY '||vOrd';
LOOP
FETCH vCur INTO vRec;
EXIT WHEN cur%NOTFOUND;
END LOOP;
CLOSE vCur;
END;
/

Is there a way to loop through selected columns in plsql

I have a table TestTable with columns of col_test1, col_test2, col_test3 ...
and I want to create a loop that accesses each of these columns individually and find the max value and place it in the variable made in the declare block and simply dbms.out.put it.
Declare
my_array sys.dbms_debug_vc2coll := sys.dbms_debug_vc2coll('col_test1','col_test2','col_test2');
v_test number(8,0);
Begin
for r in my_array.first..my_array.last
loop
select max(my_array(r)) into v_test from TestTable;
dbms_output.put_line(v_test);
end loop;
End;
/
The output I get is just the string 'col_test1'which should be 50.
This is done through oracle SQL. Is there any way to achieve this?
You could use dynamic SQL for this
Declare
my_array sys.dbms_debug_vc2coll := sys.dbms_debug_vc2coll('col_test1','col_test2','col_test2');
v_test number(8,0);
Begin
for r in my_array.first..my_array.last
loop
execute immediate 'select max(' || my_array(r) || ') from TestTable'
into v_test;
dbms_output.put_line(v_test);
end loop;
End;
If you're going to resort to dynamic SQL, however, it would generally make more sense to build a single SQL statement that took that max of all three columns in one pass rather than potentially doing three separate table scans on the same table.

How to execute results of dbms_output.put_line

There is a table contains this kind of data: select to_char(sysdate,'day') from dual in a column. I want to get results of the every query that the table keeps.
My result set should be the result of select to_char(sysdate,'day') from dual query. So in this case it is a tuesday.
SO_SQL_BODY is Varchar2.
I wrote this code but it returns only table data.
CREATE or replace PROCEDURE a_proc
AS
CURSOR var_cur IS
select SO_SQL_BODY FROM SO_SUB_VARS group by SO_SQL_BODY;
var_t var_cur%ROWTYPE;
TYPE var_ntt IS TABLE OF var_t%TYPE;
var_names var_ntt;
BEGIN
OPEN var_cur;
FETCH var_cur BULK COLLECT INTO var_names;
CLOSE var_cur;
FOR indx IN 1..var_names.COUNT LOOP
DBMS_OUTPUT.PUT_LINE(var_names(indx).SO_SQL_BODY);
END LOOP;
END a_proc;
DECLARE
res varchar2(4000);
sql_str varchar2(1000);
BEGIN
FOR r IN
(select SO_SQL_BODY FROM SO_SUB_VARS WHERE SO_SQL_BODY IS NOT NULL
)
LOOP
sql_str := r.SO_SQL_BODY;
EXECUTE immediate sql_str INTO res;
dbms_output.put_line(sql_str);
dbms_output.put_line('***********************');
dbms_output.put_line(res);
dbms_output.put_line('***********************');
END LOOP;
END;
/
Try this - iterate to not null records - execute them and print the result.This script works supposing the fact that SO_SQL_BODY contains a query which projects only one column.Also if the projection is with more than two columns then try to use a refcursor and dbms_sql package
İf var_names(indx).SO_SQL_BODY output is a runnable sql text;
CREATE or replace PROCEDURE a_proc
AS
CURSOR var_cur IS
select SO_SQL_BODY FROM SO_SUB_VARS group by SO_SQL_BODY;
var_t var_cur%ROWTYPE;
TYPE var_ntt IS TABLE OF var_t%TYPE;
var_names var_ntt;
BEGIN
OPEN var_cur;
FETCH var_cur BULK COLLECT INTO var_names;
CLOSE var_cur;
FOR indx IN 1..var_names.COUNT LOOP
DBMS_OUTPUT.PUT_LINE(var_names(indx).SO_SQL_BODY);
EXECUTE IMMEDIATE var_names(indx).SO_SQL_BODY;
END LOOP;
END a_proc;
You don't need a full cursor for this example. An implicit one would make it a lot shorter.
create or replace procedure a_proc is
lReturnValue varchar2(250);
begin
for q in (select so_sql_body from so_sub_vars group by so_sql_body)
loop
execute immediate q.so_sql_body into lReturnValue;
dbms_output.put_line(lReturnValue);
end loop;
end a_proc;
You should add an exception handler that will care for cases where there is a bad SQL query in your table. Also note that executing querys saved in a database table is your entry point to SQL injection.

Call stored procedure for each Row with/without using a cursor

I want to a run a stored procedure for almost 1000 records (P_SHIPMENT_GID) in one go and below is the pseudo code.
DECLARE
P_SHIPMENT_GID VARCHAR2(200);
BEGIN
P_SHIPMENT_GID := NULL;
ULE_PKG_UNPLANNED_ICT_CALC.UNPLANNED_ICT_CALC(
P_SHIPMENT_GID => P_SHIPMENT_GID
);
END;
How can I achieve this with or without using cursors?
It is not all that clear what you want to do (where are the 1000 records from?) but here is a "pattern" I am pretty sure you can use :
BEGIN
FOR i IN (SELECT table_name, status FROM user_tables) LOOP
dbms_output.put_line('name : ' || i.table_name ||
' status : ' || i.status);
END LOOP;
END;
This creates a loop on an implicit cursor and allows you to use the returned rows/column in a readable way.
You can write this anonymous block for your requirement. Although its not clear from where you are storing your SHIPMENT_GID values which you wanted to pass to your procedure/pkg.
BEGIN
FOR rec IN ( --Assuming your shipmentid are stored in a table
SELECT SHIPMENT_GID
FROM Your_TABLE)
LOOP
ULE_PKG_UNPLANNED_ICT_CALC.UNPLANNED_ICT_CALC (
P_SHIPMENT_GID => rec.SHIPMENT_GID);
END LOOP;
END;

Dynamic Select from table at database link

I want to select data from a table in a remote database which I have its database link in a variable, how I can do that?
My query is something like this:
select `table_column` form any_table#:any_variable_1 where any_column= :any_variable_2;
Note:
any_variable_1 is a string variable contains the name of the database link
any_variable_2 is a string variable contains the string for filtering
* this code is to be executed in function in powerbuilder 8 or 9
* the database which I am connecting to is oracle 11 g
Try this:
DECLARE
l_var number(10); -- data type you are expecting from the table_column column
l_cursor sys_refcursor;
l_any_variable_1 varchar2(50) := 'YOUR_DBLINK_HERE';
l_any_variable_2 varchar2(50);
BEIGN
open l_cursor for 'select table_column from any_table# '||
l_any_variable_1 ||
' where any_column = :any_variable_2'
using l_any_variable_2;
loop
fetch l_cursor into l_var;
exit when l_cursor%NOTFOUND;
DBMS_OUTPUT.put_line(l_var);
end loop;
close l_cursor;
END;
string ls_sql
ls_sql="Select column_name from table_name#"+var_db_link_name+""+&
" where column_name='"+var_value+"' and another_column_name='"+another_var+"'"
DECLARE var_cursor DYNAMIC CURSOR FOR SQLSA ;
PREPARE SQLSA FROM :ls_sql ;
OPEN DYNAMIC var_cursor ;
FETCH var_cursor INTO :another_var ;//another_var holds the result of the cursor
CLOSE var_cursor;