Skip to Main Content
  • Questions
  • using a collection (nested table) in a query join fails when it's inside a proc

Breadcrumb

Question and Answer

Tom Kyte

Thanks for the question, Brian.

Asked: March 05, 2002 - 10:34 am UTC

Last updated: March 05, 2002 - 1:21 pm UTC

Version: 8.1.6

Viewed 1000+ times

You Asked

I know that if I have a simple table with a collection (nested table) I can do the simple select to get the columns...

in Oracle's simple example:

</code> http://metalink.oracle.com/metalink/plsql/ml2_documents.showDocument?p_database_id=NOT&p_id=69467.1 <code>

Example 21 - Collection Unnesting using the TABLE operator
----------------------------------------------------------

SELECT p.FirstName, p.LastName, a.*
FROM People p, TABLE(p.PrevAddrs) a
WHERE p.LastName = 'Ellison';

the result gives:
p.FirstName p.LastName a.Street a.City a.State a.Zip
------------ ----------- -------------- ---------- --------- --------
Mr. Ellison 2 Second Street Orlando FL 34812
Mr. Ellison 3 Third Street Orlando FL 34812
Mrs. Ellison 2 Second Street Orlando FL 34812
Mrs. Ellison 3 Third Street Orlando FL 34812
Larry Ellison 2 Second Street Orlando FL 34812
Larry Ellison 3 Third Street Orlando FL 34812


I am doing something similar...

create or replace type step_status_rec is object (step_work_id number, step_num
number, step_stat varchar2(10), update_date DATE);

create or replace type step_status_type is table of step_status_rec;

CREATE TABLE ROLLUP_WORKFLOW (
WORK_ID NUMBER NOT NULL,
WORK_STATUS CHAR(1) NULL,
STEP_STATUS step_status_type null,
CONSTRAINT ROLLUP_WORKFLOW_PKN
PRIMARY KEY (WORK_ID)
)
NESTED table STEP_STATUS store as STEP_STATUS_TAB
/

This table stores a "work order", which has many steps (each with it's own status). So I store them in a collection in a single row for the work order...


this query shows all steps and their statuses...


select w1.work_id, w2.step_work_id, w2.step_num, w2.step_stat
from rollup_workflow w1, table(w1.step_status) w2
where w1.work_id = w2.step_work_id
order by w1.work_id,w2.update_date asc
/

result: (note, I am storing the table PK inside the collection as well, I thought it was needed for the join from w1 to w2)...

WORK_ID STEP_WORK_ID STEP_NUM STEP_STAT
---------- ------------ ---------- ----------
1 1 0 R
1 1 1
1 1 2
1 1 4
1 1 5
1 1 3
2 2 0 R
2 2 1
2 2 2
2 2 3
2 2 4
2 2 5


however, I am writing a stored procedure which takes this data into a cursor (loop) and then does other work...

My problem is this FAILS:

declare cursor cur1 is select w1.work_id, w2.step_work_id, w2.step_num, w2.step_stat
from rollup_workflow w1, table(w1.step_status) w2
where w1.work_id = w2.step_work_id
and w2.STEP_NUM = p_step_num -- even without this row it fails
order by w1.work_id,w2.update_date asc;
begin
null;
end;
/

from rollup_workflow w1, table(w1.step_status) w2
*
ERROR at line 2:
ORA-06550: line 2, column 32:
PLS-00201: identifier 'W1.STEP_STATUS' must be declared
ORA-06550: line 1, column 24:
PL/SQL: SQL Statement ignored
...

So I tried to rewrite the second half of the "from" statement to...

declare cursor c1 is select select w1.work_id, w2.step_work_id, w2.step_stat
from rollup_workflow w1, table(select step_status from rollup_workflow) w2
where w1.work_id = w2.step_work_id
and w2.STEP_NUM = p_step_num
order by w2.update_date asc;

THIS COMPILES.. however, when I run it.. I get this:

ERROR at line 2:
ORA-02324: more than one column in the SELECT list of THE subquery

The new FROM statement is not bringing back results in an acceptable way.. also should I be using the keyword "THE"? how do I use it?

thanks.









and Tom said...

Ok, in 9i -- both of these approaches work. In 8i the second approach works (and would be your current solution -- to use a ref cursor and dynamic sql, avoiding the PLSQL sql parser which does not understand that construct. In 9i and up -- SQL and PLSQL share a common SQL parser so this mismatch of functionality should not happen again)

ops$tkyte@ORA9I.WORLD> declare
2
3 p_step_num number;
4
5
6 cursor cur1 is select w1.work_id, w2.step_work_id, w2.step_num,
7 w2.step_stat
8 from rollup_workflow w1, table(w1.step_status) w2
9 where w1.work_id = w2.step_work_id
10 and w2.STEP_NUM = p_step_num -- even without this row it fails
11 order by w1.work_id,w2.update_date asc;
12 begin
13 null;
14 end;
15 /

PL/SQL procedure successfully completed.

ops$tkyte@ORA9I.WORLD>
ops$tkyte@ORA9I.WORLD>
ops$tkyte@ORA9I.WORLD> declare
2 type rc is ref cursor;
3
4 l_cur1 rc;
5 p_step_num number;
6 begin
7 open l_cur1 for
8 'select w1.work_id, w2.step_work_id,
9 w2.step_num, w2.step_stat
10 from rollup_workflow w1, table(w1.step_status) w2
11 where w1.work_id = w2.step_work_id
12 and w2.STEP_NUM = :p_step_num
13 order by w1.work_id,w2.update_date asc' using p_step_num;
14
15 close l_cur1;
16 end;
17 /

PL/SQL procedure successfully completed.



Rating

  (1 rating)

Is this answer out of date? If it is, please let us know via a Comment

Comments

Thanks, it worked.. I also have another solution

Brian, March 05, 2002 - 12:20 pm UTC

I made a view of the original select statement... and simply do a cursor of the view:
CREATE OR REPLACE VIEW ROLLUP_WORKFLOW_STEP_V
(
WORK_ID, BUSINESS_ID, FLOW_DATE, WORK_STATUS,
ARRAY_SIZE, STEP_WORK_ID, STEP_NUM, STEP_STAT,
UPDATE_DATE
)
AS
select
W1.WORK_ID,
W1.BUSINESS_ID,
W1.UPDATE_DATE as FLOW_DATE,
W1.WORK_STATUS,
W1.ARRAY_SIZE,
w2.*
from rollup_workflow w1, table(w1.step_status) w2
where w1.work_id = w2.step_work_id
order by w1.work_id, w2.step_num
/

then I can use simply: select ... from (view_name)...


but I have one more question.. when these steps are done.. an inner step status may have an error, in that case I want to update the overall status for all those rows whose (collection) has a status or error... I get the same single-query error as above.. I can create a cursor loop and do it that way.. but is there something that get get this to work?

update table(select step_status from rollup_workflow where work_status = 'I')
set step_stat= v_done_status, update_date = sysdate
where step_num = p_step_num and step_stat = v_lock_status;


I get:
ERROR at line 1:
ORA-01427: single-row subquery returns more than one row
ORA-06512: at "JOB_PROC", line 128
ORA-06512: at line 5



Tom Kyte
March 05, 2002 - 1:21 pm UTC

Well -- you are selecting more then on "virtual" table. The TABLE clause is expecting a single collection -- you are not event sending it a collection type!

You would use an update more like:

update table( select w.step_status from rollup_workflow w WHERE WORK_ID = 0 )
set step_stat = ...
/

That is you identifiy the COLLECTION instance you want to update with the inline view (where work_id = 0 in my world would select at least one and at most one row from rollup_workflow).

Then, you can treat that collection instance as if it were a table and update the values in it -- using a where clause on it if need be.



More to Explore

PL/SQL demos

Check out more PL/SQL tutorials on our LiveSQL tool.

PL/SQL docs

PL/SQL reference manual from the Oracle documentation library