PLSQL select query in BEGIN block - oracle

CREATE OR REPLACE PROCEDURE validate_date
AS
strABC DATE;
strDummy VARCHAR2(20);
CURSOR C_Example IS SELECT * from dummytable;
BEGIN
FOR R_Example IN C_RetNxWeek LOOP
strABC := R_RetNxWeek.something;
strDummy := R_RetNxWeek.something;
END LOOP;
IF (something < something) THEN
ELSE
strDummy:= SELECT * FROM sometable WHERE something = something; <-----alternative to do this?
END IF;
END validate_date;
I have a very basic store procedure template like above, i have a cursor that will select some record from a table, in the IF ELSE statement in BEGIN block, i wish to do a checking on a data by selecting a table, since i cannot put cursor in BEGIN block, how can i do that?

The select statement result cannot be stored as you stated,
it should be done via
It should use INTO Clause please refer https://docs.oracle.com/cd/B19306_01/appdev.102/b14261/returninginto_clause.htm

No need of an explicit cursor, use a CURSOR FOR LOOP. I don't know your requirement, since I think it could be done using plain SQL. However, if you really want to use PL/SQL, you can make use of BULK COLLECT and FORALL.
And regarding the SELECT, you need to use INTO clause in PL/SQL.
SQL> DECLARE
2 eno NUMBER;
3 STR_DUMMY VARCHAR2(20);
4 BEGIN
5 FOR i IN
6 (SELECT * FROM emp
7 )
8 LOOP
9 eno := i.empno;
10 dbms_output.put_line(eno);
11 END LOOP;
12 SELECT ENAME INTO STR_DUMMY FROM EMP WHERE EMPNO = 7788;
13 dbms_output.put_line(STR_DUMMY);
14 END;
15 /
7369
7499
7521
7566
7654
7698
7782
7788
7839
7844
7876
7900
7902
7934
SCOTT
PL/SQL procedure successfully completed.
SQL>

Related

How to pass multiple parameters in oracle stored procedure

i am trying to execute like exec print_emp(1010,1111) but it will showing error.
create or replace
procedure print_emp(
P_empno NUMBER
)
IS
begin
for c in ( SELECT *
from emp
where empno in p_empno)
loop
dbms_output.put_line( c.empno||' '||c.ename||' '||c.job||' '||c.sal);
end loop;
END;
You'll need to create a type that is a collection of numbers, and then a procedure that accepts that collection.
Rather than use the IN operator, you should use MEMBER OF to test whether a scalar value is in a collection.
create or replace type tab_number is table of number
/
create or replace procedure print_nums
(p_nums in tab_number)
is
cursor c_main is
select column_value
from table(p_nums)
order by 1;
begin
for r_main in c_main loop
dbms_output.put_line(r_main.column_value);
end loop;
--
if 33 member of p_nums then
dbms_output.put_line('In the list');
end if;
end;
/
exec print_nums(tab_number(10,20,50));
exec print_nums(tab_number(10,20,33));
Obviously, if all parameters you'd like to pass represent the same column value, you can't just list them as if they were two different parameters. If that was the case, procedure should actually name them all, e.g.
create procedure print_emp(par_emp_1 in number, par_emp_2 in number)
but - what if there are 3 or 4 EMPNOs you'd like to pass? You can't modify the procedure every time (not just while declaring it, but also in SELECT statements, as you'd have to add new parameters there as well).
Therefore, one option might be this (as far as I understood the question):
one parameter, whose datatype is varchar2
it means that you'd have to enclose list of EMPNOs into single quotes and separate them with the same separator every time; let it be a comma , sign
cursor's query would contain a subquery (lines #6 - 9) which splits that comma-separated values list of EMPNO values into rows
the rest is simple
Here you go:
SQL> create or replace procedure print_emp(par_empno in varchar2)
2 is
3 begin
4 for c in (select *
5 from emp
6 where empno in (select to_number(regexp_substr(par_empno, '[^,]+', 1, level))
7 from dual
8 connect by level <= regexp_count(par_empno, ',') + 1
9 )
10 )
11 loop
12 dbms_output.put_line(c.empno||' '||c.ename||' '||c.job||' '||c.sal);
13 end loop;
14 end;
15 /
Procedure created.
Scott's EMP sample table:
SQL> select * from emp where deptno = 20;
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- ---------- --------- ---------- ------------------- ---------- ---------- ----------
7369 SMITH CLERK 7902 17.12.1980 00:00:00 1000 20
7566 JONES MANAGER 7839 02.04.1981 00:00:00 2975 20
7788 SCOTT ANALYST 7566 09.12.1982 00:00:00 3000 20
7876 ADAMS CLERK 7788 12.01.1983 00:00:00 1100 20
7902 FORD ANALYST 7566 03.12.1981 00:00:00 3000 20
Testing:
SQL> set serveroutput on
SQL> exec print_emp('7369,7566,7788');
7566 JONES MANAGER 2975
7788 SCOTT ANALYST 3000
7369 SMITH CLERK 1000
PL/SQL procedure successfully completed.
SQL>

Oracle PL/SQL collect values from a loop into a cursor

I have a PL/SQL TABLE TYPE result set that contains document ids.
I can loop over the result set without a problem, but the issue is that I have to return a sys_refcursor from the function, but I am unable to collect the values from the loop into the cursor.
TYPE table_typ IS TABLE OF DOCUMENT_QUEUE.ENV_ID%TYPE INDEX BY PLS_INTEGER;
FUNCTION GET_DOCS()
RETURN SYS_REFCURSOR
IS
LS_CUR SYS_REFCURSOR;
LR_UPDATED_ROWS table_typ;
BEGIN
UPDATE DOCUMENT_QUEUE DQ
...
RETURNING DQ.ENV_ID BULK COLLECT INTO LR_UPDATED_ROWS;
-- Need to collect all of the following rows into the cursor
FOR indx IN NVL (LR_UPDATED_ROWS.FIRST, 0) .. NVL (LR_UPDATED_ROWS.LAST, -1)
LOOP
SELECT * FROM DOCUMENT_QUEUE DQ WHERE DQ.ENV_ID = LR_UPDATED_ROWS(indx);
END LOOP;
RETURN LS_CUR;
END GET_DOCS;
All help and hints are welcome.
FOR indx IN NVL (LR_UPDATED_ROWS.FIRST, 0) .. NVL (LR_UPDATED_ROWS.LAST, -1)
LOOP
SELECT * FROM DOCUMENT_QUEUE DQ WHERE DQ.ENV_ID = LR_UPDATED_ROWS(indx);
END LOOP;
RETURN LS_CUR;
You do not need the cursor FOR LOOP. You could use OPEN CURSOR FOR statement and return a SYS_REFCURSOR.
For example,
OPEN LS_CUR FOR SELECT * FROM DOCUMENT_QUEUE DQ
WHERE DQ.ENV_ID IN (SELECT * FROM TABLE(LR_UPDATED_ROWS));
RETURN LS_CUR;
or,
OPEN LS_CUR FOR SELECT * FROM DOCUMENT_QUEUE DQ
WHERE DQ.ENV_ID MEMBER OF LR_UPDATED_ROWS;
RETURN LS_CUR;
However, in order to do that, you must CREATE the type at SQL level not at PL/SQL level. Else, you would receive PLS-00642: local collection types not allowed in SQL statements.
A small demo:
Create the type at SQL level:
SQL> CREATE OR REPLACE TYPE table_typ AS TABLE OF NUMBER
2 /
Type created.
Let's get the output in SQL*Plus using a refcursor:
Using MEMBER OF syntax:
SQL> variable r refcursor
SQL> DECLARE
2 l_typ table_typ;
3 TYPE numbers IS TABLE OF NUMBER;
4 n numbers;
5 BEGIN
6 SELECT empno BULK COLLECT INTO l_typ FROM emp;
7 OPEN :r FOR SELECT empno,
8 ename FROM emp WHERE empno member OF l_typ;
9 END;
10 /
PL/SQL procedure successfully completed.
SQL> print r
EMPNO ENAME
---------- ----------
7369 SMITH
7499 ALLEN
7521 WARD
7566 JONES
7654 MARTIN
7698 BLAKE
7782 CLARK
7788 SCOTT
7839 KING
7844 TURNER
7876 ADAMS
7900 JAMES
7902 FORD
7934 MILLER
14 rows selected.
Using TABLE function:
SQL> variable r refcursor
SQL> DECLARE
2 l_typ table_typ;
3 TYPE numbers IS TABLE OF NUMBER;
4 n numbers;
5 BEGIN
6 SELECT empno BULK COLLECT INTO l_typ FROM emp;
7 OPEN :r FOR SELECT empno,
8 ename FROM emp WHERE empno IN (SELECT * from TABLE(l_typ));
9 END;
10 /
PL/SQL procedure successfully completed.
SQL> print r
EMPNO ENAME
---------- ----------
7369 SMITH
7499 ALLEN
7521 WARD
7566 JONES
7654 MARTIN
7698 BLAKE
7782 CLARK
7788 SCOTT
7839 KING
7844 TURNER
7876 ADAMS
7900 JAMES
7902 FORD
7934 MILLER
14 rows selected.
For the mentioned requirement i have mentioned below a snippet which will help to fetch all the rows into ref cursor for every rowid. Let me know if this helps.
CREATE OR REPLACE TYPE table_typ
IS
TABLE OF DOCUMENT_QUEUE.ENV_ID%TYPE INDEX BY PLS_INTEGER;
CREATE OR REPLACE FUNCTION GET_DOCS
RETURN SYS_REFCURSOR
IS
LS_CUR SYS_REFCURSOR;
LR_UPDATED_ROWS table_typ;
lv_rows_lst VARCHAR2(32676);
BEGIN
SELECT <COL1> BULK COLLECT INTO LR_UPDATED_ROWS FROM <TABLE_NAME>;
FOR I IN LR_UPDATED_ROWS.FIRST..LR_UPDATED_ROWS.LAST
LOOP
lv_rows_lst:=lv_rows_lst||','||LR_UPDATED_ROWS(I);
END LOOP;
lv_rows_lst:=SUBSTR(lv_rows_lst,2,LENGTH(lv_rows_lst));
OPEN LS_CUR FOR 'SELECT * FROM DOCUMENT_QUEUE DQ WHERE DQ.ENV_ID IN ('||lv_rows_lst||')';
RETURN LS_CUR;
END GET_DOCS;

Oracle PLSQL BULK Collect and For Loop

I have written the following oracle procedure to fetch data in bulk and process it in blocks. I am using the bulk collect option with limit to fetch the data. But inside for loop i am not able to retrieve the ORD_ID. I am trying to output the ORD_ID using
DBMS_OUTPUT.put_line(l_orders(indx));
But getting compilation error "wrong number or type of arguments in call to 'PUT_LINE'"
create or replace PROCEDURE TESTPROC AS
CURSOR order_id_cur IS SELECT ORD_ID FROM orders ORDER BY ORD_ID ASC;
l_order_id VARCHAR2(100);
TYPE orders_aat IS TABLE OF order_id_cur%ROWTYPE;
l_orders orders_aat;
limit_in NUMBER :=10;
batch_in NUMBER :=0;
BEGIN
OPEN order_id_cur;
LOOP
FETCH order_id_cur
BULK COLLECT INTO l_orders LIMIT limit_in;
DBMS_OUTPUT.put_line('Batch-----'||batch_in);
FOR indx IN 1 .. l_orders.COUNT
LOOP
DBMS_OUTPUT.put_line(indx);
DBMS_OUTPUT.put_line(l_orders(indx));
END LOOP;
EXIT WHEN l_orders.COUNT < limit_in;
batch_in := batch_in+1;
END LOOP;
CLOSE order_id_cur;
END TESTPROC;
How can i get the values of ORD_ID inside the for loop.
Do it like this -
DBMS_OUTPUT.put_line(l_orders(indx).ORD_ID);
For example,
SQL> DECLARE
2 type t
3 IS
4 TABLE OF emp%rowtype;
5 a t;
6 BEGIN
7 SELECT * BULK COLLECT INTO a FROM emp;
8 FOR i IN 1..a.count
9 LOOP
10 dbms_output.put_line (a(i).ename);
11 END LOOP;
12 END;
13 /
SMITH
ALLEN
WARD
JONES
MARTIN
BLAKE
CLARK
SCOTT
KING
TURNER
ADAMS
JAMES
FORD
MILLER
PL/SQL procedure successfully completed.
SQL>
you can also make loop directly to cursor like below
FOR recc in order_id_cur
LOOP
DBMS_OUTPUT.put_line(recc.ORD_ID );
END LOOP;

Passing cursor record to a function

I have a stored procedure. I want to call a function from it. Want to pass the retrieved cursor record to the function. how can i pass the retrieved cursor record as function argument and how can i access it inside the function? How do i declare the function?
CREATE OR REPLACE PROCEDURE service__update as
cursor c_getData is
select *
from service_1
where status=5 ;
begin
dbms_output.enable(null);
for rec in c_getData loop
function(rec)
Assuming that you really want a function (which implies that you want to return a value) rather than a procedure (which does not return a value) and assuming that your cursor really is selecting every column from a single table, you can declare a function that takes an anchored %ROWTYPE
SQL> create function get_empno( p_rec in emp%rowtype )
2 return number
3 is
4 begin
5 return p_rec.empno;
6 end;
7 /
Function created.
and then call that function from your procedure
SQL> declare
2 l_empno emp.empno%type;
3 begin
4 for i in (select * from emp)
5 loop
6 l_empno := get_empno( i );
7 dbms_output.put_line( l_empno );
8 end loop;
9 end;
10 /
7369
7499
7521
7566
7654
7698
7782
7788
7839
7844
7876
7900
7902
7934
PL/SQL procedure successfully completed.

Get resultset from oracle stored procedure

I'm working on converting a stored procedure from SQL server to Oracle.
This stored procedure provides a direct resultset. I mean that if you call the stored procedure in eg Management Studio you directly obtain the resultset.
By converting to Oracle I walk against the problem that I in Oracle will not display the resultset
I searched on the Internet and have seen that the stored procedure should yield a REF CURSOR, but I still walk with the problem to write a little piece of code to obtain the resultset en process that.
Pseudo Code:
Call stored procedure and obtain cursor
Do something with that cursor so that my resultset appears
Someone an idea?
In SQL Plus:
SQL> create procedure myproc (prc out sys_refcursor)
2 is
3 begin
4 open prc for select * from emp;
5 end;
6 /
Procedure created.
SQL> var rc refcursor
SQL> execute myproc(:rc)
PL/SQL procedure successfully completed.
SQL> print rc
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- ---------- --------- ---------- ----------- ---------- ---------- ----------
7839 KING PRESIDENT 17-NOV-1981 4999 10
7698 BLAKE MANAGER 7839 01-MAY-1981 2849 30
7782 CLARKE MANAGER 7839 09-JUN-1981 2449 10
7566 JONES MANAGER 7839 02-APR-1981 2974 20
7788 SCOTT ANALYST 7566 09-DEC-1982 2999 20
7902 FORD ANALYST 7566 03-DEC-1981 2999 20
7369 SMITHY CLERK 7902 17-DEC-1980 9988 11 20
7499 ALLEN SALESMAN 7698 20-FEB-1981 1599 3009 30
7521 WARDS SALESMAN 7698 22-FEB-1981 1249 551 30
7654 MARTIN SALESMAN 7698 28-SEP-1981 1249 1400 30
7844 TURNER SALESMAN 7698 08-SEP-1981 1499 0 30
7876 ADAMS CLERK 7788 12-JAN-1983 1099 20
7900 JAMES CLERK 7698 03-DEC-1981 949 30
7934 MILLER CLERK 7782 23-JAN-1982 1299 10
6668 Umberto CLERK 7566 11-JUN-2009 19999 0 10
9567 ALLBRIGHT ANALYST 7788 02-JUN-2009 76999 24 10
Oracle is not sql server. Try the following in SQL Developer
variable rc refcursor;
exec testproc(:rc2);
print rc2
My solution was to create a pipelined function. The advantages are that the query can be a single line:
select * from table(yourfunction(param1, param2));
You can join your results to other tables or filter or sort them as you please..
the results appear as regular query results so you can easily manipulate them.
To define the function you would need to do something like the following:
-- Declare the record columns
TYPE your_record IS RECORD(
my_col1 VARCHAR2(50),
my_col2 varchar2(4000)
);
TYPE your_results IS TABLE OF your_record;
-- Declare the function
function yourfunction(a_Param1 varchar2, a_Param2 varchar2)
return your_results pipelined is
rt your_results;
begin
-- Your query to load the table type
select s.col1,s.col2
bulk collect into rt
from your_table s
where lower(s.col1) like lower('%'||a_Param1||'%');
-- Stuff the results into the pipeline..
if rt.count > 0 then
for i in rt.FIRST .. rt.LAST loop
pipe row (rt(i));
end loop;
end if;
-- Add more results as you please....
return;
end find;
And as mentioned above, all you would do to view your results is:
select * from table(yourfunction(param1, param2)) t order by t.my_col1;
Hi I know this was asked a while ago but I've just figured this out and it might help someone else. Not sure if this is exactly what you're looking for but this is how I call a stored proc and view the output using SQL Developer.
In SQL Developer when viewing the proc, right click and choose 'Run' or select Ctrl+F11 to bring up the Run PL/SQL window. This creates a template with the input and output params which you need to modify. My proc returns a sys_refcursor. The tricky part for me was declaring a row type that is exactly equivalent to the select stmt / sys_refcursor being returned by the proc:
DECLARE
P_CAE_SEC_ID_N NUMBER;
P_FM_SEC_CODE_C VARCHAR2(200);
P_PAGE_INDEX NUMBER;
P_PAGE_SIZE NUMBER;
v_Return sys_refcursor;
type t_row is record (CAE_SEC_ID NUMBER,FM_SEC_CODE VARCHAR2(7),rownum number, v_total_count number);
v_rec t_row;
BEGIN
P_CAE_SEC_ID_N := NULL;
P_FM_SEC_CODE_C := NULL;
P_PAGE_INDEX := 0;
P_PAGE_SIZE := 25;
CAE_FOF_SECURITY_PKG.GET_LIST_FOF_SECURITY(
P_CAE_SEC_ID_N => P_CAE_SEC_ID_N,
P_FM_SEC_CODE_C => P_FM_SEC_CODE_C,
P_PAGE_INDEX => P_PAGE_INDEX,
P_PAGE_SIZE => P_PAGE_SIZE,
P_FOF_SEC_REFCUR => v_Return
);
-- Modify the code to output the variable
-- DBMS_OUTPUT.PUT_LINE('P_FOF_SEC_REFCUR = ');
loop
fetch v_Return into v_rec;
exit when v_Return%notfound;
DBMS_OUTPUT.PUT_LINE('sec_id = ' || v_rec.CAE_SEC_ID || 'sec code = ' ||v_rec.FM_SEC_CODE);
end loop;
END;
In SQL Plus:
SQL> var r refcursor
SQL> set autoprint on
SQL> exec :r := function_returning_refcursor();
Replace the last line with a call to your procedure / function and the contents of the refcursor will be displayed
FYI as of Oracle 12c, you can do this:
CREATE OR REPLACE PROCEDURE testproc(n number)
AS
cur SYS_REFCURSOR;
BEGIN
OPEN cur FOR SELECT object_id,object_name from all_objects where rownum < n;
DBMS_SQL.RETURN_RESULT(cur);
END;
/
EXEC testproc(3);
OBJECT_ID OBJECT_NAME
---------- ------------
100 ORA$BASE
116 DUAL
This was supposed to get closer to other databases, and ease migrations.
But it's not perfect to me, for instance SQL developer won't display it nicely as a normal SELECT.
I prefer the output of pipeline functions, but they need more boilerplate to code.
more info:
https://oracle-base.com/articles/12c/implicit-statement-results-12cr1
CREATE OR REPLACE PROCEDURE SP_Invoices(p_nameClient IN CHAR)
AS
BEGIN
FOR c_invoice IN
(
SELECT CodeInvoice, NameClient FROM Invoice
WHERE NameClient = p_nameClient
)
LOOP
dbms_output.put_line('Code Invoice: ' || c_invoice.CodeInvoice);
dbms_output.put_line('Name Client : ' || c_invoice.NameClient );
END LOOP;
END;
Executing in SQL Developer:
BEGIN
SP_Invoices('Perico de los palotes');
END;
-- Or:
EXEC SP_Invoices('Perico de los palotes');
Output:
> Code Invoice: 1
> Name Client : Perico de los palotes
> Code Invoice: 2
> Name Client : Perico de los palotes

Resources