Creating a procedure with PLSQL - oracle

I am trying to write a PLSQL function that implements a constraint that an employee cannot be both a driver and a mechanic at the same time, in other words, the same E# from TRKEMPLOYEE cannot be in TRKDRIVER and TRKMECHANIC at the same time. If the contents of the DB violate that constraint, list the E# and NAME of all employees that are both mechanics and drivers. The abovementioned tables are something like as follows:
TRKEMPLOYEE(E# NUMBER(12) NOT NULL
NAME VARCHAR(50) NOT NULL,
DOB DATE ,
ADDRESS VARCHAR(300) NOT NULL,
HIREDATE DATE NOT NULL,
CONSTRAINT TRKEMPLOYEE_PKEY PRIMARY KEY(E#))
TRKDRIVER(E# NUMBER(12) NOT NULL
L# NUMBER(8) NOT NULL,
STATUS VARCHAR(10) NOT NULL,
CONSTRAINT TRKDRIVER_PKEY PRIMARY KEY(E#),
CONSTRAINT TRKDRIVER_FKEY FOREIGN KEY(E#) REFERENCES TRKEMPLOYEE(E#))
TRKMECHANIC(E# NUMBER(12) NOT NULL
L# NUMBER(8) NOT NULL,
STATUS VARCHAR(10) NOT NULL,
EXPERIENCE VARCHAR(10) NOT NULL,
CONSTRAINT TRKMECHANIC_PKEY PRIMARY KEY(E#),
CONSTRAINT TRKMECHANIC_FKEY FOREIGN KEY(E#) REFERENCES TRKEMPLOYEE(E#))
I have attempted to write a function but keep getting a compile error in line 1 column 7. Can someone tell me why my code doesn't work? My code is as follows
CREATE OR REPLACE FUNCTION Verify()
IS DECLARE
E# TRKEMPLOYEE.E#%TYPE;
CURSOR C1 IS SELECT E# FROM TRKEMPLOYEE;
BEGIN
OPEN C1;
LOOP
FETCH C1 INTO EMPNUM;
IF(EMPNUM IN(SELECT E# FROM TRKMECHANIC )AND EMPNUM IN(SELECT E# FROM TRKDRIVER))
SELECT E#, NAME FROM TRKEMPLOYEE WHERE E#=EMPNUM;
ELSE
dbms_output.put_line(“OK”);
ENDIF
EXIT WHEN C1%NOTFOUND;
END LOOP;
CLOSE C1;
END;
/
Any help would be appreciated. Thanks.

You are creating a function but missing the RETURN declaration. If you don't want to return a result, the use create or replace procedure.
Additionally, if you don't have any parameters, remove the brackets () and the DECLARE keyword is not correct either.
The the way you check the tables is not really efficient. You can get the count of all employees violating your business constraint with a single query:
select emp.e#,
emp.name,
count(drv.e#) + count(mec.e#) as cnt
from trkemployee emp
left join trkdriver drv on drv.e# = emp.e#
left join trkmechanic mec on mec.e# = emp.e#
group by emp.e#, emp.name
having count(drv.e#) + count(mec.e#) > 1;
Additionally the EXIT WHEN C1%NOTFOUND; should be right after the FETCH statement. Otherwise you are staying in the loop even though the cursor didn't fetch anything.
If you take my simplified statement, you can loop once through all employees and print OK, nor Not OK depending on the count:
CREATE OR REPLACE procedure Verify
IS
empnum number(12);
cnt integer;
empname varchar(50);
CURSOR C1 IS
select emp.e#,
emp.name,
count(drv.e#) + count(mec.e#) as cnt
from trkemployee emp
left join trkdriver drv on drv.e# = emp.e#
left join trkmechanic mec on mec.e# = emp.e#
group by emp.e#, emp.name;
BEGIN
OPEN C1;
LOOP
FETCH C1 INTO empnum, empname, cnt;
EXIT WHEN C1%NOTFOUND;
if cnt > 1 then
dbms_output.put_line(to_char(empnum)||' NOK');
else
dbms_output.put_line(to_char(empnum)||' OK');
end if;
END LOOP;
CLOSE C1;
END;
/
Solving the problem without a stored procedure
I was thinking about a way how this business rule can be enforced with only constraints in the database:
create table trkemployee
(
E# NUMBER(12) NOT NULL,
NAME VARCHAR(50) NOT NULL,
DOB DATE ,
ADDRESS VARCHAR(300) NOT NULL,
HIREDATE DATE NOT NULL,
emp_type char(1) NOT NULL,
constraint trkemployee_pkey primary key(e#, emp_type),
constraint chk_emp_type check (emp_type in ('d','m'))
);
create table TRKDRIVER
(
e# number(12) not null,
emp_type char(1) default 'd' not null,
l# number(8) not null,
status varchar(10) not null,
constraint trkdriver_pkey primary key(e#),
constraint trkdriver_fkey foreign key(e#,emp_type) references trkemployee(e#, emp_type),
constraint check_drv_type check (emp_type = 'd')
);
create table trkmechanic
(
e# number(12) not null,
emp_type char(1) default 'm' not null,
l# number(8) not null,
status varchar(10) not null,
experience varchar(10) not null,
constraint trkmechanic_pkey primary key(e#),
constraint trkmechanic_fkey foreign key(e#,emp_type) references trkemployee(e#, emp_type),
constraint check_mec_type check (emp_type = 'm')
);
The idea is to include the employee type in its foreign key, and to make sure that the dependent tables cannot use the wrong type. When inserting a new trkemployee the type must be specified. The check constraint on the detail tables will reject any row with the wrong type.
To "move" an employee from one type to the other (if this is possible at all), the old detail row must be deleted first. Only then the employee's type can be changed to the other type. And finally the new detail could be inserted.

Okay, there's a lot wrong with this function.
As a_horse_with_no_name notes if you have no parameters then remove the () and by definition a function requires a RETURN statement.
However, that's not all:
You can't use a SELECT in a IF statement.
You have to put the result in a variable or reference it as part of
a cursor.
There's no need for the DECLARE block in a function or a procedure.
Your IF statement needs a THEN... But, I don't think you need this as you're only doing something in the ELSE.
You're fetching the results of the cursor into a non-existent variable.
I would hazard a guess that you want a procedure as I don't see what you could return. I would also guess that if you don't want to do anything with your first IF then you could put the other selects into the cursor.
Lastly I'm going to assume that you pass it the e# of the employee you want to check.
As all 3 tables are unique on e# you can use LEFT OUTER JOINS to put all your SQL in a single cursor
create or replace function verify ( Pemployee trkemployee.e#%type
) return varchar2 is
l_mechanic trkemployee.e#%type;
l_driver trkemployee.e#%type;
begin
-- Doing things in SQL is more efficient.
select m.e#, d.e#
into l_mechanic, l_driver
from trkemployee e
left outer join trkmechanic m
on e.e# = m.e#
left outer join trkdriver d
on e.e# = d.e#
;
if l_driver is not null and l_mechanic is not null then
return 'BAD';
else
return 'OK';
end if;
end;
/

Mixing the answers given by a_horse_with_no_name and Ben and then 'Simplifying' a little bit gives-
CREATE OR REPLACE FUNCTION Verify
return varchar2 IS
BEGIN
FOR c_rec in (select emp.e#,
count(drv.e#) + count(mec.e#) as cnt
from trkemployee emp
left join trkdriver drv on drv.e# = emp.e#
left join trkmechanic mec on mec.e# = emp.e#
group by emp.e#)
LOOP
if c_rec.cnt > 1 then
return ('BAD '||c_rec.e#);
else
return ('OK '||c_rec.e#);
end if;
END LOOP;
EXCEPTION
WHEN ....THEN
--as the wise man once said "Do some meaningful exception handling here"...
END;
/
Looks like an overkill to have to DECLARE, OPEN, FETCH and CLOSE a cursor.
OR a PROCEDURE like
CREATE OR REPLACE PROCEDURE Verify
IS
BEGIN
FOR c_rec in (select emp.e#,
count(drv.e#) + count(mec.e#) as cnt
from trkemployee emp
left join trkdriver drv on drv.e# = emp.e#
left join trkmechanic mec on mec.e# = emp.e#
group by emp.e#)
LOOP
if c_rec.cnt > 1 then
dbms_output.put_line('BAD '||c_rec.e#);
else
dbms_output.put_line('OK '||c_rec.e#);
end if;
END LOOP;
EXCEPTION
WHEN ....THEN
--as the wise man once said "Do some meaningful exception handling here"...
END;
/

Related

Why am I getting this error: "ORA-00922: missing or invalid option" after running a PL/SQL procedure?

I created a table Patient with some attributes, like p_name, p_surname, p_number... I would like to create a procedure to transfer a patient from this table Patient to another table (Patient_backup), case his "p_number" attribute has received an input, deleting it from the first table and remaining only in the second. The second table has the same structure of the first one. I have coded the procedure like that.
CREATE TABLE patient (
p_number VARCHAR2(10) NOT NULL,
p_name VARCHAR2(15),
p_surname VARCHAR2(15),
p_street VARCHAR2(20),
p_city VARCHAR2(15)
);
CREATE TABLE patient_backup (
p_number VARCHAR2(10) NOT NULL,
p_name VARCHAR2(15),
p_surname VARCHAR2(15),
p_street VARCHAR2(20),
p_city VARCHAR2(15)
);
CREATE [OR REPLACE] PROCEDURE transfer (p_number VARCHAR2)
AS
CURSOR k1 IS SELECT p_number FROM patient;
BEGIN
OPEN k1;
LOOP
FETCH k1 INTO p_number;
IF p_number IS NULL THEN
dbms_output.put_line('empty');
ELSE
INSERT INTO patient_backup (SELECT * FROM patient);
Execute Immediate 'Drop Table patient;';
END IF;
END LOOP;
CLOSE k1;
END transfer;
But when I run it,I get the error "ORA-00922: missing or invalid option". Could you help me with that? I wonder if the code is correct. I have read a material about PL/SQL, but the concepts were not connected to each other, so I just tried to gather everything together, and I hope it is correct. Could you help me to correct this code and make it work?
It's hard to tell where exactly the error is, but my guess is: remove the ; from inside the string for execute immediate.
But I think you want do not want to DROP the table - that removes the table completely from the database including all rows and its definition. It won't be accessible after that.
I think what you really want is to DELETE a row from that table, not remove the table completely.
Also: the whole loop is completely unnecessary (and inefficient). You can do that with two simple SQL statements:
insert into patient_backup
select *
from patient
where p_number = 42; --<< to pick one patient
delete from patient
where p_number = 42;
Putting that into a procedure:
CREATE PROCEDURE transfer (p_number_to_delete VARCHAR2)
AS
BEGIN
insert into patient_backup
select *
from patient
where p_number = p_number_to_delete;
delete from patient
where p_number = p_number_to_delete;
END transfer;
It's highly recommended to not use the name of a column as the name of a parameter. That's why I named the parameter p_number_to_delete (but p_number is a bad name for a column that isn't a number to begin with - but that's a different discussion)
I think you need to DECLARE your cursor before you define it.
In Your procedure code have some error
1.P_NUMBER input parameter cannot be used into statment
2.don't use semicolon inside the EXECUTE IMMEDIATE string
3. in loop statement you should use exit otherwise it will run
continuously
Here the code
CREATE OR REPLACE PROCEDURE TRANSFER (P_NUMBER IN VARCHAR2) AS
CURSOR K1 IS
SELECT P_NUMBER FROM PATIENT;
P_NUM PLS_INTEGER;
BEGIN
OPEN K1;
LOOP
FETCH K1 INTO P_NUM;
IF P_NUM IS NULL THEN
DBMS_OUTPUT.PUT_LINE('EMPTY');
ELSE
INSERT INTO PATIENT_BACKUP (SELECT * FROM PATIENT);
DELETE FROM PATIENT;
END IF;
EXIT WHEN P_NUM IS NULL;
END LOOP;
CLOSE K1;
END TRANSFER;

Use fields from another table as max-number-rows-with-type constrain in oracle

I have two tables:
CREATE TABLE users (
user_id INT(7) NOT NULL,
restricted_type VARCHAR(64) NOT NULL
)
CREATE TABLE type_restrictions (
name VARCHAR(64) NOT NULL,
restriction INT NOT NULL
)
I want to check on insert, that there are no more than restriction users with restricted_type = type_restriction.name.
At this point I'm inserting data with this query:
INSERT INTO users (user_id, restricted_type) SELECT <id>, <type> FROM DUAL
WHERE NOT EXISTS (
SELECT 1
FROM type_restrictions T
WHERE T.name = <type> AND T.restriction < (
SELECT COUNT(*)
FROM users U
WHERE U.user_id = <id> AND U.restricted_type = <type>)
)
But with two or more parallel queries it is possible to end up with more users with restricted_type than actual restriction for this type.
Is there any way to make such constraint work? (Also, I always insert only one row per query, if it helps)
You cannot use select ... in constraint. You cannot select from table which you are inserting into in normal trigger. What you can do? Materialized view (probably, I am not sure) or compound trigger. Here is my (working) try:
create or replace trigger trg_users_restrict
for insert on users compound trigger
type tt is table of number index by varchar2(5);
vt tt;
i varchar2(5);
v_max int;
before statement is
begin
for r in (select restricted_type, count(1) cnt from users group by restricted_type)
loop
vt(r.restricted_type) := r.cnt;
end loop;
end before statement;
after each row is
begin
begin
vt(:new.restricted_type) := vt(:new.restricted_type) + 1;
exception when no_data_found then
vt(:new.restricted_type) := 1;
end;
end after each row;
after statement is
begin
i := vt.first;
while i is not null loop
select nvl(max(restriction), 0) into v_max
from type_restrictions where name = i;
if vt(i) > v_max then
raise_application_error( -20001,
'maximum number exceeded for restriction type ' || i );
end if;
i := vt.next(i);
end loop;
end after statement;
end trg_users_restrict;
In before statement I grouped data from users table into collection. In after each row I increased proper values in collection for newly inserted row(s). In after statement I check if data in collection exceeds allowed ranges in table type_restrictions.
When two sessions insert concurent data then this which commits last causes exception.

Inserting into a table using a procedure only if the record doesn't exist yet

I have a table that i'm trying to populate via a plsql script (runs on plsql developer). The actual DML statement
is contained in a procedure inside a package. The procedure only inserts if the record doesn't exist yet.
It doesn't work. The part that checks for existence returns true after the first iteration of the script loop even if it doesn't actually exist in the table.
If i put the commit outside of the loop, nothing gets inserted at all and the existence checks return true for all iteration even if the table it empty.
When i try to simplify the insert with existence check to be in just one statement without the exception handling, i get the same outcome.
Please tell me what I'm doing wrong here.
CREATE OR REPLACE PACKAGE BODY some_package
IS
PROCEDURE add_to_queue(id IN NUMBER)
IS
pending_record VARCHAR2(1);
BEGIN
-- this part succeeds even if nothing matches the criteria
-- during the loop in the outside script
SELECT 'Y'
INTO pending_record
FROM dual
WHERE EXISTS (SELECT 'x' FROM some_queue smq
WHERE smq.id = id AND smq.status IS NULL);
EXCEPTION
WHEN NO_DATA_FOUND THEN
INSERT INTO some_queue (seqno, id, activity_date)
VALUES (some_sequence.nextval, id, SYSDATE);
WHEN OTHERS THEN
NULL;
END;
END some_package;
CREATE TABLE some_queue
(
seqno VARCHAR2(500) NOT NULL,
id NUMBER NOT NULL,
activity_date DATE NOT NULL,
status VARCHAR2(25),
CONSTRAINT some_queue_pk PRIMARY KEY (seqno)
);
-- script to randomly fill in the table with ids from another table
declare
type ids_coll_tt is table of number index by pls_integer;
ids_coll_table ids_coll_tt;
cursor ids_coll_cur is
select tab.id
from (select *
from ids_source_table
order by dbms_random.value ) tab
where rownum < 10;
begin
open ids_coll_cur;
fetch ids_coll_cur bulk collect into ids_coll_table;
close ids_coll_cur;
for x in 1..ids_coll_table.count
loop
some_package.add_to_queue(ids_coll_table(x));
commit; -- if this is here, the first iteration gets inserted
end loop;
-- commit; -- if the commit is done here, nothing gets inserted
end;
Note: I translated this code to be more generic for posting. Forgive me if there are any typos.
Update: even if i put everything inside the script and not use the package, i'm not able to properly check for existence and I get the same results.
I figured out the solution:
CREATE OR REPLACE PACKAGE BODY some_package
IS
PROCEDURE add_to_queue(p_id IN NUMBER)
IS
pending_record VARCHAR2(1);
BEGIN
-- this part succeeds even if nothing matches the criteria
-- during the loop in the outside script
SELECT 'Y'
INTO pending_record
FROM dual
WHERE EXISTS (SELECT 'x' FROM some_queue smq
WHERE smq.id = p_id AND smq.status IS NULL);
EXCEPTION
WHEN NO_DATA_FOUND THEN
INSERT INTO some_queue (seqno, id, activity_date)
VALUES (some_sequence.nextval, p_id, SYSDATE);
WHEN OTHERS THEN
NULL;
END;
END some_package;
changing the parameter name fixed it. I guess the compiler gets confused if it's the same name as the table field.
Don't name the parameter the same as the column (use a prefix like p_ or in_) and you can do it in a single statement if you use a MERGE statement self-joining on the ROWID pseudo-column:
CREATE OR REPLACE PACKAGE BODY some_package
IS
PROCEDURE add_to_queue(
in_id IN NUMBER
)
IS
BEGIN
MERGE INTO some_queue dst
USING ( SELECT ROWID AS rid
FROM some_queue
WHERE id = in_id
AND status IS NULL ) src
ON ( src.rid = dst.ROWID )
WHEN NOT MATCHED THEN
INSERT (seqno, id, activity_date)
VALUES (some_sequence.nextval, in_id, SYSDATE);
END;
END some_package;

Cast SYS_REFCURSOR to a PL/SQL Type

I have a stored procedure that calls a function that returns a SYS_REFCURSOR. The function returns a SYS_REFCURSOR because this function is also called from Java application and Java does not understand rowtype.
Here is my function.
function f_get_building(
p_building_id in T_BUILDING.ID%type
) return sys_refcursor
AS
v_cursor sys_refcursor;
BEGIN
open v_cursor for
select
BUILDING_ID,
CAMPUS_ID,
DELETE_FLAG,
max(EFFECTIVE_DATE),
END_DATE,
IMAGE_URL,
INSTITUTION_ID,
LOCAL_ID,
LOCATION_ID,
NAME
from V_BUILDING
where BUILDING_ID = p_building_id
group by
BUILDING_ID,
CAMPUS_ID,
DELETE_FLAG,
END_DATE,
IMAGE_URL,
INSTITUTION_ID,
LOCAL_ID,
LOCATION_ID,
NAME;
return v_cursor;
END f_get_building;
In another stored procedure I am also calling this function but having issues using it. Here is the stored procedure.
procedure sp_delete_building(
p_building_id in T_BUILDING.ID%type,
p_permanent_delete in boolean default false
)
AS
v_building_cur sys_refcursor;
v_building_rec V_BUILDING%rowtype;
BEGIN
-- if permanment delete
if p_permanent_delete = true
then
delete from T_BUILDING where ID = p_building_id;
-- otherwise perform soft delete
else
-- lookup
v_building_cur := f_get_building(p_building_id);
-- if cursor is empty there is nothing to do
if v_building_cur%notfound then
return;
end if;
fetch v_building_cur into v_building_rec; -- this line is where the error happens
-- if its already deleted nothing to do
if v_building_rec.DELETE_FLAG = 'Y'
then
return;
else
insert into T_BUILDING_ATTRIBUTE(BUILDING_ID,EFFECTIVE_DATE,DELETE_FLAG,
IMAGE_URL,LOCATION_ID,NAME)
values (v_building_rec.BUILDING_ID,current_timestamp,'Y',v_building_rec.IMAGE_URL
,v_building_rec.LOCATION_ID,v_building_rec."NAME");
end if;
end if;
END sp_delete_building;
I am getting the following PL/SQL stacktrace.
ORA-01722: invalid number
ORA-06512: at "OBR.PKG_BUILDING", line 114
ORA-06512: at line 8
Forgive my ignorance, this is my first project using PL/SQL, I would classify myself as a Java developer, not a database developer. Since I am selecting everything from V_BUILDING I expected I would just be able to case it as a rowtype inside the stored procedure. How can I use my function inside my stored procedure?
Update:
Here is the create statement for V_BUILDING
CREATE OR REPLACE FORCE VIEW "OBR"."V_BUILDING" ("BUILDING_ID", "LOCAL_ID", "INSTITUTION_ID", "EFFECTIVE_DATE", "END_DATE", "DELETE_FLAG", "CAMPUS_ID", "LOCATION_ID", "IMAGE_URL", "NAME") AS
SELECT
ba.BUILDING_ID,
b.LOCAL_ID,
b.INSTITUTION_ID,
ba.EFFECTIVE_DATE,
NVL(MIN(ba2.EFFECTIVE_DATE - INTERVAL '0.000001' SECOND),TO_DATE('31-DEC-9999', 'DD-MON-YYYY')) AS END_DATE,
ba.DELETE_FLAG,
ba.CAMPUS_ID,
ba.LOCATION_ID,
ba.IMAGE_URL,
ba.NAME
FROM
T_BUILDING b
INNER JOIN T_BUILDING_ATTRIBUTE ba
ON b.ID = ba.BUILDING_ID
LEFT JOIN T_BUILDING_ATTRIBUTE ba2
ON ba.BUILDING_ID = ba2.BUILDING_ID
AND ba2.EFFECTIVE_DATE > ba.EFFECTIVE_DATE
GROUP BY
ba.BUILDING_ID,
b.LOCAL_ID,
b.INSTITUTION_ID,
ba.EFFECTIVE_DATE,
ba.DELETE_FLAG,
ba.CAMPUS_ID,
ba.LOCATION_ID,
ba.IMAGE_URL,
ba.NAME
ORDER BY ba.BUILDING_ID, ba.EFFECTIVE_DATE DESC;
Update 2:
Here is a screenshot of the types in the view
CAMPUS_ID - NUMBER(10)
LOCATION_ID - NUMBER(10)
IMAGE_URL - VARCHAR(500)
NAME - VARCHAR(255)
BUILDING_ID - NUMBER(10)
LOCAL_ID - VARCHAR(30)
INSTITUTION_ID - NUMBER(10)
EFFECTIVE_DATE - TIMESTAMP(6)
END_DATE - TIMESTAMP (6)
DELETE_FLAG - CHAR(1)
Here are the list of columns and their datatypes as returned by the view and the ref cursor:
LIST OF COLS FROM VIEW DATATYPE FROM VIEW LIST OF COLS FROM CURSOR DATATYPE FROM CURSOR
---------------------- ------------------ ------------------------ --------------------
BUILDING_ID NUMBER(10) BUILDING_ID NUMBER(10)
LOCAL_ID VARCHAR(30) CAMPUS_ID NUMBER(10)
INSTITUTION_ID NUMBER(10) DELETE_FLAG CHAR(1)
EFFECTIVE_DATE TIMESTAMP(6) max(EFFECTIVE_DATE) TIMESTAMP(6)
END_DATE TIMESTAMP(6) END_DATE TIMESTAMP(6)
DELETE_FLAG CHAR(1) IMAGE_URL VARCHAR(500)
CAMPUS_ID NUMBER(10) INSTITUTION_ID NUMBER(10)
LOCATION_ID NUMBER(10) LOCAL_ID VARCHAR(30)
IMAGE_URL VARCHAR(500) LOCATION_ID NUMBER(10)
NAME VARCHAR(255) NAME VARCHAR(255)
They are not the same, yet by using the V_BUILDING%ROWTYPE in your sp_delete_building procedure, you're treating the ref cursor results as if the column order is the same as that of the view.
You can see that there are several mismatches between the datatypes of the view and the cursor select lists - it's probably the "LOCATION_ID/LOCAL_ID" mismatch that's causing the invalid number error that you're seeing.
You either need to change the order of your ref cursor so that the list of columns is returned in the same order as that of the view, or to explicitly list the columns of the cursor in the v_building_rec record type.
As an aside, you should give your max(EFFECTIVE_DATE) column in the refcursor an alias.

select inside loop oracle

I have written a stored procedure with a query inside a loop.
This query sets the records into a custom data type of the type RECORD something like
TYPE finalrecord
IS
RECORD
(
corh VARCHAR2(1),
myspissueid NUMBER(10),
mypkey VARCHAR2(10),
mycreated DATE,
myprevstepname VARCHAR2(10),
mystepname VARCHAR2(10),
mystorypoints NUMBER(2) );
myfinalrecord finalrecord;
The for loop goes like
for vh in (select * from table1 where abc=3)
loop
select steps.current_or_history,
steps.issueid,
steps.pkey,
steps.created,
steps.prev_step_name,
steps.step_name,
steps.story_points
from steps where column1 = 'xyz' and column2=vh.column2;
end loop;
Every time the inner loop is executed, the SELECT statement would return more than one record. I want to add this record to a main variable (as a collection..but varray or nested table or associative array) and return that variable as a output of the stored procedure.
Any idea?
declare
type t is table of finalrecord;
my_table t;
begin
for vh in (select * from table1 where abc = 3) loop
execute immediate 'select finalrecord(steps.current_or_history,
steps.issueid,
steps.pkey,
steps.created,
steps.prev_step_name,
steps.step_name,
steps.story_points)
from steps where column1 = ''xyz'' and column2=vh.column2' bulk
collect
into my_table;
end loop;
end;
you can try this if it works you can also create procedure...

Resources