Bulk collection PL/SQL table
Hi all,
10g version 10.2.0.1
What approach can I take to accomplish the following.
I need to build a collection based on the result set of two SQL statements within a loop.
Example:
FUNCTION( get_info )IS
RETURN retrieval_pkg_public_ty
PIPELINED
TYPE ret_tab IS TABLE OF ret_rec;
FOR i IN 1 .. 2
LOOP
SELECT...
BULK COLLECT into ret_tbl
FROM(SELECT...
FROM(SELECT..
quite a large SQL statement...
WHERE
x = parameter_value, --parameter changes on based on i values
y = parameter_value, --parameter changes on based on i values
END LOOP;
FOR i IN ret_tbl.FIRST..ret_tbl.LAST
LOOP
PIPE ROW...
END LOOP;
I can use a global temporary table to hold the results of each loop and them select from gtt, however I would prefer to use a table function.
thanks
Mark
user1602736 wrote:
Currently, I have a procedure that is called within a package that returns a SYS_REFCURSOR.
Current code in procedure is
FOR i IN 1..2
LOOP
INSERt INTO gtt
END LOOP;Why not simply populate the GTT using an INSERT INTO gtt SELECT ... FROM source WHERE .. ?
I wanted to avoid creating a gtt to accomplish above.Why? What problems with this GTT approach do you think there are?
The cursor only returns around 50 records. The record has around 20 data fieldsRemember that if you store this as a PL/SQL collection (there's no such thing as PL "+table+"), this collection resides in expensive private process memory (the PGA). If there a 100 sessions using this code, then there will be a 100 copies of this collection.
On the other hand, a GTT does not reside in expensive private memory. And it can scale to a 1000 rows in future, without affecting performance (remember that GTTs can be indexed - collections not). For a collection, you will pay an excessive price in memory for keeping that 1000 rows in the PGA.
GTTs are not a bad thing. Collections are not a bad thing. They are tools for addressing specific problems. Your task is to select the right tool for the job. Caching SQL row data in a PL/SQL collection is almost never the right tool for the job, as it requires private process memory and uses a very simplistic data structure (does not support indexes and so on).
Similar Messages
-
How to improve performance using bulk collects with plsql tables or arrays
Hi All,
my procedure is like this
declare
cursor c1 is select ----------------------
begin
assigning to variables
validations on that variables
--50 validations are here --
insert into a table
end;
we have created indexes on primary keys,
i want to use
DECLARE
CURSOR a_cur IS
SELECT program_id
FROM airplanes;
TYPE myarray IS TABLE OF a_cur%ROWTYPE;
cur_array myarray;
BEGIN
OPEN a_cur;
LOOP
FETCH a_cur BULK COLLECT INTO cur_array LIMIT 100;
***---------can i assign cursor data to the plsql table variables or array***
***validate on the pl sql variable as---***
i
nsert into a table
EXIT WHEN a_cur%NOTFOUND;
END LOOP;
CLOSE a_cur;
END;
Edited by: Veekay on Oct 21, 2011 4:28 AMFastest way often is this:
insert /*+append */
into aTable
select * from airplanes;
commit;The select and insert part can even be done in parallel if needed.
However if the oparation is complex or the dataset is very very very very very large or the programmer is decent but not excellent then the bulk approach should be considered. It is often a pretty stable and linear scaling approach.
The solution depends a little on the database version.
LOOP
FETCH a_cur BULK COLLECT INTO cur_array LIMIT 100;
EXIT WHEN a_cur.count = 0;
forall i in a_cur.first.. a_cur.last
insert into aTable (id)
values (a_cur(i));
END LOOP;
...If you have more then one column then you might need a single collection for each column. Other possibilities depend on the db version.
Also: do not exit using a_cur%NOTFOUND. This is wrong! You might loose records from the end of the data set. -
Error while doing Bulk Collect to a table type
I'm using a Table type to accumulate resultset from a loop and finally return the records in the table type as a ref cursor to the front end.
But when I'm using Bult collect to insert into the table type object it keeps throwing an error
'PLS-00597: expression 'TAB_CALENDAR_AVAIL_RESULTSET' in the INTO list is of wrong type'. Can someone help me to let me know what could be the reason for this error. I'm not able to proceed further, please help.
Here is the code.
CREATE OR REPLACE PACKAGE hotel
AS
TYPE calendar_cursor IS REF CURSOR;
TYPE type_calendar_avail is RECORD(
HOTEL_ID AVAILABILITY_CALENDAR.hotel_id%TYPE,--varchar2(4), --AVAILABILITY_CALENDAR.hotel_id%TYPE,
AVAIL_DATE AVAILABILITY_CALENDAR.AVAIL_DATE%TYPE ,
TOTAL_COUNT number
TYPE type_calendar_avail_resultset IS TABLE OF type_calendar_avail;
tab_calendar_avail_resultset type_calendar_avail_resultset ; -- declare variable of type type_calendar_avail_resultset
PROCEDURE sp_get_calendar_results (
sallhotelswithavaildate VARCHAR2,
ilengthofstay NUMBER,
sorcowner VARCHAR2,
all_unittypes VARCHAR2, --DBMS_SQL.VARCHAR2S
calendar_resultset OUT calendar_cursor
-- tab_calendar_avail_resultset out type_calendar_avail_resultset
PROCEDURE sp_get_calendar_results (
sallhotelswithavaildate VARCHAR2,
ilengthofstay NUMBER,
-- ivariant NUMBER,
sorcowner VARCHAR2,
all_unittypes VARCHAR2, --DBMS_SQL.VARCHAR2S
calendar_resultset OUT calendar_cursor
AS
sbuf VARCHAR2 (200);
sepr VARCHAR2 (1);
shotelwithdate VARCHAR2 (200);
shotelid VARCHAR2 (10);
savaildate VARCHAR2 (8);
sactualavaildate VARCHAR2 (8);
pos NUMBER;
istart NUMBER;
sstartdate VARCHAR2 (8);
senddate VARCHAR2 (8);
squery VARCHAR2 (32767) := '';
sunittypecond VARCHAR2 (500) := '';
sunitdesccond VARCHAR2 (500) := '';
v_unit_cond a_unit_cond;
tempunitcond VARCHAR2 (50) := '';
BEGIN
istart := 1;
LOOP
tempunitcond := hotel.stringtokenizer (all_unittypes, istart, '|');
IF tempunitcond IS NOT NULL
THEN
v_unit_cond (istart) := tempunitcond;
istart := istart + 1;
END IF;
EXIT WHEN tempunitcond IS NULL;
END LOOP;
sunitdesccond := hotel.get_unit_description_cond (v_unit_cond);
DBMS_OUTPUT.put_line ('unit description : ' || sunitdesccond);
sbuf := sallhotelswithavaildate;
sepr := '|';
istart := 1;
LOOP
shotelwithdate := hotel.stringtokenizer (sbuf, istart, sepr);
EXIT WHEN shotelwithdate IS NULL;
shotelid :=
SUBSTR (shotelwithdate, 1, INSTR (shotelwithdate, ',') - 1);
savaildate :=
SUBSTR (shotelwithdate, INSTR (shotelwithdate, ',') + 1);
squery :=
' SELECT MIN (ad.avail_date) '
|| ' FROM wvo_fonres.fpavail_daily ad'
|| ' WHERE ad.hotel_id = '
|| shotelid
|| ' AND ad.days_left >= '
|| ilengthofstay
|| ' AND ad.avail_date >= '
|| savaildate;
IF UPPER (sorcowner) = 'N'
THEN
squery :=
squery
|| ' AND ad.ORC_TYPE != ''R'' and ad.ORC_TYPE != ''P'' and ad.ORC_TYPE != ''E'' ';
END IF;
squery := squery || ' AND ( ' || sunitdesccond || ') ';
EXECUTE IMMEDIATE squery
INTO sactualavaildate;
DBMS_OUTPUT.put_line ('Actual available Date: ' || sactualavaildate);
hotel.sp_get_startdate_enddate (sactualavaildate,
--ivariant,
sstartdate,
senddate
sunittypecond := hotel.get_unittype_cond (v_unit_cond, sorcowner);
-- execute immediate
squery :=
'select HOTEL_ID, AVAIL_DATE, ' || sunittypecond || ' AS TOTAL_COUNT '
|| ' FROM AVAILABILITY_CALENDAR A '
|| 'WHERE '
|| 'AVAIL_DATE >= '''
|| sstartdate
|| ''' '
|| 'AND '
|| 'AVAIL_DATE <= '''
|| senddate
|| ''' '
||'AND '
|| 'A.HOTEL_ID IN ('
|| shotelid
|| ') '
|| 'AND ('
|| sunittypecond
|| '> 0) '
|| -- where total available count of unit type is greater than 0
' ORDER BY AVAIL_DATE'; --order clause
open calendar_resultset for squery;
fetch calendar_resultset BULK COLLECT INTO tab_calendar_avail_resultset;
istart := istart + 1;
END LOOP;
COMMIT;
EXCEPTION
WHEN NO_DATA_FOUND
THEN
NULL;
WHEN OTHERS
THEN
DBMS_OUTPUT.put_line
(SQLERRM (SQLCODE));
RAISE;
END sp_get_calendar_results;
END hotel;
/1. put tags [co[/b][b]de] and [co[/b][b]de] around your code, so it's readable
B. what does "hotel.get_unittype_cond (v_unit_cond, sorcowner)" actually retun?
and third, try this for the array declaration:
tab_calendar_avail_resultset type_calendar_avail_resultset := type_calendar_avail_resultset ; () ; -
Error in bulk collect into nested table
I keep getting an error while trying to compile this line:
fetch c_juros bulk collect into wrk_juros_plano(p_ind_segreg);
LINE/COL ERROR
0/0 PLS-00801: internal error [74306]When i put that single line into comments it goes fine. Sure it doesn't do what I want.
The data structure i use is as follows:
cursor c_juros(p_ind_segreg in varchar2) is
select (((power(1 + (i.prc_juros_atuari_ano / 100), 1 / 12) - 1) * 100) / 100) prc_juros_efetiv_mes,
i.dat_inic_vigenc,
(nvl(i.dat_fim_vigenc, sysdate) + 1) dat_fim_vigenc,
i.ind_segreg
from v_indexador_taxa_atuarial i
where i.ind_segreg = p_ind_segreg
order by i.dat_inic_vigenc;
type t_juros_plano is table of c_juros%rowtype;
type t_tab_juros_plano is table of t_juros_plano index by binary_integer;
wrk_juros_plano t_tab_juros_plano;the code goes like this:
begin
if not(wrk_juros_plano.exists(p_ind_segreg))
then
if c_juros%isopen
then
close c_juros;
end if;
open c_juros(p_ind_segreg);
wrk_juros_plano(p_ind_segreg) := t_juros_plano();
fetch c_juros bulk collect into wrk_juros_plano(p_ind_segreg);
end if;
...p_ind_segreg is my input parameter, that should be the index of the array.
The purpose is to create the parameter indexed element if it doesn't already exist, fetching it
from the cursor, that defines a nested table.
I tried removing the initialization line to no effect, among other things.Ok, I just found out a way around it. It works, but that error is probably a bug, cause workarounds are not really cute.
I declared a nested table compatible with the element from the associative array:
wrk_juros t_juros_plano;and chaged that line that was causing the error
fetch c_juros bulk collect into wrk_juros_plano(p_ind_segreg);for
fetch c_juros bulk collect into wrk_juros;
wrk_juros_plano(p_ind_segreg) := wrk_juros;Awesome =\ -
Dynamic sql with dynamic bulk collection variable
Hi,
I am facing the issue while bulk collecting dynamic sql query data into dynamic variable.
Eg:
query1:= << dynamic select query>>
Execute immediate query1 bulk collect into Dynamic_varibale;
here dynamic_varible is pl/sql table type with 1 column.
How do i declare "dynamic_variable" here????
please suggest...create type t_id is table of number
SQL> create type t_id is table of number
2 /
Type created.
SQL> declare
2
3 v_tid t_id;
4 v_results sys_refcursor;
5
6 v_employee_id number;
7 v_name varchar2(100);
8
9 v_sql varchar2(1000);
10
11
12 begin
13 v_tid := t_id(7902,7934);
14
15 --
16
17
18 v_sql := 'select empno, ename from scott.emp ' ||CHR(10)
19 || 'where empno in (select column_value from table(cast(:v_tid as
t_id)))';
20
21 dbms_output.put_line(v_sql);
22 dbms_output.put_line('----------');
23
24 open v_results for v_sql using v_tid;
25
26
27 IF v_results IS NOT NULL
28 THEN
29 LOOP
30 FETCH v_results
31 INTO v_employee_id, v_name;
32
33 EXIT WHEN (v_results%NOTFOUND);
34 dbms_output.put_line(v_name);
35 END LOOP;
36
37 IF v_results%ISOPEN
38 THEN
39 CLOSE v_results;
40 END IF;
41 END IF;
42
43 end;
44 /
select empno, ename from scott.emp
where empno in (select column_value from
table(cast(:v_tid as t_id)))
FORD
MILLER -
Hi there, need help, is it a right way of using bulk collect here? As I could not get the correct result.
The problem is the 'where clause' is only taking 'SEAEGO_CC_FAMILYMODEL_INFO_ENCRYPTION_TYPE' column name
to output but not for the rest of columns. The output given is only 3 records from 'SEAEGO_CC_FAMILYMODEL_INFO_ENCRYPTION_TYPE'.
In fact, other column names have records existed. Please advise. Regards, BE.
FOR i in 1..l_flex_column_list.count LOOP
dbms_output.put_line('SEAEGO_CC_FAMILYMODEL_INFO_'||l_flex_column_list(i).column_name);
BEGIN
SELECT evsvv.value_set_name, evsvv.internal_name, evsvv.display_name
BULK COLLECT INTO l_flex_value_list -- table collection
FROM ego_value_set_values_v evsvv
*WHERE evsvv.value_set_name= 'SEAEGO_CC_FAMILYMODEL_INFO_'||l_flex_column_list(i).column_name;*
EXCEPTION
WHEN NO_DATA_FOUND THEN
l_flex_value_list:=NULL;
WHEN OTHERS THEN
dbms_output.put_line('test ');
END;
END LOOP;
dbms_output.put_line('');
BEGIN
FOR i in 1..l_flex_value_list.count LOOP
dbms_output.put_line(l_flex_value_list(i).value_set_name ||' '||
l_flex_value_list(i).internal_name||' '||
l_flex_value_list(i).display_name);
END LOOP;
END;
END;
*Output*
SEAEGO_CC_FAMILYMODEL_INFO_PRODUCT_TYPE
SEAEGO_CC_FAMILYMODEL_INFO_INTERNAL_PRODUCT_NAME
SEAEGO_CC_FAMILYMODEL_INFO_NUMBER_OF_HEADS
SEAEGO_CC_FAMILYMODEL_INFO_NUMBER_OF_DISCS
SEAEGO_CC_FAMILYMODEL_INFO_GENERATION
SEAEGO_CC_FAMILYMODEL_INFO_DESIGN_APPLICATION
SEAEGO_CC_FAMILYMODEL_INFO_FORM_FACTOR
SEAEGO_CC_FAMILYMODEL_INFO_INTERFACE
SEAEGO_CC_FAMILYMODEL_INFO_BASE_WARRANTY_MONTHS
SEAEGO_CC_FAMILYMODEL_INFO_PHYSICAL_SECTOR_SIZE
SEAEGO_CC_FAMILYMODEL_INFO_MODEL_HEIGHT
SEAEGO_CC_FAMILYMODEL_INFO_ENCRYPTION_TYPE
_incorrect result_
SEAEGO_CC_FAMILYMODEL_INFO_ENCRYPTION_TYPE NO ENCRYPTION No Encryption
SEAEGO_CC_FAMILYMODEL_INFO_ENCRYPTION_TYPE FDE BASE FDE Base
SEAEGO_CC_FAMILYMODEL_INFO_ENCRYPTION_TYPE FDE FIPS 140-2 FDE FIPS 140-2
Query Statement for other columns
SELECT evsvv.value_set_name, evsvv.internal_name, evsvv.display_name
FROM ego_value_set_values_v evsvv
WHERE evsvv.value_set_name = 'SEAEGO_CC_FAMILYMODEL_INFO_MODEL_HEIGHT'
*Output*
SEAEGO_CC_FAMILYMODEL_INFO_MODEL_HEIGHT 5MM 0.196 IN/5MM
SEAEGO_CC_FAMILYMODEL_INFO_MODEL_HEIGHT 7MM 0.276 IN/7MM
SEAEGO_CC_FAMILYMODEL_INFO_MODEL_HEIGHT 8MM 0.315 IN/8MM
SEAEGO_CC_FAMILYMODEL_INFO_MODEL_HEIGHT 9.5MM 0.374 IN/9.5MM
SEAEGO_CC_FAMILYMODEL_INFO_MODEL_HEIGHT 10.5MM 0.431 IN/10.5MMHi there, the select statement below actually query record into 'l_flex_value_list' record variable by
looping in different values e.g. SEAEGO_CC_FAMILYMODEL_INFO_BASE_WARRANTY_MONTHS,
SEAEGO_CC_FAMILYMODEL_INFO_PHYSICAL_SECTOR_SIZE and SEAEGO_CC_FAMILYMODEL_INFO_ENCRYPTION_TYPE.
But, my problem is the 'l_flex_value_list' is only storing the result for SEAEGO_CC_FAMILYMODEL_INFO_ENCRYPTION_TYPE, overwriting
the values of SEAEGO_CC_FAMILYMODEL_INFO_BASE_WARRANTY_MONTHS and SEAEGO_CC_FAMILYMODEL_INFO_PHYSICAL_SECTOR_SIZE.
What is the logic should be in this case?
FOR i in 1..l_flex_column_list.count LOOP
-- dbms_output.put_line('SEAEGO_CC_FAMILYMODEL_INFO_'||l_flex_column_list(i).column_name);
dbms_output.put_line(l_flex_column_list(i).column_name||' '||
l_flex_column_list(i).column_value);
BEGIN
SELECT evsvv.value_set_name, evsvv.internal_name, evsvv.display_name
BULK COLLECT INTO l_flex_value_list
FROM ego_value_set_values_v evsvv
WHERE evsvv.value_set_name= 'SEAEGO_CC_FAMILYMODEL_INFO_'||l_flex_column_list(i).column_name;
-- AND internal_name = l_flex_column_list(i).column_value;
EXCEPTION
WHEN NO_DATA_FOUND THEN
l_flex_value_list:=NULL;
WHEN OTHERS THEN
dbms_output.put_line(' ');
END;
END LOOP;
------------------the PL/SQL -----------------------
Declare
l_query VARCHAR2(2000);
l_where VARCHAR2(2000);
l_bind_var1 VARCHAR2(40);
l_bind_var2 VARCHAR2(40);
l_sql NUMBER:=0;
l_column_name VARCHAR2(100);
l_column_value VARCHAR2(200);
p_item_id NUMBER :=NULL;--931104 ;
p_item_number VARCHAR2(40):='9NH2D4-570';
p_stmodel VARCHAR2(40):='ST901603FGD1E1-RK';
TYPE l_flex_column_rec IS RECORD
column_name varchar2(100),
column_value varchar2(100));
TYPE l_flex_column_tab IS TABLE OF l_flex_column_rec;
l_flex_column_list l_flex_column_tab;
TYPE l_flex_value_rec IS RECORD
( value_set_name fnd_flex_value_sets.flex_value_set_name%type,
internal_name fnd_flex_values.flex_value%type,
display_name fnd_flex_values_tl.description%type);
TYPE l_flex_value_tab IS TABLE OF l_flex_value_rec;
l_flex_value_list l_flex_value_tab;
BEGIN
IF p_stmodel is not null THEN
IF p_item_number IS NULL AND p_item_id IS NULL THEN
l_where :='and st.stmodelnumber= :1 and sp.detailedproductname=''GENERIC''';
l_bind_var1 := p_stmodel;
l_sql := 1;
ELSIF p_item_number IS NULL AND p_item_id IS NOT NULL THEN
l_where :='and st.stmodelnumber=:1 and sc.ccitemnumber = (select msi.segment1
from mtl_system_items msi
where msi.inventory_item_id = :2 and rownum=1)';
l_bind_var1 := p_stmodel;
l_bind_var2 := p_item_id;
l_sql :=2;
ELSE
l_where :='and st.stmodelnumber=:1 and sc.ccitemnumber = (select msi.segment1
from mtl_system_items msi
where msi.segment1=:2 and rownum=1)';
l_bind_var1 := p_stmodel;
l_bind_var2 := p_item_number;
l_sql :=2;
END IF;
ELSE
IF p_item_id is null and p_item_number is not null THEN
l_where := 'and sc.ccitemnumber = (select msi.segment1
from mtl_system_items msi
where msi.segment1=:1 and rownum=1)';
l_bind_var1 := p_item_number;
l_sql := 1;
ELSIF p_item_id is NOT null and p_item_number is null THEN
l_where := 'and sc.ccitemnumber = ( select msi.segment1
from mtl_system_items msi
where msi.inventory_item_id = :1 and rownum=1)';
l_bind_var1 := p_item_id;
l_sql := 1;
ELSIF p_item_id is not null and p_item_number is not null THEN
l_where :='and sc.ccitemnumber = (select msi.segment1
from mtl_system_items msi
where msi.inventory_item_id =:1
AND msi.segment1=:2 and rownum=1)';
l_bind_var1 := p_item_id;
l_bind_var2 := p_item_number;
l_sql :=2;
END IF;
END IF;
l_query :='select decode(rn,1,''PRODUCT_TYPE'',2,''INTERNAL_PRODUCT_NAME'',3,''NUMBER_OF_HEADS'',4,''NUMBER_OF_DISCS'',5,''GENERATION'',6,''DESIGN_APPLICATION'',
7,''FORM_FACTOR'',8,''INTERFACE'',9,''BASE_WARRANTY_MONTHS'',10,''PHYSICAL_SECTOR_SIZE'',11,''MODEL_HEIGHT'',''ENCRYPTION_TYPE'') as column_name,
decode(rn,1,st.producttype,2,sp.internalproductname,3,sp.numberofheads,4,sp.numberofdiscs,5,sp.generation,6,sp.designapplication,7,st.formfactor,
8,st.interface,9,st.warrantymonths,10,st.physical_sector_size,11,st.modelheight,st.encryption_type) as column_value
FROM seaeng_productmodel sp , seaeng_stmodel st, seaeng_ccitemnumber sc , (select rownum rn from dual connect by rownum <=12)
WHERE sc.productmodelnumber = sp.productmodelnumber
AND sp.stmodelnumber = st.stmodelnumber ';
IF l_sql = 1 THEN
EXECUTE IMMEDIATE l_query ||l_where
BULK COLLECT INTO l_flex_column_list
USING l_bind_var1 ;
-- dbms_output.put_line(l_query||l_where);
ELSIF
l_sql =2 THEN
EXECUTE IMMEDIATE l_query || l_where
BULK COLLECT INTO l_flex_column_list
using l_bind_var1,l_bind_var2;
dbms_output.put_line(l_query||l_where);
END IF;
FOR i in 1..l_flex_column_list.count LOOP
-- dbms_output.put_line('SEAEGO_CC_FAMILYMODEL_INFO_'||l_flex_column_list(i).column_name);
dbms_output.put_line(l_flex_column_list(i).column_name||' '||
l_flex_column_list(i).column_value);
BEGIN
SELECT evsvv.value_set_name, evsvv.internal_name, evsvv.display_name
BULK COLLECT INTO l_flex_value_list
FROM ego_value_set_values_v evsvv
WHERE evsvv.value_set_name= 'SEAEGO_CC_FAMILYMODEL_INFO_'||l_flex_column_list(i).column_name;
-- AND internal_name = l_flex_column_list(i).column_value;
EXCEPTION
WHEN NO_DATA_FOUND THEN
l_flex_value_list:=NULL;
WHEN OTHERS THEN
dbms_output.put_line(' ');
END;
END LOOP;
dbms_output.put_line('');
BEGIN
FOR i in 1..l_flex_value_list.count LOOP
dbms_output.put_line(l_flex_value_list(i).value_set_name ||' '||
l_flex_value_list(i).internal_name||' '||
l_flex_value_list(i).display_name);
END LOOP;
END;
END;
-------OUTPUT
SEAEGO_CC_FAMILYMODEL_INFO_ENCRYPTION_TYPE NO ENCRYPTION No Encryption
SEAEGO_CC_FAMILYMODEL_INFO_ENCRYPTION_TYPE FDE BASE FDE Base
SEAEGO_CC_FAMILYMODEL_INFO_ENCRYPTION_TYPE FDE FIPS 140-2 FDE FIPS 140-2 -
Can I use Bulk Collect results as input parameter for another cursor
MUSIC ==> remote MUSIC_DB database, MUSIC table has 60 million rows
PRICE_DATA ==> remote PRICING_DB database, PRICE_DATE table has 1 billion rows
These two table once existed in same database, but size of database exceeded available hardware size and hardware budget, so the PRICE_DATA table was moved to another Oracle database. I need to create a single report that combines data from both of these tables, and a distributed join with DRIVING_SITE hint will not work because the size of both table is too large to push to one DRIVING_SITE location, so I wrote this PLSQL block to process in small blocks.
QUESTION: how can use bulk collect from one cursor and pass that bulk collected information as input to second cursor without specifically listing each cell of the PLSQL bulk collection? See sample pseudo-code below, I am trying to determine more efficient way to code than hard-coding 100 parameter names into 2nd cursor.
NOTE: below is truly pseudo-code, I had to change the names of everything to adhere to NDA, but below works and is fast enough for my purposes, but if I want to change from 100 input parameters to 200, I have to add more hard-coded values. There has got to be a better way.
DECLARE
-- define cursor that retrieves distinct SONG_IDs from MUSIC table in remote music database
CURSOR C_CURRENT_MUSIC
IS
select distinct SONG_ID
from MUSIC@MUSIC_DB
where PRODUCTION_RELEASE=1
/* define a parameterized cursor that accepts 100 SONG_IDs and retrieves
required pricing information
CURSOR C_get_music_price_data
P_SONG_ID_001 NUMBER, P_SONG_ID_002 NUMBER, P_SONG_ID_003 NUMBER, P_SONG_ID_004 NUMBER, P_SONG_ID_005 NUMBER, P_SONG_ID_006 NUMBER, P_SONG_ID_007 NUMBER, P_SONG_ID_008 NUMBER, P_SONG_ID_009 NUMBER, P_SONG_ID_010 NUMBER,
P_SONG_ID_011 NUMBER, P_SONG_ID_012 NUMBER, P_SONG_ID_013 NUMBER, P_SONG_ID_014 NUMBER, P_SONG_ID_015 NUMBER, P_SONG_ID_016 NUMBER, P_SONG_ID_017 NUMBER, P_SONG_ID_018 NUMBER, P_SONG_ID_019 NUMBER, P_SONG_ID_020 NUMBER,
P_SONG_ID_021 NUMBER, P_SONG_ID_022 NUMBER, P_SONG_ID_023 NUMBER, P_SONG_ID_024 NUMBER, P_SONG_ID_025 NUMBER, P_SONG_ID_026 NUMBER, P_SONG_ID_027 NUMBER, P_SONG_ID_028 NUMBER, P_SONG_ID_029 NUMBER, P_SONG_ID_030 NUMBER,
P_SONG_ID_031 NUMBER, P_SONG_ID_032 NUMBER, P_SONG_ID_033 NUMBER, P_SONG_ID_034 NUMBER, P_SONG_ID_035 NUMBER, P_SONG_ID_036 NUMBER, P_SONG_ID_037 NUMBER, P_SONG_ID_038 NUMBER, P_SONG_ID_039 NUMBER, P_SONG_ID_040 NUMBER,
P_SONG_ID_041 NUMBER, P_SONG_ID_042 NUMBER, P_SONG_ID_043 NUMBER, P_SONG_ID_044 NUMBER, P_SONG_ID_045 NUMBER, P_SONG_ID_046 NUMBER, P_SONG_ID_047 NUMBER, P_SONG_ID_048 NUMBER, P_SONG_ID_049 NUMBER, P_SONG_ID_050 NUMBER,
P_SONG_ID_051 NUMBER, P_SONG_ID_052 NUMBER, P_SONG_ID_053 NUMBER, P_SONG_ID_054 NUMBER, P_SONG_ID_055 NUMBER, P_SONG_ID_056 NUMBER, P_SONG_ID_057 NUMBER, P_SONG_ID_058 NUMBER, P_SONG_ID_059 NUMBER, P_SONG_ID_060 NUMBER,
P_SONG_ID_061 NUMBER, P_SONG_ID_062 NUMBER, P_SONG_ID_063 NUMBER, P_SONG_ID_064 NUMBER, P_SONG_ID_065 NUMBER, P_SONG_ID_066 NUMBER, P_SONG_ID_067 NUMBER, P_SONG_ID_068 NUMBER, P_SONG_ID_069 NUMBER, P_SONG_ID_070 NUMBER,
P_SONG_ID_071 NUMBER, P_SONG_ID_072 NUMBER, P_SONG_ID_073 NUMBER, P_SONG_ID_074 NUMBER, P_SONG_ID_075 NUMBER, P_SONG_ID_076 NUMBER, P_SONG_ID_077 NUMBER, P_SONG_ID_078 NUMBER, P_SONG_ID_079 NUMBER, P_SONG_ID_080 NUMBER,
P_SONG_ID_081 NUMBER, P_SONG_ID_082 NUMBER, P_SONG_ID_083 NUMBER, P_SONG_ID_084 NUMBER, P_SONG_ID_085 NUMBER, P_SONG_ID_086 NUMBER, P_SONG_ID_087 NUMBER, P_SONG_ID_088 NUMBER, P_SONG_ID_089 NUMBER, P_SONG_ID_090 NUMBER,
P_SONG_ID_091 NUMBER, P_SONG_ID_092 NUMBER, P_SONG_ID_093 NUMBER, P_SONG_ID_094 NUMBER, P_SONG_ID_095 NUMBER, P_SONG_ID_096 NUMBER, P_SONG_ID_097 NUMBER, P_SONG_ID_098 NUMBER, P_SONG_ID_099 NUMBER, P_SONG_ID_100 NUMBER
IS
select
from PRICE_DATA@PRICING_DB
where COUNTRY = 'USA'
and START_DATE <= sysdate
and END_DATE > sysdate
and vpc.SONG_ID IN
P_SONG_ID_001 ,P_SONG_ID_002 ,P_SONG_ID_003 ,P_SONG_ID_004 ,P_SONG_ID_005 ,P_SONG_ID_006 ,P_SONG_ID_007 ,P_SONG_ID_008 ,P_SONG_ID_009 ,P_SONG_ID_010,
P_SONG_ID_011 ,P_SONG_ID_012 ,P_SONG_ID_013 ,P_SONG_ID_014 ,P_SONG_ID_015 ,P_SONG_ID_016 ,P_SONG_ID_017 ,P_SONG_ID_018 ,P_SONG_ID_019 ,P_SONG_ID_020,
P_SONG_ID_021 ,P_SONG_ID_022 ,P_SONG_ID_023 ,P_SONG_ID_024 ,P_SONG_ID_025 ,P_SONG_ID_026 ,P_SONG_ID_027 ,P_SONG_ID_028 ,P_SONG_ID_029 ,P_SONG_ID_030,
P_SONG_ID_031 ,P_SONG_ID_032 ,P_SONG_ID_033 ,P_SONG_ID_034 ,P_SONG_ID_035 ,P_SONG_ID_036 ,P_SONG_ID_037 ,P_SONG_ID_038 ,P_SONG_ID_039 ,P_SONG_ID_040,
P_SONG_ID_041 ,P_SONG_ID_042 ,P_SONG_ID_043 ,P_SONG_ID_044 ,P_SONG_ID_045 ,P_SONG_ID_046 ,P_SONG_ID_047 ,P_SONG_ID_048 ,P_SONG_ID_049 ,P_SONG_ID_050,
P_SONG_ID_051 ,P_SONG_ID_052 ,P_SONG_ID_053 ,P_SONG_ID_054 ,P_SONG_ID_055 ,P_SONG_ID_056 ,P_SONG_ID_057 ,P_SONG_ID_058 ,P_SONG_ID_059 ,P_SONG_ID_060,
P_SONG_ID_061 ,P_SONG_ID_062 ,P_SONG_ID_063 ,P_SONG_ID_064 ,P_SONG_ID_065 ,P_SONG_ID_066 ,P_SONG_ID_067 ,P_SONG_ID_068 ,P_SONG_ID_069 ,P_SONG_ID_070,
P_SONG_ID_071 ,P_SONG_ID_072 ,P_SONG_ID_073 ,P_SONG_ID_074 ,P_SONG_ID_075 ,P_SONG_ID_076 ,P_SONG_ID_077 ,P_SONG_ID_078 ,P_SONG_ID_079 ,P_SONG_ID_080,
P_SONG_ID_081 ,P_SONG_ID_082 ,P_SONG_ID_083 ,P_SONG_ID_084 ,P_SONG_ID_085 ,P_SONG_ID_086 ,P_SONG_ID_087 ,P_SONG_ID_088 ,P_SONG_ID_089 ,P_SONG_ID_090,
P_SONG_ID_091 ,P_SONG_ID_092 ,P_SONG_ID_093 ,P_SONG_ID_094 ,P_SONG_ID_095 ,P_SONG_ID_096 ,P_SONG_ID_097 ,P_SONG_ID_098 ,P_SONG_ID_099 ,P_SONG_ID_100
group by
vpc.SONG_ID
,vpc.STOREFRONT_ID
TYPE SONG_ID_TYPE IS TABLE OF MUSIC@MUSIC_DB%TYPE INDEX BY BINARY_INTEGER;
V_SONG_ID_ARRAY SONG_ID_TYPE ;
v_commit_counter NUMBER := 0;
BEGIN
/* open cursor you intent to bulk collect from */
OPEN C_CURRENT_MUSIC;
LOOP
/* in batches of 100, bulk collect ADAM_ID mapped TMS_IDENTIFIER into PLSQL table or records */
FETCH C_CURRENT_MUSIC BULK COLLECT INTO V_SONG_ID_ARRAY LIMIT 100;
EXIT WHEN V_SONG_ID_ARRAY.COUNT = 0;
/* to avoid NO DATA FOUND error when pass 100 parameters to OPEN cursor, if the arrary
is not fully populated to 100, pad the array with nulls to fill up to 100 cells. */
IF (V_SONG_ID_ARRAY.COUNT >=1 and V_SONG_ID_ARRAY.COUNT <> 100) THEN
FOR j IN V_SONG_ID_ARRAY.COUNT+1..100 LOOP
V_SONG_ID_ARRAY(j) := null;
END LOOP;
END IF;
/* pass a batch of 100 to cursor that get price information per SONG_ID and STOREFRONT_ID */
FOR j IN C_get_music_price_data
V_SONG_ID_ARRAY(1) ,V_SONG_ID_ARRAY(2) ,V_SONG_ID_ARRAY(3) ,V_SONG_ID_ARRAY(4) ,V_SONG_ID_ARRAY(5) ,V_SONG_ID_ARRAY(6) ,V_SONG_ID_ARRAY(7) ,V_SONG_ID_ARRAY(8) ,V_SONG_ID_ARRAY(9) ,V_SONG_ID_ARRAY(10) ,
V_SONG_ID_ARRAY(11) ,V_SONG_ID_ARRAY(12) ,V_SONG_ID_ARRAY(13) ,V_SONG_ID_ARRAY(14) ,V_SONG_ID_ARRAY(15) ,V_SONG_ID_ARRAY(16) ,V_SONG_ID_ARRAY(17) ,V_SONG_ID_ARRAY(18) ,V_SONG_ID_ARRAY(19) ,V_SONG_ID_ARRAY(20) ,
V_SONG_ID_ARRAY(21) ,V_SONG_ID_ARRAY(22) ,V_SONG_ID_ARRAY(23) ,V_SONG_ID_ARRAY(24) ,V_SONG_ID_ARRAY(25) ,V_SONG_ID_ARRAY(26) ,V_SONG_ID_ARRAY(27) ,V_SONG_ID_ARRAY(28) ,V_SONG_ID_ARRAY(29) ,V_SONG_ID_ARRAY(30) ,
V_SONG_ID_ARRAY(31) ,V_SONG_ID_ARRAY(32) ,V_SONG_ID_ARRAY(33) ,V_SONG_ID_ARRAY(34) ,V_SONG_ID_ARRAY(35) ,V_SONG_ID_ARRAY(36) ,V_SONG_ID_ARRAY(37) ,V_SONG_ID_ARRAY(38) ,V_SONG_ID_ARRAY(39) ,V_SONG_ID_ARRAY(40) ,
V_SONG_ID_ARRAY(41) ,V_SONG_ID_ARRAY(42) ,V_SONG_ID_ARRAY(43) ,V_SONG_ID_ARRAY(44) ,V_SONG_ID_ARRAY(45) ,V_SONG_ID_ARRAY(46) ,V_SONG_ID_ARRAY(47) ,V_SONG_ID_ARRAY(48) ,V_SONG_ID_ARRAY(49) ,V_SONG_ID_ARRAY(50) ,
V_SONG_ID_ARRAY(51) ,V_SONG_ID_ARRAY(52) ,V_SONG_ID_ARRAY(53) ,V_SONG_ID_ARRAY(54) ,V_SONG_ID_ARRAY(55) ,V_SONG_ID_ARRAY(56) ,V_SONG_ID_ARRAY(57) ,V_SONG_ID_ARRAY(58) ,V_SONG_ID_ARRAY(59) ,V_SONG_ID_ARRAY(60) ,
V_SONG_ID_ARRAY(61) ,V_SONG_ID_ARRAY(62) ,V_SONG_ID_ARRAY(63) ,V_SONG_ID_ARRAY(64) ,V_SONG_ID_ARRAY(65) ,V_SONG_ID_ARRAY(66) ,V_SONG_ID_ARRAY(67) ,V_SONG_ID_ARRAY(68) ,V_SONG_ID_ARRAY(69) ,V_SONG_ID_ARRAY(70) ,
V_SONG_ID_ARRAY(71) ,V_SONG_ID_ARRAY(72) ,V_SONG_ID_ARRAY(73) ,V_SONG_ID_ARRAY(74) ,V_SONG_ID_ARRAY(75) ,V_SONG_ID_ARRAY(76) ,V_SONG_ID_ARRAY(77) ,V_SONG_ID_ARRAY(78) ,V_SONG_ID_ARRAY(79) ,V_SONG_ID_ARRAY(80) ,
V_SONG_ID_ARRAY(81) ,V_SONG_ID_ARRAY(82) ,V_SONG_ID_ARRAY(83) ,V_SONG_ID_ARRAY(84) ,V_SONG_ID_ARRAY(85) ,V_SONG_ID_ARRAY(86) ,V_SONG_ID_ARRAY(87) ,V_SONG_ID_ARRAY(88) ,V_SONG_ID_ARRAY(89) ,V_SONG_ID_ARRAY(90) ,
V_SONG_ID_ARRAY(91) ,V_SONG_ID_ARRAY(92) ,V_SONG_ID_ARRAY(93) ,V_SONG_ID_ARRAY(94) ,V_SONG_ID_ARRAY(95) ,V_SONG_ID_ARRAY(96) ,V_SONG_ID_ARRAY(97) ,V_SONG_ID_ARRAY(98) ,V_SONG_ID_ARRAY(99) ,V_SONG_ID_ARRAY(100)
LOOP
/* do stuff with data from Song and Pricing Database coming from the two
separate cursors, then continue processing more rows...
END LOOP;
/* commit after each batch of 100 SONG_IDs is processed */
COMMIT;
EXIT WHEN C_CURRENT_MUSIC%NOTFOUND; -- exit when there are no more rows to fetch from cursor
END LOOP; -- bulk fetching loop
CLOSE C_CURRENT_MUSIC; -- close cursor that was used in bulk collection
/* commit rows */
COMMIT; -- commit any remaining uncommitted data.
END;I've got a problem when using passing VARRAY of numbers as parameter to remote cursor: it takes a super long time to run, sometimes doesn't finish even after an hour as passed.
Continuing with my example in original entry, I replaced the bulk collect into PLSQL table collection with a VARRAY and i bulk collect into the VARRAY, this is fast and I know it works because I can DBMS_OUTPUT.PUT_LINE cells of VARRAY so I know it is getting populated correctly. However, when I pass the VARRAY containing 100 cells populated with SONG_IDs as parameter to cursor, execution time is over an hour and when I am expecting a few seconds.
Below code example strips the problem down to it's raw details, I skip the bulk collect and just manually populate a VARRAY with 100 SONG_ID values, then try to pass to as parameter to a cursor, but the execution time of cursor is unexpectedly long, over 30 minutes, sometime longer, when I am expecting seconds.
IMPORTANT: If I take the same 100 SONG_IDs and place them directly in the cursor query's where IN clause, the SQL runs in under 5 seconds and returns result. Also, if I pass the 100 SONG_IDs as individual cells of a PLSQL table collection, then it also runs fast.
I thought that since the VARRAY is used via select subquery that is it queried locally, but the cursor is remote, and that I had a distribute problem on my hands, so I put in the DRIVING_SITE hint to attempt to force the result of query against VARRAY to go to remote server and rest of query will run there before returning result, but that didn't work either, still got slow response.
Is something wrong with my code, or I am running into a Oracle problem that may require support to resolve?
DECLARE
/* define a parameterized cursor that accepts XXX number of in SONG_IDs and
retrieves required pricing information
CURSOR C_get_music_price_data
p_array_song_ids SYS.ODCInumberList
IS
select /*+DRIVING_SITE(pd) */
count(distinct s.EVE_ID)
from PRICE_DATA@PRICING_DB pd
where pd.COUNTRY = 'USA'
and pd.START_DATE <= sysdate
and pd.END_DATE > sysdate
and pd.SONG_ID IN
select column_value from table(p_array_song_ids)
group by
pd.SONG_ID
,pd.STOREFRONT_ID
V_ARRAY_SONG_IDS SYS.ODCInumberList := SYS.ODCInumberList();
BEGIN
V_ARRAY_SONG_IDS.EXTEND(100);
V_ARRAY_SONG_IDS( 1 ) := 31135 ;
V_ARRAY_SONG_IDS( 2 ) := 31140 ;
V_ARRAY_SONG_IDS( 3 ) := 31142 ;
V_ARRAY_SONG_IDS( 4 ) := 31144 ;
V_ARRAY_SONG_IDS( 5 ) := 31146 ;
V_ARRAY_SONG_IDS( 6 ) := 31148 ;
V_ARRAY_SONG_IDS( 7 ) := 31150 ;
V_ARRAY_SONG_IDS( 8 ) := 31152 ;
V_ARRAY_SONG_IDS( 9 ) := 31154 ;
V_ARRAY_SONG_IDS( 10 ) := 31156 ;
V_ARRAY_SONG_IDS( 11 ) := 31158 ;
V_ARRAY_SONG_IDS( 12 ) := 31160 ;
V_ARRAY_SONG_IDS( 13 ) := 33598 ;
V_ARRAY_SONG_IDS( 14 ) := 33603 ;
V_ARRAY_SONG_IDS( 15 ) := 33605 ;
V_ARRAY_SONG_IDS( 16 ) := 33607 ;
V_ARRAY_SONG_IDS( 17 ) := 33609 ;
V_ARRAY_SONG_IDS( 18 ) := 33611 ;
V_ARRAY_SONG_IDS( 19 ) := 33613 ;
V_ARRAY_SONG_IDS( 20 ) := 33615 ;
V_ARRAY_SONG_IDS( 21 ) := 33617 ;
V_ARRAY_SONG_IDS( 22 ) := 33630 ;
V_ARRAY_SONG_IDS( 23 ) := 33632 ;
V_ARRAY_SONG_IDS( 24 ) := 33636 ;
V_ARRAY_SONG_IDS( 25 ) := 33638 ;
V_ARRAY_SONG_IDS( 26 ) := 33640 ;
V_ARRAY_SONG_IDS( 27 ) := 33642 ;
V_ARRAY_SONG_IDS( 28 ) := 33644 ;
V_ARRAY_SONG_IDS( 29 ) := 33646 ;
V_ARRAY_SONG_IDS( 30 ) := 33648 ;
V_ARRAY_SONG_IDS( 31 ) := 33662 ;
V_ARRAY_SONG_IDS( 32 ) := 33667 ;
V_ARRAY_SONG_IDS( 33 ) := 33669 ;
V_ARRAY_SONG_IDS( 34 ) := 33671 ;
V_ARRAY_SONG_IDS( 35 ) := 33673 ;
V_ARRAY_SONG_IDS( 36 ) := 33675 ;
V_ARRAY_SONG_IDS( 37 ) := 33677 ;
V_ARRAY_SONG_IDS( 38 ) := 33679 ;
V_ARRAY_SONG_IDS( 39 ) := 33681 ;
V_ARRAY_SONG_IDS( 40 ) := 33683 ;
V_ARRAY_SONG_IDS( 41 ) := 33685 ;
V_ARRAY_SONG_IDS( 42 ) := 33700 ;
V_ARRAY_SONG_IDS( 43 ) := 33702 ;
V_ARRAY_SONG_IDS( 44 ) := 33704 ;
V_ARRAY_SONG_IDS( 45 ) := 33706 ;
V_ARRAY_SONG_IDS( 46 ) := 33708 ;
V_ARRAY_SONG_IDS( 47 ) := 33710 ;
V_ARRAY_SONG_IDS( 48 ) := 33712 ;
V_ARRAY_SONG_IDS( 49 ) := 33723 ;
V_ARRAY_SONG_IDS( 50 ) := 33725 ;
V_ARRAY_SONG_IDS( 51 ) := 33727 ;
V_ARRAY_SONG_IDS( 52 ) := 33729 ;
V_ARRAY_SONG_IDS( 53 ) := 33731 ;
V_ARRAY_SONG_IDS( 54 ) := 33733 ;
V_ARRAY_SONG_IDS( 55 ) := 33735 ;
V_ARRAY_SONG_IDS( 56 ) := 33737 ;
V_ARRAY_SONG_IDS( 57 ) := 33749 ;
V_ARRAY_SONG_IDS( 58 ) := 33751 ;
V_ARRAY_SONG_IDS( 59 ) := 33753 ;
V_ARRAY_SONG_IDS( 60 ) := 33755 ;
V_ARRAY_SONG_IDS( 61 ) := 33757 ;
V_ARRAY_SONG_IDS( 62 ) := 33759 ;
V_ARRAY_SONG_IDS( 63 ) := 33761 ;
V_ARRAY_SONG_IDS( 64 ) := 33763 ;
V_ARRAY_SONG_IDS( 65 ) := 33775 ;
V_ARRAY_SONG_IDS( 66 ) := 33777 ;
V_ARRAY_SONG_IDS( 67 ) := 33779 ;
V_ARRAY_SONG_IDS( 68 ) := 33781 ;
V_ARRAY_SONG_IDS( 69 ) := 33783 ;
V_ARRAY_SONG_IDS( 70 ) := 33785 ;
V_ARRAY_SONG_IDS( 71 ) := 33787 ;
V_ARRAY_SONG_IDS( 72 ) := 33789 ;
V_ARRAY_SONG_IDS( 73 ) := 33791 ;
V_ARRAY_SONG_IDS( 74 ) := 33793 ;
V_ARRAY_SONG_IDS( 75 ) := 33807 ;
V_ARRAY_SONG_IDS( 76 ) := 33809 ;
V_ARRAY_SONG_IDS( 77 ) := 33811 ;
V_ARRAY_SONG_IDS( 78 ) := 33813 ;
V_ARRAY_SONG_IDS( 79 ) := 33815 ;
V_ARRAY_SONG_IDS( 80 ) := 33817 ;
V_ARRAY_SONG_IDS( 81 ) := 33819 ;
V_ARRAY_SONG_IDS( 82 ) := 33821 ;
V_ARRAY_SONG_IDS( 83 ) := 33823 ;
V_ARRAY_SONG_IDS( 84 ) := 33825 ;
V_ARRAY_SONG_IDS( 85 ) := 33839 ;
V_ARRAY_SONG_IDS( 86 ) := 33844 ;
V_ARRAY_SONG_IDS( 87 ) := 33846 ;
V_ARRAY_SONG_IDS( 88 ) := 33848 ;
V_ARRAY_SONG_IDS( 89 ) := 33850 ;
V_ARRAY_SONG_IDS( 90 ) := 33852 ;
V_ARRAY_SONG_IDS( 91 ) := 33854 ;
V_ARRAY_SONG_IDS( 92 ) := 33856 ;
V_ARRAY_SONG_IDS( 93 ) := 33858 ;
V_ARRAY_SONG_IDS( 94 ) := 33860 ;
V_ARRAY_SONG_IDS( 95 ) := 33874 ;
V_ARRAY_SONG_IDS( 96 ) := 33879 ;
V_ARRAY_SONG_IDS( 97 ) := 33881 ;
V_ARRAY_SONG_IDS( 98 ) := 33883 ;
V_ARRAY_SONG_IDS( 99 ) := 33885 ;
V_ARRAY_SONG_IDS(100 ) := 33889 ;
/* do stuff with data from Song and Pricing Database coming from the two
separate cursors, then continue processing more rows...
FOR i IN C_get_music_price_data( v_array_song_ids ) LOOP
. (this is the loop where I pass in v_array_song_ids
. populated with only 100 cells and it runs forever)
END LOOP;
END; -
Needed help in bulk collect using collections
Hi,
I have created a schema level collection like "CREATE OR REPLACE TYPE T_EMP_NO IS TABLE OF NUMBER ;
will i able to use this in a where clause which involves bulk collect?
Please share ur thoughts.
My oracle version is 10guser13710379 wrote:
Will i be able to do a bulk collect into a table using this collection of my sql type?Bulk fetches collects into an array like structure - not into a SQL table like structure. So calling a collection variable in PL/SQL a "+PL/SQL table+" does not make much sense as this array structure is nothing like a table. For the same reason, one needs to question running SQL select statements against PL/SQL arrays.
As for your SQL type defined - it is a collection (array) of numbers. Thus it can be used to bulk fetch a numeric column. -
Calling Stored procedure which uses Bulk Collect
Hi All, I have Oracle stored procedure which uses Bulk Collect and returns table type parameter as output. Can anyone please help me how Can I call this kind of stored procedures which returns table type output using VB and Oracle's Driver. (I am successfully able to call using MS ODBC driver, but I want to use OraOLEDB driver.)
861412 wrote:
how Can I call this kind of stored procedures which returns table type output using VB and Oracle's Driver. This forum deals with the server-side languages SQL and PL/SQL.
Your question deals with the client side and Visual Basic language. -
Hi All,
I need a help to create a bulk statement. Please find the scenario below
I would like to copy a table A from table B using bulk collect also the table A has more records (1Million). Before doing this I need to either truncate the table B or drop the table to load the data from table A.
Please provide me the correct statement to achieve this request. Thanks in advance!!
Regards,
Boovan.disabling any indexes on the target should be looked at first. If there are none then look at the above.
When you do a direct path load the indexes are build after loading.The point is that the direct path load does not avoid the undo due to the indexes.
In this example on a table with no indexes the undo used goes from 216kb to 16kb using append.
When an index is added the undo used goes up from 216kb to 704kb an increase of 488kb for a standard insert.
For the direct path insert the undo goes up from 16kb to 440kb so almost the full amount of undo due to the index.
So the presence of a single index can have a much greater impact on the amount of undo required than the use of a direct path load and that undo may not be avoided by the use of a direct path load unless the index is disabled beforehand.
Also note the tiny amounts of undo we are talking about for 50k rows.
SQL> create table t as select * from all_objects where 0 = 1;
Table created.
SQL> insert into t select * from all_objects;
56108 rows created.
SQL> select
2 used_ublk undo_used_blk,
3 used_ublk * blk_size_kb undo_used_kb,
4 log_io logical_io,
5 cr_get consistent_gets
6 from
7 v$transaction, v$session s,
8 (select distinct sid from v$mystat) m,
9 (select to_number(value)/1024 blk_size_kb
10 from v$parameter where name='db_block_size')
11 where
12 m.sid = s.sid
13 and ses_addr = saddr;
UNDO_USED_BLK UNDO_USED_KB LOGICAL_IO CONSISTENT_GETS
27 216 13893 1042736
SQL> rollback;
Rollback complete.
SQL> insert /*+ append */ into t select * from all_objects;
56108 rows created.
SQL> select
2 used_ublk undo_used_blk,
3 used_ublk * blk_size_kb undo_used_kb,
4 log_io logical_io,
5 cr_get consistent_gets
6 from
7 v$transaction, v$session s,
8 (select distinct sid from v$mystat) m,
9 (select to_number(value)/1024 blk_size_kb
10 from v$parameter where name='db_block_size')
11 where
12 m.sid = s.sid
13 and ses_addr = saddr;
UNDO_USED_BLK UNDO_USED_KB LOGICAL_IO CONSISTENT_GETS
2 16 1307 1041151
SQL> rollback;
Rollback complete.
SQL> create unique index t_idx on t (object_id);
Index created.
SQL> insert into t select * from all_objects;
56109 rows created.
SQL> select
2 used_ublk undo_used_blk,
3 used_ublk * blk_size_kb undo_used_kb,
4 log_io logical_io,
5 cr_get consistent_gets
6 from
7 v$transaction, v$session s,
8 (select distinct sid from v$mystat) m,
9 (select to_number(value)/1024 blk_size_kb
10 from v$parameter where name='db_block_size')
11 where
12 m.sid = s.sid
13 and ses_addr = saddr;
UNDO_USED_BLK UNDO_USED_KB LOGICAL_IO CONSISTENT_GETS
88 704 20908 1043193
SQL> rollback;
Rollback complete.
SQL> insert /*+ append */ into t select * from all_objects;
56109 rows created.
SQL> select
2 used_ublk undo_used_blk,
3 used_ublk * blk_size_kb undo_used_kb,
4 log_io logical_io,
5 cr_get consistent_gets
6 from
7 v$transaction, v$session s,
8 (select distinct sid from v$mystat) m,
9 (select to_number(value)/1024 blk_size_kb
10 from v$parameter where name='db_block_size')
11 where
12 m.sid = s.sid
13 and ses_addr = saddr;
UNDO_USED_BLK UNDO_USED_KB LOGICAL_IO CONSISTENT_GETS
57 456 2310 1041047 -
Friends ,
I am facing Problem in debugging a bulk Collect pl/sql program .
I am violating some constraint in the table while inserting the data using forall loop .
I want to print using dbms_output.put_line the exact data that is violating the constraint
Please help me with DBMs_output.put_line statement in the exceptions block
Kind Regards
SushantI think DBMS_APPLICATION_INFO is a bit of a red herring, as FORALL is not a LOOP.
The PL/SQL User's Guide has examples of reporting errors using the %BULK_EXECPTIONS clause.
Cheers, APC -
Trouble with Bulk Collect to Ref cursor
I'm trying to open a ref cursor to a dynamic query, and the fetch the cursor (BULK COLLECT)to the table type variable.But I keep getting the compilation error as 'PLS-00597: expression 'EMP_RESULTSET' in the INTO list is of wrong type'
But when I use a simple select from a table and Bulk Collect directly to the table type variable it works. But that is not what I want.
Can someone tell me where I have gone wrong in this stored proc I have listed below.
your help will be highly appreciated.
PROCEDURE SP_TEST_EMP_TABLE_TYPE (
p_resultset OUT result_cursor -- ref cursor as out parameter
AS
TYPE TYPE_REC_EMP is RECORD(EMPNO EMPLOYEE.EMPNO%TYPE, JOIN_DATE EMPLOYEE.JOIN_DATE%TYPE, SALARY EMPLOYEE.SALARY%TYPE); -- declare record type
TYPE TYPE_TAB_EMP IS TABLE OF TYPE_REC_EMP; -- declare table type
EMP_RESULTSET TYPE_TAB_EMP; -- declare variable of type type_calendar_avail_resultset
SQUERY VARCHAR2(32000):='';
BEGIN
SQUERY:='SELECT EMPNO,JOIN_DATE,SALARY FROM EMPLOYEE WHERE EMPNO= 1001 AND JOIN_DATE=''20070530'' ';
--select EMPNO,JOIN_DATE,SALARY BULK COLLECT INTO EMP_RESULTSET from EMPLOYEE WHERE EMPNO=1001 AND JOIN_DATE='20070525';
OPEN p_resultset FOR SQUERY;
FETCH p_resultset BULK COLLECT INTO EMP_RESULTSET;
EXCEPTION
WHEN NO_DATA_FOUND
THEN
NULL;
WHEN OTHERS
THEN
DBMS_OUTPUT.put_line (SQLERRM (SQLCODE));
END SP_TEST_EMP_TABLE_TYPE ;> i) I use a ref cursor to return back to the java
front end, so I had to use a ref cursor.
What is a ref cursor? It is not a data set. It is a pointer to a "SQL program". This program is created by the SQL Engine and the CBO that parses the SQL source code and determine an execution plan to get to the requested rows.
When the client fetches from a (ref) cursor, the client is running this program and it find and returns the next row.
There is no such thing as a physical result set for a cursor - no "copy" of the rows found for the source code SQL is made as a result set.
> ii) I also use a dynamic sql, but I was thinking it
wasn't useful for this posting, so tried to write a
simple sql
What is dynamic SQL? SQL where object names (e.g name of the table) is only known at run-time. Or where the filter (e.g. WHERE conditions) can only be determined at run time.
If these are known, the SQL is static SQL.
For both static and dynamic SQL, bind variables are critical. It is the biggest performance mistake (in Oracle) to hardcode values and literals into a SQL.
> ii) I use a Bulk Collect to the table type
collection, since I use a loop, for which I had to
collect the results from each loop and finally send
the resultset thru the ref cursor.
Impossible. Nor does it make any sense. As stated, a ref cursor is a program and not a result set.
What you intend to do is run a SQL against data. Copy this data into private/local PL/SQL memory. Construct another SQL against this data - which means that it needs to be shipped back to the SQL engine as it cannot use/read local PL/SQL memory structures. And the pass that SQL cursor to the client.
What for?
> I had earlier used the logic to for this using a
temporary table, which works perfectly fine, but our
DBA says we should avoid temporary tables since it
makes additional read/write to the disk. This is the
reason I'm using table type collection here.
Your DBA is correct. One should so a single pass through a data set. Which is why simply passing a ref cursor for a SQL statement to the client is the simplest.
It makes no sense copying SQL data into a collection and then copying that back into the SQL engine in order to throw a ref cursor around it.
Basic client-server fundamentals.
And why RTFM the Oracle manuals I've indicated is important. You need to understand the memory and processing architectures in Oracle in order to make an informed and correct decision. -
How to use BULK COLLECT in oracle forms
hi gurus,
I am using oracle forms
Forms [32 Bit] Version 10.1.2.0.2 (Production)
Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - ProductionI wanna use bulk collect from database table lets say <employees>
while working on database level with collections and records it's working very well for me, but when I try to use that technique on oracle forms it hits me error
error 591 this feature is not supported in client side programmingI know I can use cursors to loop through the records of oracle tables ,
but I'm convenient while using collections and arrays
for example
Set Serveroutput On
Declare
Type Rec_T Is Record (
Empid Number ,
Empname Varchar2(100)
Type V_R Is Table Of Rec_T Index By Binary_Integer;
V_Array V_R;
Begin
Select Employee_Id , First_Name
Bulk Collect
Into V_Array
From Employees;
For Indx In V_Array.First..V_Array.Last Loop
Dbms_Output.Put_Line('employees id '||V_Array(Indx).Empid ||'and the name is '||V_Array(Indx).Empname);
End Loop;
End;I wanna use this same way on oracle forms , for certain purposes , please guide me how can I use ...
thanks...For information, you can use and populate a collection within the Forms application without using the BULK COLLECT
Francoisactually I want to work with arrays , index tables ,
like
record_type (variable , variable2);
type type_name <record_type> index by binary_integer
type_variable type_name;
and in main body of program
select something
bulk collect into type_variable
from any_table;
loop
type_variable(indx).variable , type_variable(indx).variable2;
end loop;
this is very useful for my logic on which I am working
like
type_variable(indx).variable || type_variable(indx-1);
if it's possible with cursors then how can I use cursor that can fullfill my this logic@Francois
if it's possible then how can i populate without using bulk collect?
thanks
and for others replies: if I can use stored procedures please give me any example..
thanks -
Send some example of bulk collect option in loop
Hi
I have three type parameter which is bulk collect from same table
i want to use two of the parameter to verify the data in other table.
and if data won't find using this 3rd bulk collect option to update 3 rd table..
help is appreciated,http://download.oracle.com/docs/cd/E11882_01/appdev.112/e10472/composites.htm
-
ORA-06502 during a procedure which uses Bulk collect feature and nested tab
Hello Friends,
have created one procedure which uses Bulk collect and nested table to hold the bulk data. This procedure was using one cursor and a nested table with the same type as the cursor to hold data fetched from cursor. Bulk collection technique was used to collect data from cursor to nested table. But it is giving ORA-06502 error.
I reduced code of procedure to following to trace the error point. But still error is comming. Please help us to find the cause and solve it.
Script which is giving error:
declare
v_Errorflag BINARY_INTEGER;
v_flag number := 1;
CURSOR cur_terminal_info Is
SELECT distinct
'a' SettlementType
FROM
dual;
TYPE typ_cur_terminal IS TABLE OF cur_terminal_info%ROWTYPE;
Tab_Terminal_info typ_cur_Terminal;
BEGIN
v_Errorflag := 2;
OPEN cur_terminal_info;
LOOP
v_Errorflag := 4;
FETCH cur_terminal_info BULK COLLECT INTO tab_terminal_info LIMIT 300;
EXIT WHEN cur_terminal_info%rowcount <= 0;
v_Errorflag := 5;
FOR Y IN Tab_Terminal_Info.FIRST..tab_terminal_info.LAST
LOOP
dbms_output.put_line(v_flag);
v_flag := v_flag + 1;
end loop;
END LOOP;
v_Errorflag := 13;
COMMIT;
END;
I have updated script as following to change datatype as varchar2 for nested table, but still same error is
comming..
declare
v_Errorflag BINARY_INTEGER;
v_flag number := 1;
CURSOR cur_terminal_info Is
SELECT distinct
'a' SettlementType
FROM
dual;
TYPE typ_cur_terminal IS TABLE OF varchar2(50);
Tab_Terminal_info typ_cur_Terminal;
BEGIN
v_Errorflag := 2;
OPEN cur_terminal_info;
LOOP
v_Errorflag := 4;
FETCH cur_terminal_info BULK COLLECT INTO tab_terminal_info LIMIT 300;
EXIT WHEN cur_terminal_info%rowcount <= 0;
v_Errorflag := 5;
FOR Y IN Tab_Terminal_Info.FIRST..tab_terminal_info.LAST
LOOP
dbms_output.put_line(v_flag);
v_flag := v_flag + 1;
end loop;
END LOOP;
v_Errorflag := 13;
COMMIT;
I could not find the exact reason of error.
Please help us to solve this error.
Thanks and Regards..
Dipali..Hello Friends,
I got the solution.. :)
I did one mistake in procedure where the loop should end.
I used the statemetn: EXIT WHEN cur_terminal_info%rowcount <= 0;
But it should be: EXIT WHEN Tab_Terminal_Info.COUNT <= 0;
Now my script is working fine.. :)
Thanks and Regards,
Dipali..
Maybe you are looking for
-
Hi guys, I'm developing an ADF application in JDev 11.1.1.6.0. I have problem about using arrays in jsp page. I have an iterator that brings me data from UCM. I just want to take every documents seperately and use in a Jquery division by division. Ca
-
Hi i want understand the role of "Management ID" I read that in the BI administration guide but I can not understand the purpose of this parameter Note: The Change Management ID is used for obtaining information related to logging, auditing, job hist
-
RME Syslog Automated Actions with exclude Filter
Dear all, It's possible to realise a Filter with "exclude string"? I search how to for Create action for all Severity 2 without "FAN-FAULT" mnemonic... Best regards
-
Applying a class to a button on a page
Using APEX 4.0.2 Trying to style a button on a form. BUTTON STYLE = Template Based Button BUTTON TEMPLATE = Button BUTTON ATTRIBUTES = class="btn btn-primary" When I firebug the page the only class I see applied is "t3ButtonHtmlMiddle". Is it possibl
-
hi, I like to know besides running 2 or more operating systems,like exchange or SQL ect . what other benefits it has for example when you install 2-3 applications in t hyper_v environment can you use those applications from each client computer or