Getting error when trying to return the ORACLE cursor output into a variable - sql

I have declared a SELECT query into a cursor which takes 1 argument - the output of which is 1 row and 1 column containing an integer value. I am attempting to open this cursor to store the result into a variable and later print it.
But it is throwing an error: PLS-00306: wrong number or types of arguments in call to 'c1'
I am not sure what I am doing wrong, I have tried declaring return types/ arguments too, but nothing works. Please help.
Here's what I am working with:
DECLARE
dept_no int ;
cursor c1(Var1 date)
IS
SELECT dept_no
from Employees
where academic_period = 202050
and trunc(r_date) = to_date(:Var1, 'yyyy-mm-dd');
BEGIN
dbms_output.put_line('Department Number: ');
OPEN c1;
FETCH c1 INTO dept_no;
CLOSE c1;
END;

You need to open the cursor like this :
OPEN c1(value);
Here is one example how your code "should" look like:
declare
cursor c1(Var1 date)
IS
SELECT dept_no
from Employees
where academic_period = 202050
and trunc("date") = Var1; -- I have removed ":" from the variable call
-- I have also removed the format Check if you actually need it
v_dept_no int ;
BEGIN
dbms_output.put_line('Department Number: ');
OPEN c1(to_date('01-02-2020','dd-mm-yyyy')); --I have formatred the value I am sending
FETCH c1 INTO v_dept_no;
CLOSE c1;
dbms_output.put_line(v_dept_no); -- I have shown you the value reutrned just for show
END;
/
Here is a demo

Your cursor declaration requires a date input parameter:
cursor c1(Var1 date)
IS
 ...
But then you call it without a date:
OPEN c1;
Fix one, or the other!

Related

how to get multiple records by passing parameter to where clause in oracle pl/sql

table :
create table emp
(
E_ID number,
E_NAME varchar2(30)
);
select * from emp;
101 name1
102 name2
My code:
declare
v1 varchar2(30) := '101,102';
begin
for i in (select e_id,e_name
from emp
where e_id in (v1)) loop
dbms_output.put_line(i.e_id);
end loop;
end;
/
ISSUE:
Getting ORA -01722:invalid number
Please help to understand this issue and suggest me the solution.
It is syntax error.
E_ID is of number type and you are comparing it will v1 which is varchar2 type.
Welcome to SO. A great place to ask questions: I can see what you're trying to do. Syntactically, you'd be forgiven for trying to query your table using the "IN" clause, but as others have said, this can not be done where you have committed your numeric values into a varchar2. In anycase, an array or a collection, (even if you had created one) it isn't an easy option here. But you do have a variety of solutions open to you:
1/ Place your numbers into an Array and use a condition in your loop and check that e_id forms part of the your array. But in-elegant!
2/ Create a global temporary table and add your numbers in and add the table into your query, specify a join.
3/ Create some dynamic PL/SQL using a Ref Cursor. I've included an example for you below, using your table (emp) and values. In this case, you'd be able to build up your string according to the values you want to query. See below. The varchar2 string: sqlString can be manipulated however you want. Paste into a test-harness and see. Hope it helps
declare
type refCursor is ref cursor;
tableCursor refCursor;
emp_record emp%rowtype;
sqlString varchar2(200);
begin
-- Dynamic SQL statement with placeholder:
sqlString := 'SELECT * FROM emp WHERE e_id in
(101, 102)';
-- Open cursor:
open tableCursor for sqlString;
-- Fetch rows from result set one at a time:
loop
fetch tableCursor
into emp;
exit when tableCursor%notfound;
dbms_output.put_line(emp.e_id);
end loop;
-- Close cursor:
close tableCursor;
end;

How to populate variable in pl sql on declaration in store procedure with sql statement return

So I have a variable on the declaration on the store procedure. It must have a default value that is populated on the return of a sql statement. The thing is that that variable is used in the declaration of the query of a cursor, thats why it needs to be populated on the declaration. How am i supposed to do this?
create or replace
PROCEDURE PROCESAR AS
ultimaejecucion date := select fecha from table where rownum<=1;
--I know I have to use the word INTO but throws me error when i compile.
cursor cursor_licencias is
select lic.campo1
from lic lic
where lic.licfhing >= ultimaejecucion
BEGIN
open cursor
.
.
.
END PROCESAR;
Your problem is quite unclear. If your cursor always depends on values from another table, you should include this table to query, as Multisync advised. If your cursor also has to depend on different rows of that table, you can use cursor parameters to choose that row:
create or replace
PROCEDURE PROCESAR AS
cursor cursor_licencias (cursor_parameter number default 1234) is
select lic.campo1
from lic lic
where lic.licfhing >= (select fecha from table where column = cursor_parameter);
BEGIN
open cursor cursor_licencias; -- using with default value
open cursor cursor_licencias (5678); -- using with value '5678'
END PROCESAR;
Example in oracle documentation.
You may move it into the cursor declaration:
create or replace
PROCEDURE PROCESAR AS
cursor cursor_licencias is
select lic.campo1
from lic lic
where lic.licfhing >= (select fecha from table where rownum<=1);
BEGIN
open cursor
.
.
.
END PROCESAR;
if you need this field somewhere else you can assign the value to the ultimaejecucion right after BEGIN
I would do something like:
declare
l_date date;
-- the value of l_date does not matter at this point
cursor sel_cur is
select 'It works' as val
from dual
where sysdate > l_date;
begin
-- populate l_date using query
select sysdate - 1
into l_date
from dual;
-- open cursor (implicitly).
-- here the value of l_date is used in the execution of the query
for rec in sel_cur
loop
dbms_output.put_line(rec.val);
end loop;
end;

PL/SQL cursor with IF condition

I Have below cursor in the code.
CURSOR cur1
IS
SELECT a, b, c, d,
FROM EMP;
BEGIN
--Stored procedure logic
END
This curosr is getting information from EMP table.
But I need to change is as per below
There is a table (Table1) with Key Value pairs.
If the Table1 value is TRUE then the cursor should be created with STUDENT table
If the table1 value is FALSE then the cursor should be created with EMP table.
I can check the Value in the Table1 as below
select t.value into variable1 from Table1 t where s.key='xxxxx';
And I want write something like
IF variable1 := 'true'
curosr created with STUDENT
ELSE
curosr created with EMP
END IF
BEGIN
--Stored procedure logic
END
How to do it?
In another way you can just keep two CURSORS for those two scenarios and OPEN them on the condition. Declaring two CURSORS will not affect to the performance; you should be careful when OPEN a CURSOR and FETCHING from it.
PROCEDURE Get_Details_On_Condition ( name_ OUT VARCHAR2, isEmp IN BOOLEAN )
IS
CURSOR get_emp IS
SELECT name
FROM EMP;
CURSOR get_std IS
SELECT name
FROM STUDENT;
BEGIN
IF isEmp THEN
OPEN get_emp ;
FETCH get_emp INTO name_ ;
CLOSE get_emp ;
ELSE
OPEN get_std ;
FETCH get_std INTO name_ ;
CLOSE get_std ;
END IF;
RETURN name_;
END Get_Details_On_Condition;
Using if .. else construct is not proper (neither supported). You can use REF cursor to achieve the same like below.
DECLARE type cur1 REF CURSOR;
c1 cur1;
BEGIN
IF (variable1 := 'true') THEN
OPEN c1 FOR 'SELECT * FROM STUDENT';
ELSE
OPEN c1 FOR 'SELECT * FORM EMP';
END IF ;
END;
Idea taken from Oracle Community Forum Post
NOTE: I didn't included the entire code block (I mean cursor processing, closing etc) cause the main concern here is "How he will declare/define conditional cursor". So, pointed that particular in my code snippet. Since, rest of the part like processing the cursor and closing can be directly be found in Oracle specification.
For a complete code block, you can refer the answer given by Harsh
I would prefer to solve this without using dynamic SQL. If the code to process the results is the same for both tables, then it is reasonable to assume that the columns are the same (or equivalent) as well. My inclination would be to solve this using UNION and sub-queries:
DECLARE
CURSOR cur1 IS
SELECT a, b, c, d
FROM emp
WHERE NOT EXISTS
(SELECT *
FROM table1
WHERE s.key = 'xxxxx' AND t.VALUE = 'true')
UNION ALL
SELECT a, b, c, d
FROM student
WHERE EXISTS
(SELECT *
FROM table1
WHERE s.key = 'xxxxx' AND t.VALUE = 'true');
BEGIN
--Stored procedure logic
END;
The link provided by Rahul indicates the correct way to solve the problem. From the Oracle community forum post posted by Rahul, I have taken the code snippet through which the code could run successfully.
Rahul: Please do not take this as a redundant answer as I could not comment on your answer to help shyam to take the code snippet in the link posted by you.
Declare
TYPE cv_typ IS REF CURSOR;
cv cv_typ;
Begin
If(condition1 is TRUE) then
open cv FOR
'Select * from table_name1';
EXIT WHEN cv%NOTFOUND;
ELSE
open cv FOR
'Select * from table_name2';
EXIT WHEN cv%NOTFOUND;
End If;
CLOSE cv;
END;
Thanks & Regards,
Harsh
You can move the OPEN outside IF statement:
DECLARE type cur1 REF CURSOR;
c1 cur1;
vSQL VARCHAR2(1000);
BEGIN
IF (variable1 = 'true') THEN
vSQL := 'SELECT * FROM STUDENT';
ELSE
vSQL := 'SELECT * FORM EMP';
END IF;
OPEN c1 FOR vSQL;
--procedure logic
CLOSE c1;
END;

Error in Oracle (PLS-00103: Encountered the symbol "="...) trying to select into a variable for use in a cursor

I'm creating a procedure. I'm selecting a max date from a table into a var, and then intending to use that var in sql for a cursor. It looks like:
l_max_update_date DATE;
--Param var
l_max_update_date := NULL;
SELECT max(pivlog.last_update_date) as maxdate into l_max_update_date
FROM piv_verification_log pivlog;
...and then...
--No data in log table? Create a max_update_date
IF l_max_update_date IS NULL
THEN
l_max_update_date := TO_TIMESTAMP('2014/SEP/1 00:00:00', 'YYYY/MON/DD HH24:MI:SS');
END IF;
Finally...
--Get affected employees (those who have certified since the max(last_update_date) listed in the log table)
CURSOR affected_employees_cursor
IS
SELECT [columns]
FROM [tables]
WHERE LAST_UPDATE_DATE > l_max_update_date;
But, whenever I compile, I get this error message:
[Error] PLS-00103 (47: 22): PLS-00103: Encountered the symbol "=" when expecting one of the following:
constant exception
table long double ref
char time timestamp
which points at this line:
l_max_update_date := NULL;
I appreciate your insight. I'm thinking it has to do with the order or location in the procedure where I'm defining the var and cursor(?).
Thank you.
You can't have executable code before the first BEGIN. It would help if you'd post all the code for your procedure, but given what can be seen above it looks to me like your procedure should be something like:
CREATE OR REPLACE PROCEDURE SOME_PROC AS
l_max_update_date DATE := NULL; -- not really needed - variables are
-- initialized to NULL if no other
-- initial value is given.
CURSOR affected_employees_cursor IS
SELECT [columns]
FROM [tables]
WHERE LAST_UPDATE_DATE > l_max_update_date;
rowAffected_employee affected_employees_cursor%ROWTYPE;
BEGIN
BEGIN
SELECT max(pivlog.last_update_date) as maxdate
into l_max_update_date
FROM piv_verification_log pivlog;
EXCEPTION
WHEN NO_DATA_FOUND THEN
l_max_update_date := NULL;
END;
--No data in log table? Create a max_update_date
IF l_max_update_date IS NULL THEN
l_max_update_date := TO_DATE('2014/SEP/1 00:00:00', 'YYYY/MON/DD HH24:MI:SS');
END IF;
OPEN affected_employees_cursor;
LOOP
FETCH affected_employees_cursor
INTO rowAffected_employee;
EXIT WHEN affected_employees_cursor%NOTFOUND;
-- do something useful with the data fetched from the cursor
END LOOP;
CLOSE affected_employees_cursor;
END SOME_PROC;
Share and enjoy.
Further to Bob's answer, the cursor will use whatever value l_max_update_date has at the point the cursor is opened, so it doesn't have to be set before the cursor is declared.
If you'd prefer that to be more obvious in your code then you could also pass the date to the cursor as a parameter:
CURSOR affected_employees_cursor (p_last_update_date DATE) IS
SELECT [columns]
FROM [tables]
WHERE LAST_UPDATE_DATE > p_max_update_date;
and then call it with:
OPEN affected_employees_cursor (l_max_update_date);
Or you could combine the lookup-up into the cursor definition, as long as you only open it once, and skip the separate look-up and check:
CREATE OR REPLACE PROCEDURE SOME_PROC AS
CURSOR affected_employees_cursor IS
SELECT [columns]
FROM [tables]
WHERE LAST_UPDATE_DATE > (
SELECT COALESCE(MAX(pivlog.last_update_date), DATE '2014-09-01')
FROM piv_verification_log pivlog
);
rowAffected_employee affected_employees_cursor%ROWTYPE;
BEGIN
OPEN affected_employees_cursor;
LOOP
FETCH affected_employees_cursor
INTO rowAffected_employee;
EXIT WHEN affected_employees_cursor%NOTFOUND;
-- do something useful with the data fetched from the cursor
END LOOP;
CLOSE affected_employees_cursor;
END SOME_PROC;
/
Or even simpler use an implicit cursor loop:
CREATE OR REPLACE PROCEDURE SOME_PROC AS
BEGIN
FOR rowAffected_employee In (
SELECT [columns]
FROM [tables]
WHERE LAST_UPDATE_DATE > (
SELECT COALESCE(MAX(pivlog.last_update_date), DATE '2014-09-01')
FROM piv_verification_log pivlog
)
)
LOOP
-- do something useful with the data fetched from the cursor
END LOOP;
END SOME_PROC;
/
Of course, depending on what you're doing with the data fetched form the cursor, this might be something that doesn't need PL/SQL at all and could be done in plain SQL.

Oracle: IN function within an IF block

I have a cursor c2, with one column 'note', containing numbers.
I want to check, whether the column contains 5 and change my local variable if so.
this:
CREATE OR REPLACE PROCEDURE proc
IS
result varchar(50);
cursor c2 is
SELECT note
FROM student;
BEGIN
IF c2.note IN(5) THEN
result := 'contains 5';
DBMS_OUTPUT.PUT_LINE(result);
END;
/
doesnt work.
please help!
In your code, you're declaring a cursor but you are never opening it and never fetching data from it. You'd need, presumably, some sort of loop to iterate through the rows that the cursor returned. You'll either need to explicitly or implicitly declare a record into which each particular row is fetched. One option to do that is something like
CREATE OR REPLACE PROCEDURE proc
IS
result varchar(50);
cursor c2 is
SELECT note
FROM student;
BEGIN
FOR rec IN c2
LOOP
IF rec.note IN(5) THEN
result := 'contains 5';
DBMS_OUTPUT.PUT_LINE(result);
END IF;
END LOOP;
END;
/
Note that you also have to have an END IF that corresponds to your IF statement. Naming a cursor c2 is also generally a bad idea-- your variables really ought to be named meaningfully.
You have too loop over the records/rows returned in the cursor; you can't refer to the cursor itself like that:
CREATE OR REPLACE PROCEDURE proc
IS
result varchar(50);
cursor c2 is
SELECT note
FROM student;
BEGIN
FOR r2 IN c2 LOOP
IF r2.note = 5 THEN -- IN would also work but doesn't add anything
result := 'contains 5';
END IF;
END LOOP;
DBMS_OUTPUT.PUT_LINE(result);
END;
/
But if you're just testing for the existence of any record with value 5 then you don't need a cursor:
CREATE OR REPLACE PROCEDURE proc
IS
result varchar(50);
BEGIN
SELECT max('contains 5')
INTO result
FROM student
WHERE note = 5;
DBMS_OUTPUT.PUT_LINE(result);
END;
/
If there are any rows with five you'll get the 'contains 5' string; if not you'll get null. The max() stops an exception being thrown if there are either zero or more than one matching records in the table.
You are missing an END IF and need to LOOP over the cursor. The procedure name is included in the final END.
But using IN should work. Like this:
CREATE OR REPLACE PROCEDURE proc
IS
result varchar(50);
cursor c2 is
SELECT note
FROM student;
BEGIN
FOR rec in c2
LOOP
IF rec.note IN (5) THEN
result := 'contains 5';
END IF;
END LOOP;
DBMS_OUTPUT.PUT_LINE(result);
END proc;
/