select inside loop oracle - 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...

Related

pl sql insert into within a procedure and dynamic variables

I need some help with PL SQL. I have to insert some data into table. Another application is calling my procedure and caller is passing few details which I also need to insert into my table.
here is the syntax I am struggling with:
PROCEDURE invform_last2orders_item_insert( p_userId IN NUMBER
,p_accountId IN NUMBER
,p_site_Id IN NUMBER
,p_return_message OUT VARCHAR2) IS
Begin
insert into mytable
(p_userId , p_accountId , p_site_Id , sku, description, 'Cart', 1, unitId)
as
select sku, description, unitId
from mycatalogtable where site_id= p_site_Id ) ;
End;
Can you help me with syntax? I need to pass three parameters from called in parameter and some values returned from select query. How can I achieve this?
thank you for your help.
That would be something like this; see comments within code:
PROCEDURE invform_last2orders_item_insert
( p_userId IN NUMBER
,p_accountId IN NUMBER
,p_site_Id IN NUMBER
,p_return_message OUT VARCHAR2)
IS
Begin
insert into mytable
-- first name all columns you'll be inserting into; I don't know their
-- names so I just guessed
(userid,
accountid,
siteid,
sku,
description,
col1,
col2,
unitid
)
-- if you were to insert only values you got via parameters, you'd use the
-- VALUE keyword and insert those values separately.
-- As some of them belong to a table, use SELECT statement
(select p_userid,
p_accountid,
p_siteid,
c.sku,
c.description,
'Cart',
1,
c.unitid
from mycatalogtable c
where c.site_id = p_site_Id
);
-- I don't know what you are supposed to return; this is just an example
p_return_message := sql%rowcount || ' row(s) inserted';
End;
in your select statement you should have the same number of columns as you are inserting into the table, your code should be something like this example,
DECLARE
userid varchar2(20) := 'Jack';
Begin
INSERT INTO mytable (SELECT userid, SPORT from OLYM.OLYM_SPORTS);
commit;
end;

Oracle put resultset into variable in FORALL

I have the following plsql block
declare
TYPE t_mds_ids IS TABLE OF mds.id%TYPE;
l_mds_ids t_mds_ids;
l_mds_parents t_mds_parents;
begin
SELECT id BULK COLLECT INTO l_mds_ids FROM mds;
FORALL indx IN l_mds_ids.FIRST .. l_mds_ids.LAST
select l_mds_ids(indx), ch.id_employee_parent
into l_mds_parents
FROM hierarchy_all ch
CONNECT BY ch.id_employee = prior ch.id_employee_parent
START WITH ch.id_employee = l_mds_ids(indx);
EXECUTE IMMEDIATE 'truncate table mds_hierarchy_all';
insert into mds_hierarchy_all
select * from l_mds_parents;
end;
t_mds_parents declared as
create or replace type r_mds_parents as object (
id_mds number(5,0),
id_employee number(5,0)
);
/
create or replace type t_mds_parents as table of r_mds_parents;
/
And I get an exception ORA-00947: not enough values
I really need to put the resultset of multiple rows into variable of TABLE TYPE on each iteration of FORALL loop. I can't use BULK COLLECT into l_mds_parents as it's restricted inside of FORALL.
Is there only solution to use temporary table instead of table variable?
I don't think you can do this with forall. You could use nested loops:
declare
TYPE t_mds_ids IS TABLE OF mds.id%TYPE;
l_mds_ids t_mds_ids;
l_mds_parents t_mds_parents;
begin
SELECT id BULK COLLECT INTO l_mds_ids FROM mds;
l_mds_parents := NEW t_mds_parents();
FOR indx IN l_mds_ids.FIRST .. l_mds_ids.LAST LOOP
FOR rec IN (
select l_mds_ids(indx) as id_employee, ch.id_employee_parent
FROM hierarchy_all ch
CONNECT BY ch.id_employee = prior ch.id_employee_parent
START WITH ch.id_employee = l_mds_ids(indx)
) LOOP
l_mds_parents.extend();
l_mds_parents(l_mds_parents.COUNT)
:= NEW r_mds_parents (rec.id_employee, rec.id_employee_parent);
END LOOP;
END LOOP;
EXECUTE IMMEDIATE 'truncate table mds_hierarchy_all';
insert into mds_hierarchy_all
select * from table(l_mds_parents);
end;
/
But you don't need to use PL/SQL at all; use a single hierarchical query, or probably more simply here, recursive subquery factoring:
insert into mds_hierarchy_all /* (id_mds, id_employee) -- better to list columns */
with rcte (id_mds, id_employee) as (
select m.id, ha.id_employee_parent
from mds m
join hierarchy_all ha on ha.id_employee = m.id
union all
select r.id_mds, ha.id_employee_parent
from rcte r
join hierarchy_all ha on ha.id_employee = r.id_employee
)
select * from rcte;
db<>fiddle with some made-up data.

Using %ROWTYPE in Procedure in Oracle

I am trying to use %ROWTYPE in my code and trying to insert value into it using a cursor for loop as below :
CREATE or REPLACE PROCEDURE test_acr (
PROJECT_START_DATE IN DATE,USER_ID IN VARCHAR2)
IS TYPE acr_new IS TABLE OF acr_projected_new%ROWTYPE
INDEX BY SIMPLE_INTEGER;
acr_projected_neww acr_new;
CURSOR WEEKENDING_DATE IS
SELECT WEEKEND_DATE
FROM weekending_table
WHERE WEEKEND_DATE BETWEEN PROJECT_START_DATE AND sysdate;
BEGIN
FOR WEEKEND_DATE_REC in WEEKENDING_DATE LOOP
INSERT INTO acr_projected_neww(WEEKEND_DATE,USERID,TIMESTAMP,ACR_PROJECTED,artificial_id)
SELECT WEEKEND_DATE_REC.WEEKEND_DATE,USER_ID,sysdate,
(select sum(acr_h.activity_impact)
FROM ACR_HISTORY acr_h
LEFT JOIN Activity act on act.activity_id = acr_h.activity_id
LEFT JOIN Activity_Date_Duration act_d on act_d.activity_id = act.activity_id),1 from dual;
END LOOP;
END test_acr;
When i try to run this i get below error:
Error(54,14): PL/SQL: ORA-00942: table or view does not exist
My Requirement is to create virtual table and insert the data into it using cursor for loop if not then any other means is appreciated.
Please help it will be greatly appreciated!
Looks like table name is incorrect in your INSERT statement.
You need not use two queries. Instead, define your cursor such that it has all the columns of the records you want to store in the collection. Then use BULK COLLECT INTO instead of insert as shown. Define your collection as table of cursor%ROWTYPE.
CREATE OR REPLACE PROCEDURE test_acr
IS
CURSOR WEEKENDING_DATE
IS
SELECT a.col1,a.col2,b.col1,b.col2 ,c.col1
from table1 a , table2 b LEFT JOIN table3 c; --Here include all the data from the required tables.
TYPE acr_new
IS
TABLE OF WEEKENDING_DATE%ROWTYPE;
acr_projected_neww acr_new;
BEGIN
FETCH WEEKENDING_DATE BULK COLLECT INTO acr_projected_neww;
END test_acr;
If you need to manipulate your data (access each row - then see script below, this is sequential access (inserts) into nested table (PL/SQL collection)
CREATE or REPLACE PROCEDURE test_acr (PROJECT_START_DATE IN DATE,USER_ID IN VARCHAR2)
IS
TYPE acr_new
IS TABLE OF acr_projected_new%ROWTYPE; // nested table, notice absence of INDEX by clause
acr_projected_neww acr_new := acr_projected_neww(); // instantiation, constructor call
CURSOR WEEKENDING_DATE IS
SELECT WEEKEND_DATE
FROM weekending_table
WHERE WEEKEND_DATE BETWEEN PROJECT_START_DATE AND sysdate;
BEGIN
FOR WEEKEND_DATE_REC in WEEKENDING_DATE
LOOP
acr_new.extend; // make room for the next element in collection
acr_new(acr_new.last) := WEEKEND_DATE_REC; // Adding seq. to the end of collection
...
END LOOP;
END test_acr;
However if you want to BULK INSERT (there is no requirement to get access to each row) see script below
CREATE or REPLACE PROCEDURE test_acr (PROJECT_START_DATE IN DATE,USER_ID IN VARCHAR2)
IS
TYPE acr_new IS TABLE OF acr_projected_new%ROWTYPE; // no INDEX BY clause
acr_projected_neww acr_new = acr_new(); // Notice constructor call
CURSOR WEEKENDING_DATE IS
SELECT WEEKEND_DATE
FROM weekending_table
WHERE WEEKEND_DATE BETWEEN PROJECT_START_DATE AND sysdate;
BEGIN
FETCH WEEKENDING_DATE BULK COLLECT INTO acr_projected_neww;
...
END LOOP;
END test_acr;
I have used temporary table outside my procedure:
CREATE GLOBAL TEMPORARY TABLE "MY_TEMP"
( "WEEKEND_DATE" DATE,
"USERID" VARCHAR2(255 BYTE),
"TIMESTAMP" TIMESTAMP (6),
"ACR_PROJECTED" NUMBER,
"ARTIFICIAL_ID" NUMBER
) ON COMMIT PRESERVE ROWS ;
i have just used the above temporary table inside my Procedure
create or replace PROCEDURE GET_ACR_TEST(
PROJECT_START_DATE IN DATE ,
USER_ID IN VARCHAR2,
) AS
CURSOR WEEKENDING_DATE IS
SELECT WEEKEND_DATE, DURATION
FROM weekending_table where WEEKEND_DATE between PROJECT_START_DATE and sysdate;
Begin
FOR WEEKEND_DATE_REC in WEEKENDING_DATE
LOOP
insert into MY_TEMP (WEEKEND_DATE,USERID,TIMESTAMP,ACR_PROJECTED,artificial_id)
select WEEKEND_DATE_REC.WEEKEND_DATE,USER_ID,sysdate,
(select sum(acr_h.activity_impact)
from ACR_HISTORY acr_h
LEFT JOIN Activity act on act.activity_id = acr_h.activity_id
LEFT JOIN Activity_Date_Duration act_d on act_d.activity_id = act.activity_id),1
from dual;
End Loop;
END GET_ACR_TEST;
The above method is working.
Thank you all for your comments!

bulk collect into table type of objects

I got en error when attempting to use a BULK COLLECT statement ORA-00947: not enough values for table of objects.
Error occurs at the line from (select jta.nobject_id,
CREATE OR REPLACE TYPE "T_PPW_WORK" as object
(
nObjectKey number,
cJobType varchar2(500),
dPlanStart date,
dPlanEnd date,
cExecutor varchar2(500),
cComment varchar2(4000)
)
CREATE OR REPLACE TYPE "T_PPW_WORK_TABLE" as table of T_PPW_WORK;
function getPlannedOverdueJobs(in_nPlanKey number) return T_PPW_WORK_TABLE is
l_oWorks T_PPW_WORK_TABLE;
l_oWork T_PPW_WORK;
begin
select * bulk collect
into l_oWorks
from (select jta.nobject_id,
jt.cjobtype_name,
jta.dactual_start,
jta.dactual_finish,
st.familiya,
jta.ccomment
from ppw_jobtype_assign jta
left join pgts_sotrudnik st
on jta.nworkerid = st.npgts_sotrudnikkey
join ppw_jobtype jt
on jta.njobtype_id = jt.njobtype_key);
return l_oWorks;
end getPlannedOverdueJobs;
what is the reason?
select * bulk collect
into l_oWorks
from (select t_ppw_work(jta.nobject_id,
jt.cjobtype_name,
jta.dactual_start,
jta.dactual_finish,
st.familiya,
jta.ccomment)
from ppw_jobtype_assign jta
left join pgts_sotrudnik st
on jta.nworkerid = st.npgts_sotrudnikkey
join ppw_jobtype jt
on jta.njobtype_id = jt.njobtype_key);
You need to convert your result set using your defined object type (t_ppw_work) first.
You can do something like below instead.
CREATE OR REPLACE EDITIONABLE TYPE "F_OBJ" AS OBJECT (
Employee_name VARCHAR2(100),
Employee_id VARCHAR2 ( 100 ))
CREATE OR REPLACE EDITIONABLE TYPE "F_TAB" as table of F_OBJ
create or replace function "fname"
return f_tab
is
l_f_tab f_tab;
begin
SELECT f_obj(employee_name, employee_id) bulk collect into f_tab from employee_table;
return f_tab;
end;

Converting oracle query into user defined types in pl/sql

I have a select query on a relational table in a plsql procedure.
I want to convert the results of this query into a user defined type object to return via odp.net.
How would I go about doing this?
(this is from one of my other post today)
this is a walkthrough on getting started: http://www.oracle.com/technology/obe/hol08/dotnet/udt/udt_otn.htm
while this is a bit more detailed: http://download.oracle.com/docs/html/E10927_01/featUDTs.htm
but the real meat & potatoes are already installed on your computer after you install ODP in the Samples directory: %ORA_HOME%\product\11.1.0\client_1\odp.net\samples\2.x\UDT
but the pl/sql side of things:
First create the singleton udt to handle one row at a time
CREATE TYPE TESTTYPE IS OBJECT(COLA VARCHAR2(50) , COLB NUMBER(10) );
create or replace procedure GetTestType(lTestType OUT NOCOPY TESTTYPE)
IS
BEGIN
SELECT TESTTYPE('ValA',123)
INTO LTESTTYPE
FROM DUAL ;
END GetTestType ;
follow the directions in the above links to get the .net side insynch
NOW FOR A COLLECTION:
CREATE TYPE TESTTYPETABLE IS TABLE OF TESTTYPE ;
CREATE OR REPLACE PROCEDURE GETTESTTYPETABLE(lTestTypeTable OUT NOCOPY TestTypeTable)
IS
BEGIN
SELECT TESTTYPE(COLA,COLB)
bulk collect INTO lTestTypeTable
FROM (
SELECT 'ValA' COLA ,123 COLB
FROM DUAL
UNION
SELECT 'ValB' COLA ,234 COLB
FROM DUAL
UNION
SELECT 'Valc' COLA ,456 COLB
FROM DUAL
) ;
END GETTESTTYPETABLe;
then in the .net side of things this will effectively be a value of TESTTYPE()
Now to save you some time you can use the RETURNING clause on INSERT/UPDATE/DELETES
as such
create table testTable (colA varchar2(50) , colB number(10) );
CREATE SEQUENCE TESTSEQ START WITH 1 NOCACHE;
DECLARE
lTestTypeTable TestTypeTable ;
BEGIN
UPDATE TESTTABLE
SET
COLA = '1' ,
COLB = 'a'
WHERE COLA IS NULL
RETURNING TESTTYPE(COLA,COLB) --NOTE IF YOU HAVE ONE ROW YOU MAY DROP THE BULK COLLECT AND PUT IT INTO THE SINGLE ROW TYPE
BULK COLLECT INTO
lTestTypeTable
;
END ;
/
DECLARE
lTestType TestType;
BEGIN
INSERT INTO TESTTABLE(COLA, COLB)
VALUES ('BBB' , testSeq.NEXTVAL )
RETURNING TESTTYPE(COLA,COLB)
INTO
lTestType
;
DBMS_OUTPUT.PUT_LINE('MY NEW SEQUENCE # IS SET TO ' || lTestType.COLB) ;
END ;
/
unfortunately it seems that you cannot do a
insert into TT ... SELECT * from .. RETURNING Type(x,y) BULK COLLECT INTO lVariable;
so instead of rote COPING FROM THIS SITE, IT TELLS OF A "work-around" TO GET THE BULK COLLECT TO WORK IN AN INSERT STATEMENT
http://www.oracle-developer.net/display.php?id=413

Resources