Associative Array (Object) problems
Here is the function i'm dealing with
i'm reading in a delimited string and using indexed arrays to
break them up and assign the keys and values to an associative
array in a loop.
i'm using variables in the loop and the array loads as
expected in the loop
but outside the loop, the only key is the variable name and
the value is undefined
this is true using dot or array notation, as well as literal
strings for the keys
any help is appreciated
watchSuspendData = function (id, oldval, newval):String {
//the incoming suspendData string is delimited by the
semicolon;
//newval is: firstValue=Yes;captivateKey=1
var listSuspendData:Array = newval.split(";"); // convert it
to a list of key/value pairs
if (listSuspendData.length > 0){
//line 123: listSuspendData.length is: 2
for (i=0; i < listSuspendData.length; i++){ //for each
key/value pair
var keyValArray:Array = new Array();
var myNameValue:String = listSuspendData
//line 127: listSuspendData is: firstValue=Yes
keyValArray = myNameValue.split("="); // split 'em on the
equal sign
var myKey:String = keyValArray[0];
var myVal:String = keyValArray[1];
//keyValArray[0] is: firstValue
//keyValArray[1] is: Yes
// store the key and the value in associative array
suspendDataArray.myKey = myVal;
trace("line 134: suspendDataArray is: " +
suspendDataArray.myKey);
// trace is line 134: suspendDataArray is: Yes on the first
pass and 1 on the second
//the below loop always returns one array key: myKey and the
value as undefined
for(x in suspendDataArray){
trace("x is: " + x); //x is: myKey
trace("the val is: " + suspendDataArray.x); //the val is:
undefined
} //end for
return newval;
on lines 12-13 i assign the key=value pair to string
variables
then on lines 17-18 i assign those values to the associative
array using dot notation
the trace seems to work there
the problem is that when the procedure exits the for loop,
the associative array only has one key (myKey) and no value
(undefined)
all the documentation i've read shows using these types of
arrays with either non-quoted property names like:
myAssocArray.myKey = "somevalue";
or
myAssocArray[myKey] = "somevalue";
i tried assigning the key/value pairs directly from the
indexed arrays, but the result was always undefined
like this:
suspendDataArray.keyValArray[0] = keyValArray[1]
or
suspendDataArray[keyValArray[0]] = keyValArray[1]
i even tried building a string in the loop and trying to
assign all the pairs at once using the curly brace
this is pretty wierd behavior for actionscript or i'm missing
something basic here
thanks for looking
Similar Messages
-
Associative array related problem
Hi All,
When I am trying to use assotiative array in a select statement I recieve the following error:
ORA-06550: line 9, column 22:
PLS-00201: identifier 'COL1' must be declared
ORA-06550: line 9, column 22:
PLS-00201: identifier 'COL1' must be declared
ORA-06550: line 9, column 10:
PL/SQL: ORA-00904: : invalid identifier
ORA-06550: line 9, column 3:
PL/SQL: SQL Statement ignored
Here is the example
--create table MyTable (col1 varchar2(255), col2 varchar2(255))
declare
type m_ttMyTable
is table of MyTable%rowtype index by MyTable.col1%type;
m_tMyTable m_ttMyTable;
m_sCol2 varchar2(255);
begin
select m_tMyTable (col1).col2 /* works with ocntant: select m_tMyTable */('col1').col2
into m_sCol2
from MyTable
where rownum = 1;
end;
--drop table MyTableAny ideas how to workaround this?
ThanksThe only collection types SQL can query are ones defined in SQL using CREATE TYPE. That excludes associative arrays, as they are PL/SQL-only constructs. I'd recommend a nested table collection.
Some more suggestions:
www.williamrobertson.net/documents/collection-types.html -
Associative Array problem in Oracle Procedure
Hi,
I've searched through the internet and this forum and haven't been able to resolve a problem using associative array values within an IN clause. Everything I've read states that I can't use the associative array directly in the SQL statement. I have to convert it to a table and then I can use it. Unfortunately, I'm receiving an "ORA-21700: object does not exist or is marked for delete" error when trying to access the table I've populated from the array. Please note that I have verified the table is actually being populated during the loop. I'm catching the error when referencing it in the SELECT statement.
I've declared the following in the ARCHIVE package specification:
TYPE RSType IS REF CURSOR;
TYPE integer_aat IS TABLE OF INTEGER INDEX BY PLS_INTEGER;
TYPE integer_table IS TABLE OF INTEGER;
The procedure is as follows:
PROCEDURE SEL_SEARCH_RESULTS (v_term IN VARCHAR2,
v_categories IN ARCHIVE.integer_aat,
rs OUT RSType)
AS
/* PURPOSE: Return Search Results for the Category and Keyword Provided
VARIABLES:
v_categories = Document Categories array
v_term = Keyword entered
rs = Result Set
tbl_cat ARCHIVE.integer_table := ARCHIVE.integer_table();
BEGIN
FOR i IN 1 .. v_categories.COUNT
LOOP
tbl_cat.EXTEND(1);
tbl_cat(i) := v_categories(i);
END LOOP;
OPEN rs FOR
SELECT A.ID,
B.CATEGORY,
A.FILENAME,
A.DISPLAY_NAME,
A.COMMENTS
FROM TBL_ARCHIVE_DOCUMENTS A,
TBL_ARCHIVE_DOC_CAT B,
TBL_ARCHIVE_DOC_KEYWORDS C
WHERE A.ID = B.ID
AND A.ID = C.ID
AND B.CATEGORY IN (SELECT * FROM TABLE(tbl_cat))
AND C.KEYWORD = v_term
ORDER BY A.ID;
END SEL_SEARCH_RESULTS;
Any help would be greatly appreciated and thanks in advance,
MattThank you for the quick response. I looked at the example you suggested and made the following changes. Now I'm receiving an "Invalid datatype" error on the "SELECT column_value FROM TABLE(CAST(tbl_cat AS tbl_integer))" statement. I must be missing something simple and I just can't put my finger on it.
PROCEDURE SEL_SEARCH_RESULTS (v_term IN VARCHAR2,
v_categories IN ARCHIVE.integer_aat,
rs OUT RSType)
AS
/* PURPOSE: Return Search Results for the Category and Keyword Provided
VARIABLES:
v_categories = Document Categories array entered
v_term = Keyword entered
rs = Result Set
TYPE tbl_integer IS TABLE OF INTEGER;
tbl_cat tbl_integer;
BEGIN
FOR i IN 1 .. v_categories.COUNT
LOOP
tbl_cat.EXTEND(1);
tbl_cat(i) := v_categories(i);
END LOOP;
OPEN rs FOR
SELECT A.ID,
B.CATEGORY,
A.FILENAME,
A.DISPLAY_NAME,
A.COMMENTS
FROM TBL_ARCHIVE_DOCUMENTS A,
TBL_ARCHIVE_DOC_CAT B,
TBL_ARCHIVE_DOC_KEYWORDS C
WHERE A.ID = B.ID
AND A.ID = C.ID
AND B.CATEGORY IN (SELECT column_value FROM TABLE(CAST(tbl_cat AS tbl_integer)))
AND C.KEYWORD = v_term
ORDER BY A.ID;
END SEL_SEARCH_RESULTS; -
Object tables/associative arrays are using lots of memory what is alternate
I'm using mostly object tables/associative arrays in my package and it is using lots of server memorey so i want to use a different technicque to save momorey .
like using create global temporary table or nested Table Store as or creating table run time at the start and droping it in the end .
do have any suggestion for this ?
for this package i'm retriving data from different table into object tables and do calculation in memorey before i send data to front end for reporting using reference cursor .
give me your suggetion or if you know any example code for this type of process using different technique please let us know .
thank you very much
regards
shailen PatelYou can create a global temporary table like this:
CREATE GLOBAL TEMPORARY TABLE AR_TRIAL_RCPT(
LOC_ACCT_ID NUMBER(12),
ACCT_ID NUMBER(12),
CURRENCY_ID NUMBER(12),
AMT NUMBER(13, 4),
AMT_PRIMARY NUMBER(13, 4)
[ON COMMIT PRESERVE ROWS]
;If you want the table truncated on COMMITs leave out the part in brackets other wise leave off the brackets and the table won't be truncated until your session terminates or you explicitly truncate the table.
You can also define indexes, primary keys, foreign keys, check constraints, etc. on your temporary table if need be to improve processing.
Now when it comes to inserting into your newly minted global temporary table, you should be able to use one of insert statements from the following anonymous PL/SQL block:
CREATE GLOBAL TEMPORARY TABLE AR_TRIAL_RCPT(
LOC_ACCT_ID NUMBER(12),
ACCT_ID NUMBER(12),
CURRENCY_ID NUMBER(12),
AMT NUMBER(13, 4),
AMT_PRIMARY NUMBER(13, 4)
--[ON COMMIT PRESERVE ROWS]
CREATE GLOBAL succeeded.
declare
l_open_receipt_select_1 varchar2(4000) :=
'select 1, 1, 1, 12.05, 12.05 from dual';
l_open_receipt_select_2 varchar2(4000) :=
'select 2, 2, 1, 17.05, 17.05 from dual';
l_open_receipt_select_3 varchar2(4000) :=
'select 3 loc_acct_id,
1 currency_id,
27.05 amt,
3 acct_id,
27.05 amt_primary
from dual';
l_open_receipt_select_4 varchar2(4000) :=
'select 4 loc_acct_id,
1 currency_id,
24.35 amt,
4 acct_id,
24.35 amt_primary
from dual';
l_ins_stmt varchar2(4000);
begin
-- If the column order is known ahead of time and is consistent
-- You can use this form:
l_ins_stmt :=
'insert into ar_trial_rcpt (
loc_acct_id, acct_id, currency_id, amt, amt_primary
) '||l_open_receipt_select_1||
' union all '||
l_open_receipt_select_2;
execute immediate l_ins_stmt;
-- If the column order is NOT known ahead of time or is INconsistent
-- You can use this form:
l_ins_stmt :=
'insert into ar_trial_rcpt (
loc_acct_id, acct_id, currency_id, amt, amt_primary
select loc_acct_id
, acct_id
, currency_id
, amt
, amt_primary
from ('||l_open_receipt_select_3||')
union all
select loc_acct_id
, acct_id
, currency_id
, amt
, amt_primary
from ('||l_open_receipt_select_4||')';
execute immediate l_ins_stmt;
end;
anonymous block completed
select * from ar_trial_rcpt
LOC_ACCT_ID ACCT_ID CURRENCY_ID AMT AMT_PRIMARY
1 1 1 12.05 12.05
2 2 1 17.05 17.05
3 3 1 27.05 27.05
4 4 1 24.35 24.35
4 rows selected -
Would PL/SQL Associative Arrays solve my problem
Hi guys,
I'm new to PL/SQL development really, although i have some limited knowledge that i've relied on for the last couple of years to get by. Anyway, i'll try my best to describe my problem and how i'd like to solution it ...........
I have a table of information that holds a column for decscriptive names of payments and another column holding a difference value, for example :
employee_number | payment_name | difference
00001 | salary | 200.20
00001 | shift | 20.21
00002 | salary | 10.01
00002 | shift | 5.02
00003 | salary | 15.02
00003 | shift | 4.00I'd like to manipulate the way this data is presented, via DBMS_OUTPUT in a summary fashion counting the number of differences between ranges, for example :
payment_name | 0.00 to 10.00 | 10.01 to 100.00 | 100.01 to 99999.99
salary | | 2 | 1
shift | 2 | 1 |I thought it might be possible to use an approach in PL/SQL to mimic this table structure and populate it via a cursor looping through my initial recordset and posting the total count in the associated columns as required. Once the cursor had finished populating the PL/SQL table / array etc i could base my DBMS_OUTPUT on this data.
Or am i completely barking up the wrong tree, would there be a better, more efficient way to solution the problem. I've been reading up on PL/SQL Collections http://docs.oracle.com/cd/B10501_01/appdev.920/a96624/05_colls.htm#19661 but can't really determine is this is a) the correct approach or b) should i try using an associative array, nested table or varray?
Thanks in advance guys, just need a pointer in the right direction.It sounds like you can just pivot the data
SELECT payment_name,
SUM( CASE WHEN difference BETWEEN 0 and 10 THEN 1 ELSE 0 END ) "0.00 to 10.00",
SUM( CASE WHEN difference BETWEEN 10.01 and 100 THEN 1 ELSE 0 END ) "10.01 to 100.00",
SUM( CASE WHEN difference BETWEEN 100.01 and 99999.99 THEN 1 ELSE 0 END ) "100.01 to 99999.99"
FROM table_name
GROUP BY payment_nameYou can then do whatever you want with the data this query returns.
Justin -
Passing ARRAY object to stored procedure problem
I've created a stored procedure that accepts as a parameter a
database type
that I have defined as a VARRAY. (create type XXX)
When I attempt to pass an ARRAY object to this stored procedure
through JDBC
(Thin-client driver) I recieve the Oracle internal error ORA-
00600 and the
first "parameter" is [12760].
Has anyone else attempted the same sort of thing w/ success?
I am including the Java source code to help the investigation
private void chad(int[] railcarIds) throws NonFatalDBException,
FatalDBException {
CallableStatement theStatement = null;
try {
theStatement = this.getDatabaseConnection().prepareCall("{call
RomsRepairPackage.chad(?)} ");
// create an ARRAY object to send to the procedure
ArrayDescriptor ad =
ArrayDescriptor.createDescriptor("RAILCARIDVARRAYTYPE",
this.getDatabaseConnection());
ARRAY theArray = new ARRAY(ad, this.getDatabaseConnection(),
railcarIds);
// set the input parameter which is the array of railcar ids
((OracleCallableStatement)theStatement).setARRAY(1, theArray);
theStatement.execute();
theStatement.close();
} catch (SQLException sqle) {
System.out.println("ouch");
Thank you for any help,
Chad Sheley
Senior Consultant
Cap Gemini
Des Moines, IA
nullHi
Can u plzz help me as to how did u write the procedure to take arrays as input.I also have to write aprocedure that takes arrays and returns arrays.Plzz can u give me a working sample as I have not found any help anywhere
<BLOCKQUOTE><font size="1" face="Verdana, Arial">quote:</font><HR>Originally posted by Chad Sheley ([email protected]):
I've created a stored procedure that accepts as a parameter a
database type
that I have defined as a VARRAY. (create type XXX)
When I attempt to pass an ARRAY object to this stored procedure
through JDBC
(Thin-client driver) I recieve the Oracle internal error ORA-
00600 and the
first "parameter" is [12760].
Has anyone else attempted the same sort of thing w/ success?
I am including the Java source code to help the investigation
private void chad(int[] railcarIds) throws NonFatalDBException,
FatalDBException {
CallableStatement theStatement = null;
try {
theStatement = this.getDatabaseConnection().prepareCall("{call
RomsRepairPackage.chad(?)} ");
// create an ARRAY object to send to the procedure
ArrayDescriptor ad =
ArrayDescriptor.createDescriptor("RAILCARIDVARRAYTYPE",
this.getDatabaseConnection());
ARRAY theArray = new ARRAY(ad, this.getDatabaseConnection(),
railcarIds);
// set the input parameter which is the array of railcar ids
((OracleCallableStatement)theStatement).setARRAY(1, theArray);
theStatement.execute();
theStatement.close();
} catch (SQLException sqle) {
System.out.println("ouch");
Thank you for any help,
Chad Sheley
Senior Consultant
Cap Gemini
Des Moines, IA<HR></BLOCKQUOTE>
null -
How to use Associative Array in sql query?
Hello,
I have a problem on using Associative Array variable on query; and my query is similar to the one below;
TYPE OTHERGENERICS IS TABLE OF NUMBER(10) INDEX BY BINARY_INTEGER;
othersGenerics OTHERGENERICS;
CURSOR cursor_othersGenerics IS
select master.GENERICCODEID
from ASMTRG_ARTICLEMASTER master
join ASMTRG_ARTICLEMAP map on MAP.ARTICLECODEID = MASTER.ID
group by MASTER.GENERICCODEID
minus
select FGG.GENERICCODEID
from asmtrg_icfocusgroup fg
join asmtrg_icfocusgrpchannel fgc on FGC.GROUPID = FG.ID and fgc.isactive=1
join asmtrg_icfocusgengroup fgg on FGG.GROUPID = FG.ID and FGg.ISACTIVE=1
where fgc.channelid=1 and fg.isactive = 1
group by FGG.GENERICCODEID;
BEGIN
OPEN cursor_othersGenerics;
FETCH cursor_othersGenerics BULK COLLECT INTO othersGenerics;
CLOSE cursor_othersGenerics;
SELECT icfrd.*,
CASE
WHEN EXISTS(select ta.genericcodeid from <???XXX???> ta where ta.genericcodeid = icfgrp.genericcodeid) THEN -1
ELSE icfrd.icfgroupid
END CLASSIFICATION
FROM ASMTRGVIW_ICFOCUSREPORTDATA icfrd
LEFT JOIN ASMTRG_ICFOCUSGROUP icfgrp on icfrd.ICFGROUPID = icfgrp.ID
WHERE (channelId IS NULL OR icfrd.CHANNELID = channelId)
AND (asmCodeId IS NULL OR icfrd.ASMCODEID = asmCodeId)
AND (yearId IS NULL OR icfrd.YEARID = yearId)
AND (monthId IS NULL OR icfrd.MONTHID = monthId)
END;
By the way this is a part of my function.
The "othersGenerics" is my associative array variable and <???XXX???> is the place where I need to use my "othersGenerics" array to check. So far I've tried
"select ta.genericcodeid from table(cast(otherGenerics as OTHERGENERICS)) ta where ta.genericcodeid = icfgrp.genericcodeid",
"select ta.genericcodeid from table(otherGenerics) ta where ta.genericcodeid = icfgrp.genericcodeid",
"select ta.genericcodeid from otherGenerics ta where ta.genericcodeid = icfgrp.genericcodeid"
and these are not working.
What is your suggestions?Your type will have to be created as an independent object in your schema. So CREATE TYPE cannot be in your function declaration, it has to be outside it. (And then the line inside your declaration that defines the type will have to be removed.)
But now I can see that you use this array as a kind of "temporary lookup table" - you populate the array and then use it for lookup in your select statement. An alternative way of doing this could be like this completely without arrays:
with othergenerics as (
select master.GENERICCODEID
from ASMTRG_ARTICLEMASTER master
join ASMTRG_ARTICLEMAP map on MAP.ARTICLECODEID = MASTER.ID
group by MASTER.GENERICCODEID
minus
select FGG.GENERICCODEID
from asmtrg_icfocusgroup fg
join asmtrg_icfocusgrpchannel fgc on FGC.GROUPID = FG.ID and fgc.isactive=1
join asmtrg_icfocusgengroup fgg on FGG.GROUPID = FG.ID and FGg.ISACTIVE=1
where fgc.channelid=1 and fg.isactive = 1
group by FGG.GENERICCODEID
SELECT icfrd.*,
CASE
WHEN EXISTS(select ta.genericcodeid from othergenerics ta where ta.genericcodeid = icfgrp.genericcodeid) THEN -1
ELSE icfrd.icfgroupid
END CLASSIFICATION
FROM ASMTRGVIW_ICFOCUSREPORTDATA icfrd
LEFT JOIN ASMTRG_ICFOCUSGROUP icfgrp on icfrd.ICFGROUPID = icfgrp.ID
WHERE (channelId IS NULL OR icfrd.CHANNELID = channelId)
AND (asmCodeId IS NULL OR icfrd.ASMCODEID = asmCodeId)
AND (yearId IS NULL OR icfrd.YEARID = yearId)
AND (monthId IS NULL OR icfrd.MONTHID = monthId)
...The with clause (subquery factoring) you can think of as a kind of temp table called othergenerics created "on-the-fly".
The optimizer may decide to actually create a temp table for you and use in the lookup, or it may decide to rewrite the query into suitable joins or nested loops or hashing - whatever the optimizer decides will be the optimal way of doing things :-)
So unless you use your array other places in your function, I would recommend dropping the array completely, skip populating an array, and instead use a with clause for your temporary lookup. -
Parsing XMLType into an associative array
I'm try to build a procedure that can take an XMLType as a parameter. What I would like to do be able to extract both the node names and the string values from each tag of the XML and put them into basically a key --> value associative array.
Ex:
<envelope>
<node1>value1</node1>
<node2>value2</node2>
</envelope>
Would be put into an array structured like: array['node1'] = 'value1', array['node2'] = 'value2', etc.
I'm not entirely sure how I go about looping through the XMLType and extracting each node name and its value. I'm not worried about repeating tag names.. I know that will not be an issue in any of the XMLTypes that I'm using.
Would anyone be able to offer any suggestions? If not how to go about doing exactly that, then at least some insight as to how I can loop through and extract nodes and/or values without specifying the specific XPaths?
Thanks in advance!Hi Roger,
This is a good description of your process. Just add your Oracle DB Version somewhere. Want you want is a method to map your XML to a relationship design (some special variant of object-relational-modelling).
I still see two choices:
The programmatic approach (as you described):
Have multiple procedures where you input an XML. Each procedure is reflecting a different part of the transformation process. So it depends from the Message which procedure you will call.
Example
SQL*Plus: Release 9.2.0.2.0 - Production on Thu Aug 14 17:53:25 2008
Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved.
Connected to:
Oracle9i Enterprise Edition Release 9.2.0.8.0 - 64bit Production
With the Partitioning, OLAP and Oracle Data Mining options
JServer Release 9.2.0.8.0 - Production
SQL> create table testtab (username varchar2(100));
Table created.
/* the following insert part should be in some packaged procedure, */
/* this just don't work on my 9i version, but should in 10g */
SQL> insert into testtab (username)
2 select substr(extractvalue(column_value,'*/text()'),1,100)
3 from table(xmlsequence(extract( xmltype('<envelope>'||
4 '<username>Roger</username>'||
5 '<username>Sven</username>'||
6 '</envelope>'),'envelope/username')));
2 rows created.
SQL> select * from testtab;
USERNAME
Roger
Sven
SQL> The declarative approach:
Insert the XML into a SchemaBased Table. The XML Schema will provide the mapping to your relational tables automagically. Problem here is the writing, handling and evolving of the XML Schema (Sub schemas are allowed too). -
Associative Array our only option?
Hello,
I'm having a problem accepting associative arrays as the only option I have for getting data from a stored procedure. I have a good reason for not wanting to use ref cursors as I am using the stored procedure to manipulate data which I in turn would like to pass back to VB through the stored procedure and would rather not have to insert he data into a table just to re-select it for a ref cursor.
My main concern is that with associative arrays I am expected to define the number of return results before I even generate the data. Also from what I can see I am required to set the data length for each and every item in said array one at a time. All this overhead seems like more work than what I would have to do to utilizer a reference cursor. Is there a right way to do this? I would really like to do the most straight forward way I can without the extra processing.Hi,
Here's a blog post of mine that illustrates using pipelined functions and PL/SQL to return results:
http://oradim.blogspot.com/2007/10/odpnet-tip-using-pipelined-functions.html
Not sure if that will be helpful in your case, but perhaps it might be a place to start anyway.
- Mark -
Hi All,
I've searched through this forum trying to find information I'm needing on associative arrays with a varchar2 index without luck. What I'm looking for is a way to get the index or "key" values of the array without knowing what they are. Meaning, I wouldn't have to know the index value when designing the array but would be able to utilize them values at runtime. For those familiar with Java it would be like calling the keySet() method from a Map object.
So, if I have an array of TYPE COLUMN_ARRAY IS TABLE OF VARCHAR2(4000) INDEX BY VARCHAR2(100) is there any way to dynamically get the index values without knowing what they are?
Any help is appreciated.
ThanksThanks for the response.
I am aware of using FIRST and NEXT for iterating the array but can I extract the index value of the current element into a variable when I don't know what the index value is at runtime ?
Thanks -
Associative array comparison and INSERT upon IF condition
Hi Guys,
I have written this pl sql code to identify non existing sellers and insert their sales channel information into the dimension table (dimensional table update).
Somehow,......nothing is inserted and this script runs for 12 hours+ without any result. the sql autotrace shows no result and the explain plan (button on sql developer throws upon clicking "missing keyword". I have no
information what is going on/wrong. Does anyone spot an error?
UNDEFINE DimSales;
UNDEFINE FactTable;
DEFINE DimSales = 'testsales';
DEFINE FactTable = 'testfact';
DECLARE
v_SellerNo VarChar(9);
v_error_code T_ERRORS.v_error_code%TYPE;
v_error_message T_ERRORS.v_error_message%TYPE;
TYPE assoc_array_str_type1 IS TABLE OF VARCHAR2(32) INDEX BY PLS_INTEGER;
v1 assoc_array_str_type1;
TYPE assoc_array_str_type2 IS TABLE OF VARCHAR2(32) INDEX BY PLS_INTEGER;
v2 assoc_array_str_type2;
BEGIN
--Collect all distinct SellerNo into associative array (hash table)
select distinct SellerNo bulk collect into v1 from &FactTable;
select distinct seller_id bulk collect into v2 from &DimSales;
v_SellerNo := v1.first;
loop
exit when v1 is null;
--1 Check if v_SellerNo already exists in DIM_Sales (if NOT/FALSE, its a new seller and we can insert all records for that seller
if (v2.exists(v_SellerNo)=false) THEN
INSERT INTO &DimSales (K_Sales,REG,BVL,DS, VS,RS,GS,VK)
(SELECT DISTINCT trim(leading '0' from RS||GS) ,REG BVL,DS,VS,RS,GS,VK from &FactTable where SellerNo =v_SellerNo);
--ELSE
end if;
v_SellerNo := v1.next(v_SellerNo);
end loop;
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
--v_error_code := SQLCODE
--v_error_message := SQLERRM
--INSERT INTO t_errors VALUES ( v_error_code, v_error_message);
END;
---------------------------------------------------------------Distinct clause requires a sort. Sorts can be very expensive.
Bulk collects that are not constrained in fetch size, can potentially fetch millions of rows - requiring that data to be wholly read into server memory. I have seen how this can degrade performance so badly that the kernel reboots the server.
Using PL/SQL loops to process and insert/update/delete data is often problematic due to its row-by-row approach - also called slow-by-slow approach. It is far more scalable letting SQL do the "loop" processing, by using joins, sub-selects and so on.
Where the conditional processing is too complex for SQL to handle, then PL/SQL is obviously an alternative to use. Ideally one should process data sets as oppose to rows in PL//SQL. Reduce context switching by using bulk fetches and bulk binds.
But PL/SQL cannot execute in parallel as the SQL it fires off can. If after all the optimisation, the PL/SQL process still needs to hit a million rows to process, it will be slow irrespective of how optimal that PL/SQL approach and design - simply because of the number of rows and the processing overheads per row.
In that case, the PL/SQL code itself need to be parallelised. There are a number of ways to approach this problem - the typical one is to create unique and distinct ranges of rows to process, spawn multiple P/SQL processes, and provide each with a unique range of rows to process. In parallel.
So you need to look close at what you are trying to achieve, what the workloads are, and how to effectively decrease the workloads and increase the processing time of a workload.
For example - finding distinct column values. You can pay for that workload when wanting that distinct list. And each time afterward repeat that workload when wanting that distinct list. Or you can pay for that workload up-front with the DML that creates/updates those values - and use (for example) a materialised view to maintain a ready to use distinct list of values.
Same workload in essence - but paying once for it and up-front as oppose to each time you execute your code that needs to dynamically build that distinct list.
Kent Crotty did tests and showed stunning performance improvements with bulk collect and forall, up to 30x faster:Bulk processing is not a magical silver bullet. It is a tool. And when correctly use, the tool does exactly what it was designed to do.
The problem is using a hammer to drive in screws - instead of a screwdriver. There's nothing "stunning" about using a screwdriver. It is all about using the correct tool.
If the goal of the swap daemon is to free up "idle" chunks of memory, and try to use that memory for things like file cache instead, what does that have to do with bulk processing?The swap daemon reads virtual memory pages from swap space into memory, and writes virtual pages from memory to swap space.
What does it have to do with bulk processing? A bulk fetch reads data from the SGA (buffer cache) into the PGA (private process memory space). The larget the fetch, the more memory is required. If for example 50% of server memory is required for a bulk collection that is 2GB in size, then that will force in-use pages from memory to swap space.. only to be swapped back again as it is needed, thereby forcing other in-use pages to swap. The swap daemon will consume almost all the CPU time swapping hot pages continually in and out of memory. -
I have a SELECT query like
SELECT ename, sal from emp;
I want the ename column values from the output of the above query to be populated into an Associative array. So i did the following steps
DECLARE
TYPE ename_type IS TABLE OF VARCHAR2(10) INDEX BY PLS_INTEGER;
v_ename ename_type;
What is the next step by which i could populate the v_ename variable with the ename column values from the above query?One slight problem.
The ename is derived from a large SELECT query joining three tables. The SELECT query looks like
SELECT ename,max(sal) from ...............;
I only need ename values from this SELECT query to be populated to the Assosiative array (v_ename). But I cannot exclude max(sal) from the query due to aggregate function's technical reasons(GROUP BY and so on).
So when i try to populate the associative array v_ename by issuing the following command:
SELECT ename BULK COLLECT INTO v_ename FROM (SELECT ename,max(sal) from ...............) ;
The max(sal) value in the SELECT query is going to be a problem. How do i solve this? -
Associative Array with subsripts(Index) as Varchar2
Hi All,
I m using Oracle Version 10.1.0.2.0 - Production
I have the following requirement:
The Associative array which holds the value with the subscripts(Index) as database table column.
Create table Period_master
Period_code_c Varchar2(10),
Period_frm_dt Date,
Period_to_dt Date,
Year_code_c Varchar2(10)
Insert into period_master values ('10',to_date('01/01/2012','dd/mm/rrrr'),to_date('31/01/2012','dd/mm/rrrr'),'2011-2012');
Insert into period_master Values ('11',to_date('01/02/2012','dd/mm/rrrr'),to_date('29/02/2012','dd/mm/rrrr'),'2011-2012');
Insert into period_master Values ('12',to_date('01/03/2012','dd/mm/rrrr'),to_date('31/03/2012','dd/mm/rrrr'),'2011-2012');
Insert into period_master Values ('13',to_date('01/04/2012','dd/mm/rrrr'),to_date('30/04/2012','dd/mm/rrrr'),'2012-2013');
Insert into period_master Values ('14',to_date('01/05/2012','dd/mm/rrrr'),to_date('31/05/2012','dd/mm/rrrr'),'2012-2013');
Commit;
SQL > Select * from Period_Master;
Period_code --- Period_frm_dt --- Period_to_dt ---- Year_code_c
10 --- 01/01/2012 --- 31/01/2012 --- 2011-2012
11 --- 01/02/2012 --- 29/02/2012 --- 2011-2012
12 --- 01/03/2012 --- 31/03/2012 --- 2011-2012
13 --- 01/04/2012 --- 30/04/2012 --- 2012-2013
14 --- 01/05/2012 --- 31/05/2012 --- 2012-2013
My Requirement is get the Period_frm_dt,period_end_dt and yearcode based on period_code (which is input parameters from my procedure) by using Collections.
I have to create one PLSQL table type which having the subscripts(Index) as period_code which is Varchar2 type;
I have written follwing code ,but it's not giving the desired output:
Declare
iv_period Varchar2(10);
Cursor cur_prd(cp_period Varchar2) is select * from Period_Master Where Period_code_c = cp_period;
TYPE PRD_REC_TY IS TABLE OF cur_prd%ROWTYPE INDEX BY PLS_INTEGER;
lv_prd_data prd_rec_ty;
lv_prd PERIOD_MASTER.period_code_c%TYPE ;
lv_frm_dt PERIOD_MASTER.Period_frm_dt%TYPE ;
lv_to_dt PERIOD_MASTER.Period_to_dt%TYPE ;
lv_yr_code PERIOD_MASTER.Year_code_c%TYPE ;
Begin
iv_period := :period;
Open Cur_prd(iv_period);
Loop
Fetch cur_prd BULK COLLECT into lv_prd_data;
EXIT WHEN cur_prd%NOTFOUND;
End Loop;
Close Cur_Prd;
If lv_prd_data.COUNT > 0 THEN
For i IN lv_prd_data.FIRST .. lv_prd_data.LAST
LOOP
lv_prd := lv_prd_data(i).pERIOD_cODE_C;
lv_frm_dt := lv_prd_data(i).Period_frm_dt;
lv_to_dt := lv_prd_data(i).Period_to_dt;
lv_yr_code := lv_prd_data(i).Year_Code_c;
Dbms_output.Put_line('For Period code : '||lv_prd||' the Year code is : '||lv_yr_code);
Dbms_output.Put_line('For Period code : '||lv_prd||' the Period_from_dt is : '||lv_frm_dt);
Dbms_output.Put_line('For Period code : '||lv_prd||' the Period_to_dt is : '||lv_to_dt);
END LOOP;
End if;
Exception
When Others Then
Dbms_output.Put_line('Here Error Found: '||SQLERRM);
End;
But My requirement is to get the FRM_DT,TO_DT and YEAR CODE as per the following:
For Period Code :*11* -- the YearCode is --- *2011-2012*
For Period Code :*11* -- the From Dt is --- *01/02/2012*
For Period Code :*11* -- the To Dt is --- *29/02/2012*
for Period Code : *14* -- the Yearcode is --- *2012-2013*
For Period Code : *14* -- the From Dt is --- *01/05/2012*
For Period Code : *14* -- the To Dt is --- *31/05/2012*
So on...
Like:
lv_yr_code := lv_period_data(iv_period).Year_code_c;
lv_frm_dt := lv_period_data(iv_period).Period_frm_dt;
lv_to_dt := lv_period_data(iv_period).Period_to_dt;
Dbms_output.Put_line('For Period code : '||iv_period||' the Year code is : '||lv_yr_code);
Dbms_output.Put_line('For Period code : '||iv_period||' the Period_from_dt is : '||lv_frm_dt);
Dbms_output.Put_line('For Period code : '||iv_period||' the Period_to_dt is : '||lv_to_dt);
How do i resolve the above scenario.Please help me to resove the above scenario.
Regards,
PrasantaHi, Pransanta,
Prasanta wrote:
... My Requirement is get the Period_frm_dt,period_end_dt and yearcode based on period_code (which is input parameters from my procedure) by using Collections.Sorry, I don't understand.
What is the porocedure you mentioned? Do you mean the anonymous block that you posted? If not, post the procedure. How is it related to the anonymous block? E.g., does the anonymous block need to call the procedure?
I have to create one PLSQL table type which having the subscripts(Index) as period_code which is Varchar2 type;
I have written follwing code ,but it's not giving the desired output:
Declare
iv_period Varchar2(10);Please format your code, and use \ tags to keep the formatting when you post it on this site.
See the forum FAQ {message:id=9360002}
Cursor cur_prd(cp_period Varchar2) is select * from Period_Master Where Period_code_c = cp_period;You're only looking for a single given period_code_c. If you want to get all rows, lose the WHERE clause. If you want to multiple rows, but not all rows, then use an appropriate WHERE clause.
TYPE PRD_REC_TY IS TABLE OF cur_prd%ROWTYPE INDEX BY PLS_INTEGER;
lv_prd_data prd_rec_ty;
lv_prd PERIOD_MASTER.period_code_c%TYPE ;
lv_frm_dt PERIOD_MASTER.Period_frm_dt%TYPE ;
lv_to_dt PERIOD_MASTER.Period_to_dt%TYPE ;
lv_yr_code PERIOD_MASTER.Year_code_c%TYPE ;
Begin
iv_period := :period;Post the code that declares and sets :period.
Open Cur_prd(iv_period);
Loop
Fetch cur_prd BULK COLLECT into lv_prd_data;
EXIT WHEN cur_prd%NOTFOUND;
End Loop;
Close Cur_Prd;
If lv_prd_data.COUNT > 0 THEN
For i IN lv_prd_data.FIRST .. lv_prd_data.LAST
LOOP
lv_prd := lv_prd_data(i).pERIOD_cODE_C;
lv_frm_dt := lv_prd_data(i).Period_frm_dt;
lv_to_dt := lv_prd_data(i).Period_to_dt;
lv_yr_code := lv_prd_data(i).Year_Code_c;If the block is just supposed to do what it's doing now; then you don't need all these local variables. It's simpler just to teference lv_prd_data.
If you're planning to add some other code to the block later, then the local variables could be useful.
Dbms_output.Put_line('For Period code : '||lv_prd||' the Year code is : '||lv_yr_code);
Dbms_output.Put_line('For Period code : '||lv_prd||' the Period_from_dt is : '||lv_frm_dt);
Dbms_output.Put_line('For Period code : '||lv_prd||' the Period_to_dt is : '||lv_to_dt);
END LOOP;
End if;
Exception
When Others Then
Dbms_output.Put_line('Here Error Found: '||SQLERRM);Only use an EXCEPTION section when you need to. The EXCEPTION section above is only hiding some information about the error.
End;
But My requirement is to get the FRM_DT,TO_DT and YEAR CODE as per the following:
For Period Code :*11* -- the YearCode is --- *2011-2012*
For Period Code :*11* -- the From Dt is --- *01/02/2012*
For Period Code :*11* -- the To Dt is --- *29/02/2012*
for Period Code : *14* -- the Yearcode is --- *2012-2013*
For Period Code : *14* -- the From Dt is --- *01/05/2012*
For Period Code : *14* -- the To Dt is --- *31/05/2012*
So on...
Like:
lv_yr_code := lv_period_data(iv_period).Year_code_c;
lv_frm_dt := lv_period_data(iv_period).Period_frm_dt;
lv_to_dt := lv_period_data(iv_period).Period_to_dt;
Dbms_output.Put_line('For Period code : '||iv_period||' the Year code is : '||lv_yr_code);
Dbms_output.Put_line('For Period code : '||iv_period||' the Period_from_dt is : '||lv_frm_dt);
Dbms_output.Put_line('For Period code : '||iv_period||' the Period_to_dt is : '||lv_to_dt);
How do i resolve the above scenario.Please help me to resove the above scenario.
Regards,
PrasantaIf the problem is that you need to show all period_code_cs, not just one, then you can do this:DECLARE
CURSOR cur_prd
IS SELECT *
FROM period_master
ORDER BY period_code_c;
TYPE prd_rec_ty IS TABLE OF cur_prd%ROWTYPE INDEX BY PLS_INTEGER;
lv_prd_data prd_rec_ty;
BEGIN
OPEN cur_prd;
FETCH cur_prd BULK COLLECT into lv_prd_data;
CLOSE cur_prd;
IF lv_prd_data.COUNT > 0
THEN
FOR i IN lv_prd_data.FIRST .. lv_prd_data.LAST
LOOP
dbms_output.put_line ( 'For Period code : '
|| lv_prd_data(i).period_code_c
|| ' the Year code is : '
|| lv_prd_data(i).year_code_c
dbms_output.Put_line ( 'For Period code : '
|| lv_prd_data(i).period_code_c
|| ' the Period_from_dt is : '
|| lv_prd_data(i).period_frm_dt
dbms_output.put_line ( 'For Period code : '
|| lv_prd_data(i).period_code_c
|| ' the Period_to_dt is : '
|| lv_prd_data(i).period_to_dt
END LOOP;
END IF;
END; -
Associative array two variable comparison :update table error
Hi,
i am using associative array to update the version number of table
-i declare two associative array to compare the column from two table (temp,main tables)values in loop
-if id's of both variable(for temp and main table) are equal and column of either of table not matching then it should update the version no of temp table
-if id's not equal i.e record only exists temp table then update null version number annd increment it by 1
-following is the structure and procedure --it shows the matching and non matching records but for the update statement it not giving expected output i.e it updates all records irrespective of the condition provided
-i tried to put condition in update as well as in the if statement but it updates all record
....suggestion and help highly appreciate. thankx in advance !!!
/*--table structure and data--*/
CREATE TABLE "TEMP_TABLE"
( "ID" NUMBER NOT NULL ENABLE,
"COL1" VARCHAR2(20 BYTE),
"COL2" VARCHAR2(20 BYTE),
"VERSION" NUMBER
INSERT INTO TEMP_TABLE VALUES (101,'A','B',NULL);
INSERT INTO TEMP_TABLE VALUES (102,'x','y',NULL);
INSERT INTO TEMP_TABLE VALUES (103,'r','t',NULL);
CREATE TABLE "MAIN_TABLE"
( "ID" NUMBER NOT NULL ENABLE,
"COL1" VARCHAR2(20 BYTE),
"COL2" VARCHAR2(20 BYTE),
"VERSION" NUMBER
INSERT INTO MAIN_TABLE VALUES (101,'A','B',1);
/*------update version procedure----------*/
DECLARE
TYPE T_tmp_table IS TABLE OF tmp_table %ROWTYPE INDEX BY PLS_INTEGER;
TYPE T_main_table IS TABLE OF main_table%ROWTYPE INDEX BY PLS_INTEGER;
l_tmp_table T_tmp_table;
l_main_table T_main_table;
BEGIN
SELECT * BULK COLLECT INTO l_tmp_table FROM tmp_table;
SELECT * BULK COLLECT INTO l_main_table FROM main_table;
FOR i IN 1 .. l_tmp_table.count
LOOP
FOR j IN 1 .. l_main_table.count
LOOP
if(l_tmp_table(i).ID = l_main_table(j).ID AND l_tmp_table(i).VERSION IS NULL) then
---this first if loop updates temp table version irrespective of l_tmp_table.ID=l_main_table.ID orl_tmp_table. ID<>l_main_table.ID .it display proper matching and non-matching records.
dbms_output.put_line('matching ids from tmp and main are :'||l_tmp_table(i).ID||' '||l_main_table(j).ID);
UPDATE tmp_table SET VERSION = l_tmp_table(i).version +1;
--where l_tmp_table(i).ID = l_main_table(j).ID --
end if;
if (l_tmp_table(i).ID <> l_main_table(j).ID) then
dbms_output.put_line('non matching ids from tmp and main are :'||l_tmp_table(i).ID||' '||l_main_table(j).ID);
UPDATE tmp_table SET VERSION = l_tmp_table(i).version +1;
--where l_tmp_table(i).ID <> l_main_table(j).ID
end if;
END LOOP;
END LOOP;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('OTHER');
END;Hello user8937641
I think there is a problem with the logic of your SQL-Code.
But maybe in this formatted structure you can see where your problem is. -> I can not say it because I do not know what is the requirement.
I hope it helps...
/*------update version procedure----------*/
DECLARE
TYPE T_tmp_table IS TABLE OF tmp_table %ROWTYPE INDEX BY PLS_INTEGER;
TYPE T_main_table IS TABLE OF main_table%ROWTYPE INDEX BY PLS_INTEGER;
l_tmp_table T_tmp_table;
l_main_table T_main_table;
BEGIN
SELECT * BULK COLLECT INTO l_tmp_table FROM tmp_table;
SELECT * BULK COLLECT INTO l_main_table FROM main_table;
FOR i IN 1 .. l_tmp_table.count
LOOP
FOR j IN 1 .. l_main_table.count
LOOP
IF l_tmp_table(i).ID = l_main_table(j).ID
AND l_tmp_table(i).VERSION IS NULL
THEN
---this first if loop updates temp table version irrespective of l_tmp_table.ID=l_main_table.ID orl_tmp_table. ID<>l_main_table.ID .it display proper matching and non-matching records.
dbms_output.put_line('matching ids from tmp and main are :'||l_tmp_table(i).ID||' '||l_main_table(j).ID);
UPDATE tmp_table
SET version = l_tmp_table(i).version +1;
WHERE id = l_tmp_table(i).ID
END IF;
IF l_tmp_table(i).ID <> l_main_table(j).ID
THEN
dbms_output.put_line('non matching ids from tmp and main are :'||l_tmp_table(i).ID||' '||l_main_table(j).ID);
-- Maybe you do not need this update:
UPDATE tmp_table
SET version = l_tmp_table(i).version +1;
WHERE id = l_tmp_table(i).ID
END IF;
COMMIT;
END LOOP;
END LOOP;
EXCEPTION WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Error at Executing the PLSQL-Block - ' || SQLERRM);
END; -
Returning collection-associative array from pl-sql procedure
CREATE OR REPLACE procedure test_ganesh( p_deptno IN number,gana out PARTIES_RESULT)
is
query varchar2(200);
PARTY_ID varchar2(200);
PARTY_CODE varchar2(200);
PARTY_NAME varchar2(200);
PARTY_SEQ VARCHAR2(200);
counter number;
TYPE PARTIES IS TABLE OF varchar2(2000) index by binary_integer;
txn_parties PARTIES;
type PARTIES_RESULT IS TABLE OF PARTIES index by binary_integer;
total_result PARTIES_RESULT;
TYPE EmpTyp IS REF CURSOR;
p_du EmpTyp;
p_cursor EmpTyp;
global_counter number;
begin
global_counter:=1;
counter:=1;
open p_cursor FOR
select A.ref_no
from ot_lc_txn_details A
where rownum <12;
LOOP
FETCH p_cursor INTO query;
EXIT WHEN p_cursor%NOTFOUND;
counter:=1;
open p_du FOR
select party_id,party_code,seq_no,party_name from ot_txn_party where ref_no=query;
LOOP
FETCH p_du INTO PARTY_ID,PARTY_CODE,PARTY_SEQ,PARTY_NAME;
EXIT WHEN p_du%NOTFOUND;
txn_parties(counter):=PARTY_ID || '&&&' || PARTY_CODE || '&&&'||PARTY_SEQ || '&&&' || PARTY_NAME;
counter:=counter+1;
END LOOP;
CLOSE p_du;
total_result(global_counter):=txn_parties;
global_counter:=global_counter+1;
END LOOP;
CLOSE p_cursor;
--open gana FOR SELECT * FROM table(cast(total_result as PARTIES_RESULT)) ;
end;
The error comes at line one, PLS-00905- object PARTIES_RESULT is invalid.
i have used the create type thing to create this type.
if i remove the out parameter it works, no compilation error.
Questions i) How to return the associative array as out parameter?
ii)Am i doing aynthing qrong here?
iii) Can i open a ref cursor to this associative array and then return that ref_cursor?
Please anyone reply back, Thanks in advance
Message was edited by:
user649602As an example:
SQL> create type PARTIES is table of varchar2(2000);
2 /
Type created.
SQL> create or replace procedure proc1(p_deptno number,gana out parties) as
2 begin
3 select ename
4 bulk collect into gana
5 from emp
6 where deptno = p_deptno;
7 end;
8 /
Procedure created.
Maybe you are looking for
-
"No such file or directory" errors on Time Machine backup volume
I remotely mounted the Time Machine backup volume onto another Mac and was looking around it in a Terminal window and discovered what appeared to be a funny problem. If I "cd" into some folders (but not all) and do a "ls -la" command, I get a lot of
-
- How do you refer to an HTML carriage return in PHP?
Someone sent me a php script that replaces foul language with kinder words in message board postings. I'd like the same script to weed out carriage returns, but we can't find the correct syntax for it. We're using : $patterns[0] = '/\n\r/'; What's th
-
File to mail scenario with zip file as an attachment
Hi experts, I have a file to mail scenario.The mail contains a zip file as an attachment. The file in the input folder is a zip file. I want to send this zip file via email using mail adapter.How can i achieve this?Please help me to solve it out. Reg
-
Considering 24" imac but afraid of Freezing
I am currently considering buying the 2.4ghz 24" imac. It seems like it would suite my needs as a good machine to use for Logic Studio 8. I am scared because i am seeing alot of threads of freeezing. The Question is... Is this a common problem on a m
-
Accept terms and conditions of iTunes
When I try and accept terms and conditions at iTunes no accept button comes up.