create oracle sql cursor inside procedure ERROR - oracle

I created a procedure for calculating salary of employees by considering shift table data
my shift table is ,
CREATE TABLE SHIFT
(SHIFT_ID NUMBER(4),
SHIFT_DATE DATE,
CUSTOMER_ID NUMBER(4),
SERVICE_ID NUMBER(4),
EMPLOYEE_ID NUMBER(4),
SHIFT_CHARGE FLOAT(10),
PRIMARY KEY(SHIFT_ID)
);
my procedure is,
CREATE OR REPLACE PROCEDURE CAL_SALLARY
AS
CURSOR SHIFT_CURSOR IS SELECT EMPLOYEE_ID,SUM(SHIFT_CHARGE) AS SALARY FROM SHIFT GROUP BY EMPLOYEE_ID;
BEGIN
OPEN SHIFT_CURSOR;
LOOP
FETCH SHIFT_CURSOR INTO SHIFT_REC;
EXIT WHEN SHIFT_CURSOR%NOTFOUND;
DBMS_OUTPUT.PUT_LINE('EMPLOYYE ID : '||SHIFT_REC.EMPLOYEE_ID||' SALARY : '||SHIFT_REC.SALARY);
END LOOP;
CLOSE SHIFT_CURSOR;
END;
/
But when I try to run this procedure in SQL plus, it says compilation fails. I count found what's the issue.
please anyone help me.

You forgot to declare cursor variable (see line #7):
SQL> CREATE OR REPLACE PROCEDURE CAL_SALLARY
2 AS
3 CURSOR SHIFT_CURSOR IS
4 SELECT EMPLOYEE_ID, SUM(SHIFT_CHARGE) AS SALARY
5 FROM SHIFT GROUP BY EMPLOYEE_ID;
6
7 shift_Rec shift_cursor%rowtype;
8 BEGIN
9 OPEN SHIFT_CURSOR;
10 LOOP
11 FETCH SHIFT_CURSOR INTO SHIFT_REC;
12 EXIT WHEN SHIFT_CURSOR%NOTFOUND;
13 DBMS_OUTPUT.PUT_LINE('EMPLOYYE ID : '||SHIFT_REC.EMPLOYEE_ID
14 ||' SALARY : '||SHIFT_REC.SALARY);
15 END LOOP;
16 CLOSE SHIFT_CURSOR;
17 END;
18 /
Procedure created.
SQL>
A simpler option is cursor FOR loop; Oracle does most of dirty job for you (e.g. declaring cursor variable, opening and closing cursor, exiting the loop):
SQL> create or replace procedure cal_sallary as
2 begin
3 for shift_rec in (select employee_id, sum(shift_charge) as salary
4 from shift
5 group by employee_id
6 )
7 loop
8 dbms_output.put_line('EMPLOYYE ID : '||shift_rec.employee_id
9 ||' SALARY : '||shift_rec.salary);
10 end loop;
11 end;
12 /
Procedure created.
SQL>

Related

How to print random from table in a procedure oracle?

Let's say I have a table child and I want in a procedure to select random from 1 to 5, random values from the table and print them. How can i do it?
create table child(name varchar2(20), age number);
insert into child(name, age) values('A',5);
insert into child(name, age) values('B',12);
insert into child(name, age) values('C',7);
insert into child(name, age) values('D',4);
create or replace procedure random_child
as
l_name child.name%type;
l_age child.age%type;
begin
for i in(select dbms_random.value(1,5)
from (select name from child sample(50)))
loop
DBMS_OUTPUT.put_line(i.name);
end loop;
end;
It gives me a PLS-00302: name must be declared
You can use:
CREATE PROCEDURE random_child
AS
BEGIN
FOR i in(
SELECT name,
FLOOR(DBMS_RANDOM.VALUE(1,6)) AS value
FROM child
SAMPLE(50)
)
LOOP
DBMS_OUTPUT.put_line(i.name || ' ' || i.value);
END LOOP;
END;
/
Then:
BEGIN
random_child();
END;
/
May randomly output:
B 3
C 2
D 2
db<>fiddle here
There's no i.name there; alias is missing at the end of line #6:
SQL> create or replace procedure random_child
2 as
3 l_name child.name%type;
4 l_age child.age%type;
5 begin
6 for i in(select dbms_random.value(1,5) as name --> here
7 from (select name from child sample(50)))
8 loop
9 DBMS_OUTPUT.put_line(i.name);
10 end loop;
11 end;
12 /
Procedure created.
SQL> exec random_child
1,30966411991963041689918865935551009464
1,13993832387089615287177388489291237644
3,85292920191145794430114472793297022632
PL/SQL procedure successfully completed.
SQL>

Select Query in cursor FOR LOOP

Pretty new to Oracle, need help on this Procedure, using Oracle 11g
Sample table data (TAB1):
ID
Amount
Currency
10
300
GBP
15
500
GBP
20
100
GBP
Requirement is to select all the ID's from TAB1 based on currency and store it in a variable and later use these ID's in other select Queries within the same Stored Procedure.
CREATE OR REPLACE PROCEDURE myproc (i_id IN VARCHAR, i_curr IN VARCHAR)
AS
CURSOR GET_I IS
SELECT ID, CURRENCY
FROM TAB1
WHERE CURRENCY = 'GBP';
-- This will give me 3 ID's (10, 15 & 20) which I am storing in variable r_1 below.
r_1 VARCHAR (5) : NULL;
BEGIN
OPEN GET_I;
LOOP
FETCH GET_I INTO r_1;
IF GET_I%NOTFOUND
THEN
EXIT;
---In the below ELSE PART can we run a select query using the value stored in r_1??
--ELSE
--Data stored in r_1 to be used in further select queries in later part and output of the below
--be returned as SYS_REFCURSOR;
--BELOW two lines gives error
--FOR I in r_1 (
--SELECT ID FROM TAB2 WHERE TAB2.ID=r_1);
END IF;
END LOOP;
CLOSE GET_ID;
END;
It looks you want to use a nested FOR loop.
I'd suggest you to use cursor FOR loops - they are easier to maintain as you don't have to declare cursor variable (by the way, in your case it wouldn't work anyway as you'd like to store both ID and CURRENCY into a scalar R_1 variable), open the cursor, pay attention about exiting the loop and closing the cursor. In a cursor FOR loop, Oracle does all that for you.
Here's an example:
Sample table:
SQL> select * from tab1;
ID AMOUNT CUR
---------- ---------- ---
10 300 GBP
15 500 GBP
20 100 GBP
Procedure:
SQL> create or replace procedure myproc as
2 begin
3 for cur_id in (select id from tab1) loop
4 dbms_output.put_line('ID = ' || cur_id.id);
5 for cur_other in (select amount, currency
6 from tab1
7 where id = cur_id.id --> use ID fetched in outer loop
8 )
9 loop
10 dbms_output.put_line(cur_other.amount ||' - '|| cur_other.currency);
11 end loop;
12 end loop;
13 end;
14 /
Procedure created.
Testing:
SQL> set serveroutput on
SQL> exec myproc;
ID = 10
300 - GBP
ID = 15
500 - GBP
ID = 20
100 - GBP
PL/SQL procedure successfully completed.
SQL>
How to return a refcursor?
SQL> create or replace procedure myproc (par_id in tab1.id%type,
2 par_rc out sys_refcursor) as
3 begin
4 for cur_id in (select id
5 from tab1
6 where id = par_id
7 ) loop
8
9 open par_rc for select amount, currency
10 from tab1
11 where id = cur_id.id;
12 end loop;
13 end;
14 /
Procedure created.
SQL> var l_rc refcursor
SQL>
SQL> exec myproc(10, :l_rc);
PL/SQL procedure successfully completed.
SQL> print l_rc
AMOUNT CUR
---------- ---
300 GBP
SQL>

fetching table data into a table using cursor

I have a table called phonebook and it has two columns (firstName, LastName). I want to create a table of lastName index by firstName using cursor, and I wrote this code:
CREATE OR REPLACE PROCEDURE proc1 AS
TYPE tableNames IS TABLE OF VARCHAR2(20) INDEX BY VARCHAR(20);
v1 tableNames;
v_firstName PHONEBOOK.FIRSTNAME%TYPE;
v_lastName PHONEBOOK.LASTNAME%TYPE;
CURSOR c_name IS SELECT FIRSTNAME, LASTNAME FROM PHONEBOOK;
BEGIN
OPEN c_name;
LOOP
FETCH c_name INTO v_firstName, v_lastName;
EXIT WHEN c_name%NOTFOUND;
v1(v_firstName) := v_lastName;
END LOOP;
FOR idx IN v1.FIRST..v1.LAST
LOOP
DBMS_OUTPUT.PUT_LINE (v1(idx));
END LOOP;
CLOSE c_name;
END;
/
It has been successfully compiled. When I run this procedure it should print lastNames which stored in the tableNames but it gave me an error:
ORA-06502 "PL/SQL: numeric or value error"
Cause: An arithmetic, numeric, string, conversion, or constraint error
occurred. For example, this error occurs if an attempt is made to
assign the value NULL to a variable declared NOT NULL, or if an
attempt is made to assign an integer larger than 99 to a variable
declared NUMBER(2).
Action: Change the data, how it is manipulated, or how it is declared so
that values do not violate constraints.
Please help me to solve this problem
Not FOR, but WHILE. Also, I used cursor FOR loop as a source; easier to write & maintain.
SQL> create table phonebook (firstname varchar2(10), lastname varchar2(10));
Table created.
SQL> insert into phonebook
2 select 'Little', 'Foot' from dual union all
3 select 'Mc' , 'Donalds' from dual;
2 rows created.
SQL> create or replace procedure proc1 as
2 type tablenames is table of varchar2(10) index by varchar2(10);
3 v1 tablenames;
4 idx varchar2(10);
5 begin
6 for cur_r in (select firstname, lastname
7 from phonebook
8 )
9 loop
10 v1(cur_r.firstname) := cur_r.lastname;
11 end loop;
12
13 idx := v1.first;
14 while idx is not null loop
15 dbms_output.put_line(v1(idx));
16 idx := v1.next(idx);
17 end loop;
18 end;
19 /
Procedure created.
SQL> exec proc1;
Foot
Donalds
PL/SQL procedure successfully completed.
SQL>

Single cursor for two different SQL in Oracle

I have a scenario where i want to use a cursor for two different sql.
create or replace procedure(p_load_type in number)
as
create cursor prod_cur
is
/* This is the 1st SQL*/
select product_id,
product_name
from Test_product;
prod_rec prod_cur%rowtype;
/* here is the second sql that i want cursor open for this when p_load_type=2
select product_id,
product_name
from Test_product tp,
Test_delta_cases tdc
where tp.product_id=tdc.product_id;*/
begin
if p_load_type=1 then /* opening for 1st sql*/
open prod_cur
elsif p_load_type=2 then /* opening for 2nd sql*/
open prod_cur
end if;
loop
some logic............
end loop;
end;
Please use formatting to format your code in your question. Anyway, you can do with REF CURSORS, eg
SQL> create or replace
2 procedure P(p_type int ) is
3 rc sys_refcursor;
4
5 cursor c_template is select 1 x, 1 y from dual;
6 l_rows c_template%rowtype;
7
8 begin
9 if p_type = 1 then
10 open rc for select empno, deptno from scott.emp;
11 else
12 open rc for select empno, sal from scott.emp;
13 end if;
14
15 loop
16 fetch rc into l_rows;
17 exit when rc%notfound;
18 dbms_output.put_line(l_rows.x||','||l_rows.y);
19 end loop;
20 end;
21 /
Procedure created.
SQL> set serverout on
SQL> exec p(1);
7369,20
7499,30
7521,30
7566,20
7654,30
7698,30
7782,10
7788,20
7839,10
7844,30
7876,20
7900,30
7902,20
7934,10
PL/SQL procedure successfully completed.
SQL> exec p(2);
7369,800
7499,1600
7521,1250
7566,2975
7654,1250
7698,2850
7782,2450
7788,3000
7839,5000
7844,1500
7876,1100
7900,950
7902,3000
7934,1300
PL/SQL procedure successfully completed.

using cursor attributes in a CURSOR FOR LOOP

I am running the following in the Scott schema:
SET serveroutput ON;
BEGIN
FOR c_Emp IN (SELECT * FROM emp)
LOOP
dbms_output.put_line('The record processed by the cursor ' || c_Emp%rowcount);
END LOOP;
end;
This gives the error:
cursor attribute may not be applied to non-cursor 'C_EMP'
However if this is done using an explicit cursor it works fine:
set serveroutput on ;
DECLARE
emp_record emp%ROWTYPE;
count_variable NUMBER;
CURSOR c IS
SELECT * FROM emp;
BEGIN
OPEN c;
loop
fetch c INTO emp_record;
exit WHEN c%notfound;
dbms_output.put_line ('The record count is ' || c%rowcount);
END loop;
close c;
end;
Just want to understand : whether while using the CURSOR FOR LOOP, is the index variable not a cursor attribute, if so why? could someone plz expalin this....
c_Emp is not the cursor, its a record with felds for each column in the SELECT statment
c_Emp is similar to the emp_record from your second example.
Even while using a FOR loop the cursor has to be explicitly defined.
A sample use of FOR loop with a cursor would look like below:
declare
cursor c1 is select a from table;
begin
FOR b in c1
loop
<required logic>
end loop;
end;
To get the index in a for loop, you can add the rownum pseudocolumn in the select clause of implicit cursor.
SET serveroutput ON;
BEGIN
FOR c_Emp IN (SELECT e.*, rownum FROM emp e)
LOOP
dbms_output.put_line('The record processed by the cursor ' || c_Emp.rownum);
END LOOP;
end;
Try this:
SET serveroutput ON;
DECLARE
x NUMBER :=0 ;
BEGIN
FOR c_Emp IN (SELECT * FROM emp)
LOOP
x := x+1;
dbms_output.put_line('The record processed by the cursor ' || x);
END LOOP;
-----
IF x>0 THEN
dbms_output.put_line('Cursr was opened');
ELSE
dbms_output.put_line('Cursr was not opened');
END IF;
end;
SQL> create table product(
2 product_id number(4) not null,
3 product_description varchar2(20) not null
4 );
Table created.
SQL>
SQL> insert into product values (1,'Java');
1 row created.
SQL> insert into product values (2,'Oracle');
1 row created.
SQL> insert into product values (3,'C#');
1 row created.
SQL> insert into product values (4,'Javascript');
1 row created.
SQL> insert into product values (5,'Python');
1 row created.
SQL> create table company(
2 product_id number(4) not null,
3 company_id NUMBER(8) not null,
4 company_short_name varchar2(30) not null,
5 company_long_name varchar2(60)
6 );
Table created.
SQL> insert into company values(1,1001,'A Inc.','Long Name A Inc.');
1 row created.
SQL> insert into company values(1,1002,'B Inc.','Long Name B Inc.');
1 row created.
SQL> insert into company values(1,1003,'C Inc.','Long Name C Inc.');
1 row created.
SQL> insert into company values(2,1004,'D Inc.','Long Name D Inc.');
1 row created.
SQL> insert into company values(2,1005,'E Inc.','Long Name E Inc.');
1 row created.
SQL> insert into company values(2,1006,'F Inc.','Long Name F Inc.');
1 row created.
SQL> DECLARE
2 CURSOR cursorValue IS
3 SELECT h.product_description,o.company_short_name FROM company o,product h
4 WHERE o.product_id =h.product_id
5 ORDER by 2;
6 num_total_rows NUMBER;
7 BEGIN
8
9 FOR idx IN cursorValue LOOP
10 dbms_output.put_line(rpad(idx.product_description,20,' ')||' '||
11 rpad(idx.company_short_name,30,' '));
12
13 num_total_rows :=cursorValue%ROWCOUNT;
14 END LOOP;
15 IF num_total_rows >0 THEN
16 dbms_output.new_line;
17 dbms_output.put_line('Total Organizations = '||to_char(num_total_rows));
18 END IF;
19 END;
20 /
Java A Inc.
Java B Inc.
Java C Inc.
Oracle D Inc.
Oracle E Inc.
Oracle F Inc.
Total Organizations = 6
PL/SQL procedure successfully completed.
SQL> drop table product;
Table dropped.
SQL> drop table company;
Table dropped.
enter code here

Resources