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

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.

Related

pl/sql ,oracle add heading in cursor

how I can add heading for table shown at top , in my code like this pic:
enter image description here
declare
E_Name employ.name%type;
E_Salary employ.salary%type;
CURSOR c_employees is
SELECT name , salary from employ order by salary desc;
BEGIN
OPEN c_employees;
LOOP
FETCH c_employees into E_Name,E_Salary ;
EXIT WHEN c_employees%notfound;
dbms_output.put_line( rpad(E_Name, 20, '.') || ' ' || rpad('$', (E_Salary/100), '$')||' '||E_Salary);
END LOOP;
CLOSE c_employees;
END;
/
Include two more DBMS_OUTPUT.PUT_LINEs which will display that header (lines #2 and 3).
For example (using my tables as I don't have yours):
SQL> begin
2 dbms_output.put_line('Emloyee name Salary');
3 dbms_output.put_line('------------ ------');
4
5 for cur_r in (select ename, sal from emp where deptno = 10) loop
6 dbms_output.put_line(rpad(cur_r.ename, 12, ' ') ||' '||
7 to_char(cur_r.sal, '99990'));
8 end loop;
9 end;
10 /
Emloyee name Salary
------------ ------
CLARK 2450
KING 5000
MILLER 1300
PL/SQL procedure successfully completed.
SQL>

How to dbms_output record variable

set serveroutput on;
DECLARE
PI_STARTDATE DATE;
PO_STATUS NUMBER;
PO_HEADER VARCHAR2(200);
PO_LABEL VARCHAR2(200);
PO_RECORD SYS_REFCURSOR;
PO_NEXTINCSTARTDATE DATE;
BEGIN
PI_STARTDATE := to_date('2020-05-01','yyyy-MM-dd');
PCK_FAB_REPORTS.PRC_MONTHLY_WRTOFF_REPORT(
PI_STARTDATE => PI_STARTDATE,
PO_STATUS => PO_STATUS,
PO_HEADER => PO_HEADER,
PO_LABEL => PO_LABEL,
PO_RECORD => PO_RECORD,
PO_NEXTINCSTARTDATE => PO_NEXTINCSTARTDATE);
DBMS_OUTPUT.PUT_LINE('PO_STATUS = ' || PO_STATUS);
DBMS_OUTPUT.PUT_LINE('PO_HEADER = ' || PO_HEADER);
DBMS_OUTPUT.PUT_LINE('PO_LABEL = ' || PO_LABEL);
DBMS_OUTPUT.PUT_LINE('PO_NEXTINCSTARTDATE = ' || PO_NEXTINCSTARTDATE);
END;
I want to unit test the procedure and want to display the ref cursor variable as well. How to display ref cursor using dbms?
Here's an example based on Scott's EMP table:
SQL> set serveroutput on
SQL>
SQL> declare
2 l_ename emp.ename%type;
3 l_job emp.job%type;
4 l_rc sys_refcursor;
5 begin
6 open l_rc for select ename, job from emp
7 where deptno = 10;
8
9 loop
10 fetch l_rc into l_ename, l_job;
11 exit when l_rc%notfound;
12
13 dbms_output.put_line(l_ename ||' '|| l_job);
14 end loop;
15 close l_rc;
16 end;
17 /
CLARK MANAGER
KING PRESIDENT
MILLER CLERK
PL/SQL procedure successfully completed.
SQL>
So: you have to fetch refcursor into variables and then display contents of those variables.

PL/SQL Defining the select statement for sum in If and loop

For an example, we have employer salary and department based in emp table.
In SQL , we can retrieve the total salary per department just by doing this
SELECT SUM(SAL) FROM EMP WHERE DEPTNO = 20 ; //Lets put it we finding sum for dept 20.
But where else for pl/sql , I think I am syntactically wrong . I am using cursor to store all the datas. in my if statement which is inside a loop below , I tried my logic with
if deptno = 20 THEN
totalSalary = sum(salary);
DBMS_OUTPUT.PUT_LINE('Department : 20' || total Salary);
This is my actual code .
DECLARE
msal emp.salary%TYPE;
mdept emp.departmentNo%TYPE;
new_salary number(10,2);
CURSOR E1 IS select salary , departmentNo from emp;
BEGIN
OPEN E1;
LOOP
FETCH E1 into msal , mdeptno;
IF mdeptno = 20 THEN
---- I cant seems to find the right logic here to print out the total sum for department 20---
END IF;
EXIT WHEN E1%NOTFOUND;
END LOOP;
CLOSE E1;
END;
/
Thanks in advance
There is no need to use PL/SQL for thing which you can do with SQL. But if you are really need it, use following:
DECLARE
msal emp.salary%TYPE;
mdept emp.departmentNo%TYPE;
new_salary number(10,2);
CURSOR E1 (p_dept number) IS
select sum(salary) from emp where departmentNo = p_dept;
BEGIN
OPEN E1(20);
FETCH E1 into msal;
dbms_output.put_line(msal);
CLOSE E1;
END;
/
You can introduce another variable for sum aggregation and in each loop iteration add it up.
And then print out once required.
DECLARE
msal emp.salary%TYPE;
mdept emp.departmentNo%TYPE;
sum_salary number(10,2) := 0;
CURSOR E1 IS select salary , departmentNo from emp;
BEGIN
OPEN E1;
LOOP
FETCH E1 into msal , mdeptno;
sum_salary := sum_salary + msal;
IF mdeptno = 20 THEN
dbms_output.put_line(sum_salary);
EXIT WHEN E1%NOTFOUND;
END LOOP;
CLOSE E1;
PL/SQL allows you to access row by row, ( that is done by SQL behind the scenes for you)
Keep a running total with the variable, totalSalary
The algorithm is as follows:
-fetch values from cursor, e1, and assign to msal and mdeptno
-for each fetched value of msal (within the loop), keep a running total using the variable, tot_sal (or totalSalary as you originally posted)
With your approach, the assignment,totalSalary := sum(salary);, does nothing but throws errors because salary is not defined as a variable. The cursor fetches the value of salary (mine is sal) and it is assigned to msal.
If the assignment was totalSalary := sum(msal);, then it would writes over the previous fetched value and does not keep track of a running total.
The standard way to do this is initialize tot_sal to zero (or totalSalary) before the loop and then keep a running total for each fetched record:
tot_sal := tot_sal + msal;
Here is the simple sql result juxtaposed with the anonymous block:
SCOTT#dev>SELECT
2 SUM(sal)
3 FROM
4 emp
5 WHERE
6 deptno = 20;
SUM(SAL)
10875
SCOTT#dev>DECLARE
2 msal emp.sal%TYPE;
3 mdeptno emp.deptno%TYPE;
4 tot_sal emp.sal%TYPE;
5 CURSOR e1 IS
6 SELECT
7 sal,
8 deptno
9 FROM
10 emp;
11
12 BEGIN
13 tot_sal := 0;
14 OPEN e1;
15 LOOP
16 FETCH e1 INTO msal,mdeptno;
17 IF
18 mdeptno = 20
19 THEN
20 tot_sal := tot_sal + msal;
21 END IF;
22
23 EXIT WHEN e1%notfound;
24 END LOOP;
25
26 CLOSE e1;
27 dbms_output.put_line(tot_sal);
28 END;
29 /
10875
PL/SQL procedure successfully completed.
thank you for all your response ,
I am assigned to do this in pl/sql ,
i appreciate all the response from you guys. I have come out with the easiest technique in getting the result for sum, min and max and avg.
What i basically did was using the inbuild function that was already in sql and implement it in my select statement . So i have solve it by
DECLARE
totalSal emp.salary%TYPE;
maxSal emp.salary%TYPE;
minSal emp.salary%TYPE;
mdept emp.departmentNo%TYPE := 20; /* for an example getting all values for dept 20 */
CURSOR E1 IS select sum(salary) , max(salary) , min(sal) from emp where
departmentNo = mdept group by departmentNo;
BEGIN
OPEN E1;
LOOP
FETCH E1 into totalSal , maxSal , minSal;
EXIT WHEN E1%NOTFOUND;
DBMS_OUTPUT.PUT_LINE('...' || maxsal); /*...so on for display*/
END LOOP;
CLOSE E1;
END; /

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>

ORA-01403: no data found

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.