ORA-01403: no data found - sql

I've a SQL query where if output is NULL it should not send warning .
l_sup_id NUMBER;
begin
SELECT per_all_assignments_f.supervisor_id
INTO l_sup_id
FROM per_all_assignments_f
WHERE person_id = p_person_id
AND trunc (sysdate) BETWEEN effective_start_date
AND effective_end_date
AND primary_flag = 'Y';
elsif (p_person_type = 'APPRAISER' AND l_sup_id IS NOT NULL) then
hr_utility.set_message(801, 'HR_51888_APR_APPRAISER_NULL');
hr_utility.raise_error;
end if;
Whenever l_sup_id is null according to logic
hr_utility.set_message(801, 'HR_51888_APR_APPRAISER_NULL');
should not be executed
But whenever l_sup_id is null I am getting
ORA-01403: no data found
error in logs
If l_sup_id is not null application working is fine

From documentation,
NO_DATA_FOUND
A SELECT INTO statement returns no rows, or your program references a
deleted element in a nested table or an uninitialized element in an
index-by table.
In your PL/SQL code, the SELECT .. INTO statement returns no rows, thus it raises NO_DATA_FOUND error. It never goes to the next line, i.e. your IF-ELSE construct.
If you want to continue the operation, then you need to handle the EXCEPTION gracefully.
For example,
SQL> SET serveroutput ON
SQL>
SQL> DECLARE
2 o_ename emp.ename%TYPE;
3 i_empno emp.empno%TYPE;
4 BEGIN
5 SELECT ename INTO o_ename FROM emp WHERE empno = i_empno;
6 -- Handle no_data_found
7 EXCEPTION
8 WHEN no_data_found THEN
9 -- do something
10 dbms_output.put_line('No records found for employee no '|| i_empno);
11 END;
12 /
No records found for employee no
PL/SQL procedure successfully completed.
SQL>

As the error suggests its pointing to NO DATA for the condition, to handle that you need to use "Exception Handling", Please see the code for the changes,
declare
l_sup_id NUMBER;
begin
SELECT per_all_assignments_f.supervisor_id
INTO l_sup_id
FROM per_all_assignments_f
WHERE person_id = p_person_id
AND trunc (sysdate) BETWEEN effective_start_date
AND effective_end_date
AND primary_flag = 'Y';
elsif (p_person_type = 'APPRAISER' AND l_sup_id IS NOT NULL) then
hr_utility.set_message(801, 'HR_51888_APR_APPRAISER_NULL');
hr_utility.raise_error;
end if;
--changes start
exception
when no_Data_found then
dbms_output.put_line('No data exists for lsup '|| l_sup_id)
--changes end
end;
Edit:
SQL> SELECT * FROM TESTEMP WHERE EMPNO=6677;
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- ---------- --------- ---------- --------- ---------- ---------- ----------
6677 JUPITER CLERK 7902 17-DEC-80 800 20
SQL>
SQL> declare
2 l_count number;
3 begin
4 select comm into l_count from testemp where empno=6677 ;
5 DBMS_OUTPUT.PUT_LINE('lcount is'||l_count);
6 if (l_count IS NULL) then
7 dbms_output.put_line('no data');
8 else
9 dbms_output.put_line('data');
10 end if;
11 end;
12 /
lcount is
no data
PL/SQL procedure successfully completed.
Your condition wont go into the if at all if you compare to NULL or how ever you want to use it according to your specification

Thank you for all the responses.
Instead of plain sql I created the following cursor
cursor csr_supervisor_id
is
SELECT supervisor_id
FROM per_all_assignments_f
WHERE person_id = p_person_id
AND trunc (sysdate) BETWEEN effective_start_date
AND effective_end_date
AND primary_flag = 'Y';
and fetched it in l_sup_id
open csr_supervisor_id;
fetch csr_supervisor_id into l_sup_id;
Now no data received error is not coming.

Related

Why do I get the error message that my cursor is invalid?

SET SERVEROUTPUT ON
SET VERIFY OFF
DECLARE
v_deptno empcopy.deptno%TYPE;
v_empno empcopy.empno%TYPE;
v_sal empcopy.sal%TYPE;
v_bonus NUMBER(7,2);
CURSOR emp_cursor IS
SELECT deptno, empno, sal
FROM empcopy
WHERE v_deptno < 25;
BEGIN
FETCH emp_cursor INTO v_deptno, v_empno, v_sal;
FOR r_emp in emp_cursor LOOP
IF v_sal < 3000 THEN
v_bonus := v_sal * 1.1;
ELSE
v_bonus := v_sal * 1.12;
v_deptno := v_deptno;
v_empno := v_empno;
v_sal := v_sal;
END IF;
INSERT INTO emp3
VALUES(v_empno, v_deptno, v_sal);
FETCH emp_cursor INTO v_deptno, v_empno, v_sal;
END LOOP;
CLOSE emp_cursor;
DBMS_OUTPUT.PUT_LINE(v_deptno || v_empno || v_bonus);
END;
/
SET SERVEROUTPUT OFF
SET VERIFY ON
SQL> # emp3
DECLARE
*
ERROR at line 1:
ORA-01001: invalid cursor
ORA-06512: at line 11
I was wondering why it says I have an invalid cursor. I have tried to change the name of the value that has to be < 25 but it didn't work.
Code you wrote is full of errors (you already know that), I don't know whether I'll catch them all, but I'll try:
cursor selects data whose v_deptno < 25. But, v_deptno looks like a locally declared variable (the first one you declared), so - unless there's a column whose name is v_deptno, it'll fail.
besides, hardcoding deptno value to "25" doesn't scale at all. I'd suggest you to switch to a stored procedure which accepts department number as a parameter
the first executable line is FETCH, but it should have been OPEN (if you choose to do everything
manually:
declare a cursor
declare cursor variable (or separate variables, as you did)
open the cursor
loop
fetch from the cursor
exit when cursor%notfound
do something
end loop
close cursor
or, better, using cursor FOR loop where Oracle does all the dirty job for you:
FOR cursor in (SELECT statement) LOOP
do something
end loop
when you're checking salary (in IF), ELSE is ... more than strange. What's the purpose of v_deptno := v_deptno; (as well as other 3 variables you set to what they were)?
INSERT statement: it lacks column list you're inserting into. This is not an error (might fail if you did it wrong), but - it is confusing, especially when there are many columns involved).
but, you're inserting V_SAL. OK. Why did you compute V_BONUS, then? You never, ever used it (except in DBMS_OUTPUT, but that just displays the value, never does anything with it as far as data in the database is concerned)
OK, now my attempt, if I may.
First, code you wrote, fixed (I'm inserting V_BONUS value):
SQL> declare
2 v_bonus number;
3 begin
4 for cur_r in (select deptno, empno, sal
5 from empcopy
6 where deptno < 25
7 )
8 loop
9 if cur_r.sal < 3000 then
10 v_bonus := cur_r.sal * 1.1;
11 else
12 v_bonus := cur_r.sal * 1.12;
13 end if;
14
15 insert into emp3 (empno, deptno, sal)
16 values (cur_r.empno, cur_r.deptno, v_bonus);
17 end loop;
18 end;
19 /
PL/SQL procedure successfully completed.
SQL> select * From emp3;
EMPNO DEPTNO SAL
---------- ---------- ----------
7369 20 1100
7566 20 3272,5
7782 10 2695
7788 20 3360
7839 10 5600
7876 20 1210
7902 20 3360
7934 10 1430
8 rows selected.
SQL>
However, that can be done with a single INSERT statement at the SQL layer, you don't need PL/SQL at all. So, unless you're just practicing your PL/SQL skills, I'd suggest you to use this option:
SQL> rollback;
Rollback complete.
SQL> insert into emp3 (empno, deptno, sal)
2 select empno,
3 deptno,
4 case when sal < 3000 then sal * 1.1
5 else sal * 1.12
6 end
7 from empcopy
8 where deptno < 25;
8 rows created.
SQL> select * From emp3;
EMPNO DEPTNO SAL
---------- ---------- ----------
7369 20 1100
7566 20 3272,5
7782 10 2695
7788 20 3360
7839 10 5600
7876 20 1210
7902 20 3360
7934 10 1430
8 rows selected.
SQL>
Finally, a stored procedure option I suggested at the beginning; instead of < in the where clause, use =.
SQL> create or replace procedure p_bonus (par_deptno in empcopy.deptno%type)
2 is
3 v_bonus number;
4 begin
5 for cur_r in (select deptno, empno, sal
6 from empcopy
7 where deptno = par_deptno --> "=" instead of "<"
8 )
9 loop
10 if cur_r.sal < 3000 then
11 v_bonus := cur_r.sal * 1.1;
12 else
13 v_bonus := cur_r.sal * 1.12;
14 end if;
15
16 insert into emp3 (empno, deptno, sal)
17 values (cur_r.empno, cur_r.deptno, v_bonus);
18 end loop;
19 end;
20 /
Procedure created.
SQL> begin
2 p_bonus (par_deptno => 25);
3 end;
4 /
PL/SQL procedure successfully completed.
The table EMP3 apparently has fewer columns than the INSERT command provides data for (4).
Check the definition of that EMP3 table and make sure the table and the insert command can be matched.
After the comments/discussion, this is the code is a more readable form (I added indentation):
SET SERVEROUTPUT ON
SET VERIFY OFF
DECLARE
v_deptno empcopy.deptno%TYPE;
v_empno empcopy.empno%TYPE;
v_sal empcopy.sal%TYPE;
v_bonus NUMBER(7,2);
CURSOR emp_cursor IS
SELECT deptno, empno, sal
FROM empcopy
WHERE v_deptno < 25;
BEGIN
FETCH emp_cursor INTO v_deptno, v_empno, v_sal;
FOR r_emp in emp_cursor LOOP
IF v_sal < 3000 THEN
v_bonus := v_sal * 1.1;
ELSE
v_bonus := v_sal * 1.12;
v_deptno := v_deptno;
v_empno := v_empno;
v_sal := v_sal;
END IF;
INSERT INTO emp3
VALUES(v_empno, v_deptno, v_sal);
FETCH emp_cursor INTO v_deptno, v_empno, v_sal;
END LOOP;
CLOSE emp_cursor;
DBMS_OUTPUT.PUT_LINE(v_deptno || v_empno || v_bonus);
END;
/
SET SERVEROUTPUT OFF
SET VERIFY ON
What this code appears to be doing is:
go over every "employee" record in table EMPCOPY
for each of those records, check if the salary is lower than 3000 and calculate the bonus by multiplying salary by 1.1 if it is
if the salary is not lower than 3000, v_bonus is calculated by 1.12
after this, the new values should be INSERTed into table EMP3
finally, the values of the very last inserted record are printed out.
First off: the poor folks that make less than 3000 also only get 110% bonus while the already better off employees get 2% more on top?
I'm aware that this is common practice, but I'd advocate aiming for a better, fairer world - at least in simple coding examples like this.
Now to the code.
What this code should do, does not require the use of cursors at all. In fact, it is not a good practice in this case.
Instead, just use plain SQL to achieve the desired effect:
INSERT INTO EMP3
(empno, deptno, sal, bonus)
(SELECT
empno, deptno, sal
, case
when sal < 3000 then sal * 1.1
else sal * 1.12
end as bonus
FROM
empcopy
WHERE
deptno < 25);
The caveat here is that the target table EMPCOPY needs to have a column for BONUS. That this column is missing was likely the cause for the original issue.
Also worth noting that this approach does not print out anything.
If that is a requirement for the solution, then this should be done after the INSERT (a simple FOR LOOP over the target table should do).
I hope that helps.

Change condition in where clause based on a boolean (Oracle)

CREATE OR REPLACE TRIGGER "EVGENIJ_BOBROVICH"."FIX_UPD_LIMITS"
BEFORE UPDATE OR DELETE ON "EVGENIJ_BOBROVICH"."MAP_CALCULATION_SHOP_LIMITS"
FOR EACH ROW
DECLARE
is_deleted_dependant VARCHAR2(1 BYTE);
is_editable_dependant VARCHAR2(1 BYTE);
OPERATION BOOLEAN := UPDATING OR DELETING;
BEGIN
SELECT IS_DELETE, IS_EDITABLE INTO is_deleted_dependant, is_editable_dependant
FROM MAP_CALCULATION MC INNER JOIN map_calculation_group MG ON MC.ID_CALC = MG.ID_CALC
WHERE MG.ID_CALC = MC.ID_CALC AND MG.ID_GROUP =
(CASE WHEN UPDATING THEN :new.id_group WHEN DELETING THEN :old.id_group)
...
END;
/
How to change these checks in the where clause based on the updating and deleting flags?
No, it won't work. A simple example:
SQL> create table test as select * From dept;
Table created.
SQL> create or replace trigger trg_test
2 before update or delete on test
3 for each row
4 declare
5 l_cnt number;
6 begin
7 select count(*) into l_cnt
8 from emp where deptno = case when updating then :new.deptno
9 when deleting then :old.deptno
10 end;
11 end;
12 /
Warning: Trigger created with compilation errors.
SQL> show err
Errors for TRIGGER TRG_TEST:
LINE/COL ERROR
-------- -----------------------------------------------------------------
4/3 PL/SQL: SQL Statement ignored
5/46 PL/SQL: ORA-00920: invalid relational operator
SQL>
Error is here:
8 from emp where deptno = case when updating then :new.deptno
^^^^
Which means that you'll have to do something like this:
SQL> create or replace trigger trg_test
2 before update or delete on test
3 for each row
4 declare
5 l_deptno test.deptno%type;
6 l_cnt number;
7 begin
8 if updating then
9 l_deptno := :new.deptno;
10 elsif deleting then
11 l_deptno := :old.deptno;
12 end if;
13
14 select count(*) into l_cnt
15 from emp where deptno = l_deptno;
16 end;
17 /
Trigger created.
SQL>

pass correct format of date value returned from another function

I'm using V_SQL as parameter which stores SQL query as string and takes DATE input which is returned from another function.
Function which is returning date value:
----------------------------------------
FUNCTION RETURN_DATE(V_D DATE) RETURN DATE IS
IS_BUS CHAR(1);
V_CNT NUMBER(5);
V_DT DATE;
BEGIN
V_DT :=V_D;
WHILE IS_BUSINESS_DAY(V_DT) = 'N'
LOOP
V_DT := V_DT - 1;
END LOOP;
IF IS_BUSINESS_DAY(V_DT) = 'Y' THEN
V_DT := V_DT - 1;
END IF;
RETURN V_DT;
END RETURN_DATE;
V_SQL := 'SELECT A.ACCOUNT_TYPE, B.FIN_ELEM, A.ORG_UNIT_ID, A.GL_ACCOUNT_ID, B.CMN_COA_ID, B.PROD1, B.PROD2, B.PROD3, ' ||
'SUM(CURRENT_BAL) AS CB_SUM, SUM(AVG_BAL) AS AB_SUM, B.FLAG1 FROM DAILYGL_TEST A, AL_LOOKUP B '||
'WHERE A.GL_ACCOUNT_ID = B.GL_ACCT AND A.AS_OF_DATE = '||
**RETURN_DATE(V_RUN_DATE)** ||
' AND ROWNUM <=15 GROUP BY A.ACCOUNT_TYPE, B.FIN_ELEM, A.ORG_UNIT_ID, A.GL_ACCOUNT_ID,B.CMN_COA_ID, B.PROD1, B.PROD2, B.PROD3, A.AS_OF_DATE, B.FLAG1';
I am getting date returned as '29-AUG-2019' and when it is being supplied to this V_SQL query, it is throwing 'AUG not valid identifier issue'. Also, Date in AS_OF_DATE column is in MM/DD/YYYY format such 09/02/2019 for 02-SEP-2019.
Could you please help me in editing, formatting this code properly so this error can be removed. Let me know what I should change in RETURN_DATE(V_RUN_DATE) while supplying it to V_SQL.
Thanks in advance!
The way you are calling the function is wrong; it shouldn't be concatenated to the main query, but embedded into it. Have a look at this simplified example (line #5 is what you should pay attention to).
SQL> create or replace function return_date (v_d in varchar2)
2 return date
3 is
4 begin
5 return to_date(v_d, 'dd.mm.yyyy');
6 end;
7 /
Function created.
SQL> select ename, hiredate from emp where rownum = 1;
ENAME HIREDATE
---------- -------------------
SMITH 17.12.1980 00:00:00
SQL> declare
2 v_sql varchar2(500);
3 l_row emp%rowtype;
4 begin
5 v_sql := q'[select * from emp where hiredate = return_date('&v_run_date') ]' ||
6 ' and rownum = 1';
7 dbms_output.put_Line(v_sql);
8 execute immediate v_sql into l_row;
9 dbms_output.put_line(l_row.ename);
10 end;
11 /
Enter value for v_run_date: 17.12.1980
select * from emp where hiredate = return_date('17.12.1980') and rownum = 1
SMITH
PL/SQL procedure successfully completed.
SQL>

Update trigger not updating timestamp(update operation) in column

Trigger not working while updating the table column with trigger enabled on table...
CREATE OR REPLACE Trigger TR_FinlStatAssetDesignation_U
BEFORE Update
on FINLSTATASSETDESIGNATION FOR EACH ROW
DECLARE
v_AtDateTime TIMESTAMP(3);
v_LogOperation NUMBER(3,0);
v_UserName VARCHAR2(255);
v_AppName VARCHAR2(255);
SWV_error NUMBER(10,0) DEFAULT 0;
BEGIN
begin
select USERNAME INTO v_UserName FROM v$session WHERE (audsid = SYS_CONTEXT('userenv','sessionid')) AND ROWNUM <=1;
EXCEPTION
WHEN NO_DATA_FOUND THEN
NULL;
end;
SELECT program INTO v_AppName FROM v$session WHERE audsid=userenv('sessionid');
if (LENGTH(v_AppName) = 0) then
v_AppName := 'Unknown';
end if;
SELECT distinct TO_CHAR(SYSTIMESTAMP,'DD-MON-YY hh24:mi:SS.FF AM') INTO v_AtDateTime FROM dual;
if UPDATING('FinlStatAssetDesignation') then
RAISE_APPLICATION_ERROR(-20000,'Invalid attempt to update OID FinlStatAssetDesignation in FinlStatAssetDesignation');
/*
ROLLBACK */
return;
end if;
if not UPDATING('UpdDate') then
SWV_error := 0;
begin
UPDATE FinlStatAssetDesignation a SET(UpdDate) =(SELECT distinct v_AtDateTime FROM dual where a.FinlStatAssetDesignation = :NEW.FinlStatAssetDesignation)
WHERE ROWID IN(SELECT a.ROWID FROM FinlStatAssetDesignation a where a.FinlStatAssetDesignation = :NEW.FinlStatAssetDesignation);
EXCEPTION
WHEN OTHERS THEN
SWV_error := SQLCODE;
end;
if SWV_error <> 0 then
/*
ROLLBACK */
return;
end if;
end if;
END;
QL> select * from finlstatassetdesignation;
FINLSTATAS FINLSTATASSETDESIGNATIONDESC UPDOPERATION
---------- -------------------------------------------------- ------------
UPDDATE
---------------------------------------------------------------------------
one19 anything 0
01-JAN-17 08.00.00.000000 AM
SQL> update finlstatassetdesignation set finlstatassetdesignationdesc ='nothing';
1 row updated.
SQL> select * from finlstatassetdesignation;
FINLSTATAS FINLSTATASSETDESIGNATIONDESC UPDOPERATION
---------- -------------------------------------------------- ------------
UPDDATE
---------------------------------------------------------------------------
one19 nothing 0
01-JAN-17 08.00.00.000000 AM
SQL> desc finlstatassetdesignation;
Name Null? Type
----------------------------------------- -------- ----------------------------
FINLSTATASSETDESIGNATION NOT NULL CHAR(10 CHAR)
FINLSTATASSETDESIGNATIONDESC NOT NULL VARCHAR2(50 CHAR)
UPDOPERATION NOT NULL NUMBER(10)
UPDDATE NOT NULL TIMESTAMP(6)
Trying to update column FINLSTATASSETDESIGNATIONDESC gets succeded however doesnt update the timestamp in column UPDDATE
Please help....in fixing this trigger...
Trigger not working while updating the table column with trigger enabled on table...
Usually it is a bad idea to write strings (i.e. TO_CHAR(SYSTIMESTAMP,'DD-MM-YY hh24:mi:SS.FF AM') INTO v_AtDateTime) when you actually want to write timestamps.
There are several weak points in your code, according to my understanding you can write it simpler:
CREATE OR REPLACE TRIGGER TR_FinlStatAssetDesignation_U
BEFORE UPDATE
ON FINLSTATASSETDESIGNATION FOR EACH ROW
BEGIN
IF UPDATING('FinlStatAssetDesignation') THEN
RAISE_APPLICATION_ERROR(-20000,'Invalid attempt to update OID FinlStatAssetDesignation in FinlStatAssetDesignation');
-- Rather strange if a column has the same name as the table
END IF;
IF NOT UPDATING('UpdDate') THEN
:NEW.UpdDate := SYSTIMESTAMP;
END IF;
END;
Everything else in your code is redundant, resp. junk.
In case you need the username somewhere, just write USER instead of
select USERNAME INTO v_UserName
FROM v$session
WHERE (audsid = SYS_CONTEXT('userenv','sessionid')) AND ROWNUM <=1;
For application use NVL(SYS_CONTEXT('USERENV', 'CLIENT_PROGRAM_NAME'), 'Unknown') instead of
SELECT program INTO v_AppName FROM v$session WHERE audsid=userenv('sessionid');
if (LENGTH(v_AppName) = 0) then
v_AppName := 'Unknown';
end if;

How to set an object as an out parameter?

I have written a procedure in PL/SQL and want to return a EMP type object. Is it possible to do that? If yes, how can I do it?
Here is the code:
CREATE OR REPLACE
PROCEDURE get_emp_rs (p_deptno IN emp.deptno%TYPE,
p_recordset OUT emp_det) AS
emp_details emp_det;
BEGIN
OPEN p_recordset FOR
SELECT ename,
empno
FROM emp
WHERE deptno = p_deptno
ORDER BY ename;
fetch p_recordset into emp_details;
--exit when p_recordset%notfound;
--end loop;
--for indx in p_recordset
--loop
emp_details.ename:= 'test';
--end loop;
END get_emp_rs;
/
SET SERVEROUTPUT ON SIZE 1000000
DECLARE
l_cursor emp_det;
--l_cur emp_det;
--l_ename emp.ename%TYPE;
--l_empno emp.empno%TYPE;
l_deptno emp.deptno%TYPE;
BEGIN
l_cur:=get_emp_rs ('30',
l_cursor);
dbms_output.put_line('low');
/*LOOP
FETCH l_cursor
INTO l_ename, l_empno, l_deptno;
EXIT WHEN l_cursor%NOTFOUND;*/
DBMS_OUTPUT.PUT_LINE(l_cursor.ename || ' | ' || l_cursor.empno);
end;
/
I want to get the ename and empno after finally update in the procedure.
How can I do it? If there is any better way of doing this please suggest me.
And also please suggest me how I can do it in this way. I cannot use any functions here that's the only obligation. Also please let me know if there is a way of doing this using.
In your example (Table EMP) a single EMP Record shouldn't be selected by the department number. Use the EMPNO instead.
The following is a quick solution and hopefully self-explainable:
SET SERVEROUTPUT ON;
SET FEEDBACK OFF;
CLEAR;
--Define the dataset object
CREATE TYPE EMP_DET AS OBJECT (
EMPNO NUMBER(4),
ENAME VARCHAR2(10)
);
/
--Define a collection of dataset objects
CREATE TYPE EMP_DET_LIST IS TABLE OF EMP_DET;
/
--Get a SINGLE record into the OUT-Variable identified by EMP PK EMPNO
CREATE OR REPLACE PROCEDURE GET_EMP_RS(P_EMPNO IN EMP.EMPNO%TYPE,
P_RECORDSET IN OUT EMP_DET) AS
BEGIN
--Create the return object inside SQL
SELECT EMP_DET(EMPNO, ENAME)
INTO P_RECORDSET
FROM EMP
WHERE EMPNO = P_EMPNO;
P_RECORDSET.ENAME := 'test';
EXCEPTION
WHEN NO_DATA_FOUND THEN
--Return NULL if employee not found
P_RECORDSET := NULL;
END GET_EMP_RS;
/
--Get a LIST OF employees by department
CREATE OR REPLACE PROCEDURE GET_EMP_LIST(P_DEPTNO IN EMP.DEPTNO%TYPE,
P_RECORDLIST OUT EMP_DET_LIST) AS
TYPE C_CURSOR IS REF CURSOR; -- <-- For the explicit cursor solution only
C_EMP_RS C_CURSOR; -- <-- For the explicit cursor solution only
V_RS EMP_DET; -- <-- For the explicit cursor solution only
BEGIN
--Initialize out object
P_RECORDLIST := EMP_DET_LIST();
--Create the return object inside SQL
--via bulk collect
/*
SELECT EMP_DET(EMPNO,ENAME)
BULK COLLECT INTO INTO P_RECORDLIST
FROM EMP
WHERE DEPTNO = P_DEPTNO;
*/
--with manipulation of records
--use a FOR-LOOP with implizit cursor
/*
FOR L_RS IN (SELECT EMP_DET(EMPNO, ENAME) EMP_RS
FROM EMP
WHERE DEPTNO = P_DEPTNO) LOOP
L_RS.EMP_RS.ENAME := 'TEST';
P_RECORDLIST.EXTEND;
P_RECORDLIST(P_RECORDLIST.LAST) := L_RS.EMP_RS;
NULL;
END LOOP;
*/
--or define an explicit cursor and LOOP-FETCH
OPEN C_EMP_RS FOR
SELECT EMP_DET(EMPNO, ENAME) EMP_RS
FROM EMP
WHERE DEPTNO = P_DEPTNO;
LOOP
FETCH C_EMP_RS
INTO V_RS;
EXIT WHEN C_EMP_RS%NOTFOUND;
V_RS.ENAME := 'TEST';
P_RECORDLIST.EXTEND;
P_RECORDLIST(P_RECORDLIST.LAST) := V_RS;
END LOOP;
CLOSE C_EMP_RS;
END GET_EMP_LIST;
/
--**************************
-- Test
--**************************
DECLARE
L_CURSOR EMP_DET;
L_LIST EMP_DET_LIST;
BEGIN
DBMS_OUTPUT.PUT_LINE('---- Single EMP ----');
GET_EMP_RS(7369, L_CURSOR);
IF (L_CURSOR IS NOT NULL) THEN
DBMS_OUTPUT.PUT_LINE(L_CURSOR.ENAME || ' | ' || L_CURSOR.EMPNO);
END IF;
DBMS_OUTPUT.PUT_LINE('---- EMP List ----');
GET_EMP_LIST(30, L_LIST);
IF (L_LIST.count > 0 ) THEN
FOR L_I IN L_LIST.FIRST .. L_LIST.LAST LOOP
DBMS_OUTPUT.PUT_LINE(L_LIST(L_I).ENAME || ' | ' || L_LIST(L_I).EMPNO);
END LOOP;
END IF;
END;
/
DROP PROCEDURE GET_EMP_RS;
DROP PROCEDURE GET_EMP_LIST;
DROP TYPE EMP_DET_LIST;
DROP TYPE EMP_DET;
Output:
---- Single EMP ----
test | 7369
---- EMP List ----
TEST | 7499
TEST | 7521
TEST | 7654
TEST | 7698
TEST | 7844
TEST | 7900
SQL>