Home » SQL & PL/SQL » SQL & PL/SQL » Use collection in a select statement as a table (Oracle 11g)
Use collection in a select statement as a table [message #509107] Thu, 26 May 2011 02:56 Go to next message
ric90
Messages: 42
Registered: May 2011
Location: Belfort
Member
Hi all,

i'm trying to use a collection in a select statement as a table, but i've got an error which i don't understand.

Can anyone help me ?

This exemple is very simple. I'm trying to validate the solution.
The object will contain the result of a query from a big table, and i have 4 request to make on it.
I don't want to select 4 times the big table to get the result, but i need the whole result to make my requests (intersect, minus and union)



CREATE OR REPLACE
TYPE zy_w AS OBJECT(
  CODE_INFORMATION	VARCHAR2(4),
  MATRICULE_RH	VARCHAR2(8),
  INFORMATION_DATA	VARCHAR2(4000),
  DATE_TRAITEMENT	TIMESTAMP(0),
  LINE_NUMBER	NUMBER
);
/

CREATE OR REPLACE
TYPE t_toto AS TABLE OF ZY_W;
/

DECLARE
  p_toto t_toto;
  cpt NUMBER := 0;
BEGIN
  SELECT 
    CODE_INFORMATION,
    MATRICULE_RH,
    INFORMATION_DATA,
    DATE_TRAITEMENT,
    LINE_NUMBER   
  INTO p_toto
  FROM RRGQTZY_W0
  WHERE MATRICULE_RH = '01192704';
  
  SELECT line_number
  INTO cpt 
  from table(p_toto);
  
  DBMS_OUTPUT.PUT_LINE(cpt);
END;
/


****************
Rapport d'erreur :
ORA-06550: Ligne 12, colonne 3 :
PL/SQL: ORA-00947: nombre de valeurs insuffisant
ORA-06550: Ligne 5, colonne 3 :
PL/SQL: SQL Statement ignored
06550. 00000 -  "line %s, column %s:\n%s"
*Cause:    Usually a PL/SQL compilation error.
*Action:


What did i make wrong ?
Re: Use collection in a select statement as a table [message #509113 is a reply to message #509107] Thu, 26 May 2011 03:15 Go to previous messageGo to next message
Michel Cadot
Messages: 68765
Registered: March 2007
Location: Saint-Maur, France, https...
Senior Member
Account Moderator
You return 5 values and give one variable so there is not enough variable (and it is of wrong type), this is what the message says.

Convert the 5 values to the object one:
zy_w(CODE_INFORMATION, MATRICULE_RH, INFORMATION_DATA, DATE_TRAITEMENT, LINE_NUMBER)

Regards
Michel
Re: Use collection in a select statement as a table [message #509140 is a reply to message #509113] Thu, 26 May 2011 04:53 Go to previous messageGo to next message
Barbara Boehmer
Messages: 9106
Registered: November 2002
Location: California, USA
Senior Member
SCOTT@orcl_11gR2> CREATE OR REPLACE
  2  TYPE zy_w AS OBJECT(
  3    CODE_INFORMATION      VARCHAR2(4),
  4    MATRICULE_RH	     VARCHAR2(8),
  5    INFORMATION_DATA      VARCHAR2(4000),
  6    DATE_TRAITEMENT	     TIMESTAMP(0),
  7    LINE_NUMBER	     NUMBER
  8  );
  9  /

Type created.

SCOTT@orcl_11gR2> 
SCOTT@orcl_11gR2> CREATE OR REPLACE
  2  TYPE t_toto AS TABLE OF ZY_W;
  3  /

Type created.

SCOTT@orcl_11gR2> 
SCOTT@orcl_11gR2> create table RRGQTZY_W0 (
  2    CODE_INFORMATION      VARCHAR2(4),
  3    MATRICULE_RH	     VARCHAR2(8),
  4    INFORMATION_DATA      VARCHAR2(4000),
  5    DATE_TRAITEMENT	     TIMESTAMP(0),
  6    LINE_NUMBER	     NUMBER
  7  )
  8  /

Table created.

SCOTT@orcl_11gR2> insert into rrgqtzy_w0 values
  2    ('a', '01192704', 'b', systimestamp, 1)
  3  /

1 row created.

SCOTT@orcl_11gR2> insert into rrgqtzy_w0 values
  2    ('c', '01192704', 'd', systimestamp, 2)
  3  /

1 row created.

SCOTT@orcl_11gR2> 
SCOTT@orcl_11gR2> DECLARE
  2    p_toto t_toto;
  3  BEGIN
  4    SELECT CAST (MULTISET
  5  		(SELECT CODE_INFORMATION,
  6  			MATRICULE_RH,
  7  			INFORMATION_DATA,
  8  			DATE_TRAITEMENT,
  9  			LINE_NUMBER
 10  		 FROM	RRGQTZY_W0
 11  		 WHERE	MATRICULE_RH = '01192704')
 12  	       AS t_toto)
 13    INTO   p_toto
 14    FROM   DUAL;
 15  
 16    FOR r IN
 17  	 (SELECT line_number
 18  	  from	 table(p_toto))
 19    LOOP
 20  	 DBMS_OUTPUT.PUT_LINE(r.line_number);
 21    END LOOP;
 22  END;
 23  /
1
2

PL/SQL procedure successfully completed.

SCOTT@orcl_11gR2> 

Re: Use collection in a select statement as a table [message #509142 is a reply to message #509140] Thu, 26 May 2011 05:01 Go to previous messageGo to next message
ric90
Messages: 42
Registered: May 2011
Location: Belfort
Member
Tahnk you so much both of you.
I didn't think about cast(multiset.
Re: Use collection in a select statement as a table [message #509143 is a reply to message #509142] Thu, 26 May 2011 05:05 Go to previous messageGo to next message
ric90
Messages: 42
Registered: May 2011
Location: Belfort
Member
How can i flag the post as RESOLVED ?
Re: Use collection in a select statement as a table [message #509144 is a reply to message #509143] Thu, 26 May 2011 05:10 Go to previous messageGo to next message
cookiemonster
Messages: 13967
Registered: September 2008
Location: Rainy Manchester
Senior Member
You can't - we don't have that here. Don't worry about it.
Re: Use collection in a select statement as a table [message #509215 is a reply to message #509140] Thu, 26 May 2011 08:48 Go to previous messageGo to next message
Solomon Yakobson
Messages: 3305
Registered: January 2010
Location: Connecticut, USA
Senior Member
Barbara,

There is no need for FOR cursor loop. Collection element attributes can be accessed directly:

SQL> set serveroutput on
SQL> DECLARE
  2    p_toto t_toto;
  3  BEGIN
  4    SELECT CAST (MULTISET
  5    (SELECT CODE_INFORMATION,
  6     MATRICULE_RH,
  7     INFORMATION_DATA,
  8     DATE_TRAITEMENT,
  9     LINE_NUMBER
 10     FROM RRGQTZY_W0
 11     WHERE MATRICULE_RH = '01192704')
 12          AS t_toto)
 13    INTO   p_toto
 14    FROM   DUAL;
 15   FOR i IN 1..p_toto.count LOOP
 16    DBMS_OUTPUT.PUT_LINE(p_toto(i).line_number);
 17    END LOOP;
 18  END;
 19  /
1
2

PL/SQL procedure successfully completed.

SQL> 


Also, I'd use COLLECT:

DECLARE
  p_toto t_toto;
BEGIN
    SELECT  CAST(
                 COLLECT(
                         zy_w(
                              CODE_INFORMATION,
                              MATRICULE_RH,
                              INFORMATION_DATA,
                              DATE_TRAITEMENT,
                              LINE_NUMBER
                             )
                        )
                 AS t_toto
                )
      INTO  p_toto
      FROM  RRGQTZY_W0
      WHERE MATRICULE_RH = '01192704';
 FOR i IN 1..p_toto.count LOOP
	 DBMS_OUTPUT.PUT_LINE(p_toto(i).line_number);
  END LOOP;
END;
/
1
2

PL/SQL procedure successfully completed.

SQL> 


SY.
Re: Use collection in a select statement as a table [message #509250 is a reply to message #509215] Thu, 26 May 2011 11:21 Go to previous messageGo to next message
Barbara Boehmer
Messages: 9106
Registered: November 2002
Location: California, USA
Senior Member
syakobson wrote on Thu, 26 May 2011 06:48

There is no need for FOR cursor loop. Collection element attributes can be accessed directly...


Agreed and that's simpler if what was output is all that is wanted. I saw the "use collection in a select statement as a table" title of the post and repeated in the post and thought that was part of the requirement and the rest might just be a simplified test, so I left that part of the code intact.

syakobson wrote on Thu, 26 May 2011 06:48

Also, I'd use COLLECT:


That certainly works too. Is there any particular benefit? Is it more efficient? Or just a personal preference in terms of reading the code?

Re: Use collection in a select statement as a table [message #509258 is a reply to message #509250] Thu, 26 May 2011 12:36 Go to previous messageGo to next message
ric90
Messages: 42
Registered: May 2011
Location: Belfort
Member
Barbara Boehmer wrote on Thu, 26 May 2011 18:21

Agreed and that's simpler if what was output is all that is wanted. I saw the "use collection in a select statement as a table" title of the post and repeated in the post and thought that was part of the requirement and the rest might just be a simplified test, so I left that part of the code intact.


Yes, that was the goal of the post. The rest of the code is just here to test the procedure

syakobson wrote on Thu, 26 May 2011 06:48

Also, I'd use COLLECT:

Barbara Boehmer wrote on Thu, 26 May 2011 18:21

That certainly works too. Is there any particular benefit? Is it more efficient? Or just a personal preference in terms of reading the code?


I am also interest on the answer.
But good point, the code is easier to read Wink
Re: Use collection in a select statement as a table [message #509262 is a reply to message #509250] Thu, 26 May 2011 13:00 Go to previous message
Solomon Yakobson
Messages: 3305
Registered: January 2010
Location: Connecticut, USA
Senior Member
Barbara Boehmer wrote on Thu, 26 May 2011 12:21
Is there any particular benefit? Is it more efficient? Or just a personal preference in terms of reading the code?


No it is just a bit better readability. In fact, now, when my thoughts settled down Smile I would use BULK COLLECT:

DECLARE
  p_toto t_toto;
BEGIN
    SELECT  zy_w(
                 CODE_INFORMATION,
                 MATRICULE_RH,
                 INFORMATION_DATA,
                 DATE_TRAITEMENT,
                 LINE_NUMBER
                )
      BULK  COLLECT
      INTO  p_toto
      FROM  RRGQTZY_W0
      WHERE MATRICULE_RH = '01192704';
 FOR i IN 1..p_toto.count LOOP
	 DBMS_OUTPUT.PUT_LINE(p_toto(i).line_number);
  END LOOP;
END;
/
1
2

PL/SQL procedure successfully completed.

SQL> 


This would give slightly better performance. I remember reading Tom Kyte's article proving slightly better performance of BULK COLLECT versus MULTISET.

SY.
Previous Topic: Need help with a pl/sql problem
Next Topic: need a query to achieve this
Goto Forum:
  


Current Time: Wed Aug 06 06:35:06 CDT 2025