Skip to Main Content
  • Questions
  • pl/sql type and sql types and collections

Breadcrumb

Question and Answer

Tom Kyte

Thanks for the question, sj.

Asked: September 26, 2001 - 11:59 pm UTC

Last updated: November 15, 2004 - 3:48 pm UTC

Version: 8.1.7

Viewed 10K+ times! This question is

You Asked

Tom

There is a lot of confusion between what are pl/sql types and sql types.

Can you please discuss with examples and clarify the confusion for us.

2.What are collections, how do they differe from pl/sql tables.


Bye




and Tom said...

Its very simple really.

If you:

SQL> create type mytable .....;

thats a SQL type. I can use that in SQL (create table of that table, as a column, in a query, etc). Since all things SQL are in PLSQL -- I can use it in PLSQL as well (as a type for a variable, in queries and so on).

If you:

SQL> create package my_pkg as type foo is .....


thats a PLSQL type. I can use it in PLSQL only -- SQL has no clue about it. Its not in the data dictionary -- it is only available to the PLSQL engine.

2) read:
</code> http://docs.oracle.com/cd/A81042_01/DOC/appdev.816/a76976/adobjint.htm#452711 <code>

They do not differ much from plsql tables except that you must explicitly "extend" them to make space in them. In a plsql table type, I can just:


declare
x plsql_table_type;
begin
x(1) := 5;
end;


using a collection I must:

declare
x collection_type := collection_type();
begin
x.extend;
x(1) := 5;
end;


the nice thing about collection types is that you can initialize them:

declare
x collection_type := collection_type( 1, 100, 1000, 10000 );
begin
...

using a table type -- i would need to make 4 assignments to get those values in.


Rating

  (11 ratings)

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

Comments

Are collections and varrays one and the same

A reader, September 27, 2001 - 10:42 am UTC

You gave the example

SQL> create package my_pkg as type foo is .....


I cant think of an example where you have to create a package as a type of something else,

elaborate the declaration of a package as a type of something else please.
 

Tom Kyte
September 27, 2001 - 2:31 pm UTC

ops$tkyte@ORA817DEV.US.ORACLE.COM> create package my_pkg
  2  as
  3          type foo is table of number index by binary_integer;
  4  end;
  5  /

Package created.

I was just using shorthand -- maybe it makes more sense with the line breaks.  

 

varchar2 limit differences

Mikito Harakiri, September 27, 2001 - 2:15 pm UTC

The fact that varchar2 have different limits in SQL and PL/SQL is a shame. Why not to equalize CLOB and PL/SQL varchar2? PL/SQL is not constrained by storage access efficiency concerns, after all. I hope this character string mess would be cleaned one day.

On optimistic note, Oracle has a single Date datatype, while other databases have many (and it's the same in SQL and PL/SQL!-).

referenging type of a "col" of an object type

A reader, December 05, 2003 - 7:28 pm UTC

when we declare a local variable that will
get value from a table column, we do
l_variable table_name.column_name%type;

Now let us say we have an object
create or replace type obj_type as object
(a varchar2(30),
b varchar2(10)
);

If we declare a local variable where we want to
store the value of "a" in the object type, do
we have a similar elegant way?

thanx!

Tom Kyte
December 06, 2003 - 9:03 am UTC

the datatype is obj_type, people would be using "obj_type"

there isn't a way to reference the type of "a" that i'm aware of.

Record vs. Object

Alex, December 06, 2003 - 12:11 pm UTC

Tom, can you, please, comment on Record vs. Object_Type.

My goal is to have a record type
(data object without methods)
available globally for data transfer between modules.

1. SQL: create type my_rec as record.....
Failed, apparently, it is not possible

2. PLSQL record in package specification:
CoR PACKAGE "RP" AS
TYPE foo IS RECORD (todayy date,numm number);END;

Works fine as RP.FOO, but I was told that pl/sql
memory cache can expell this definition under
heavy load and cause exception (???)

3. SQL: create type my_rec as object..... (with no methods)
Is it good aproarch here? will it be some overheat
versus pl/sql record : get/set operations, IN and OUT
passing, return data from function ?

4. Is there something else to consider?

Thanks a lot in advance

Tom Kyte
December 06, 2003 - 1:30 pm UTC

1) is it sql

create or replace TYPE myType as OBJECT ( attributes .... );


2) well, that is true of everything in the shared pool -- Everything.

3) that lets others outside of PLSQL (java, c, vb, etc) have access to it. a little more "open" if you will.

4) if you are doing this for plsql, the record type is nice, easy, self contained. if you believe others might want at this type in the future, the sql type is more 'Open' that way.

Thanks

Alex, December 06, 2003 - 2:34 pm UTC

OK, I will consider "record" for our pure pl/sql
and forms project. Thanks again.

Nice

Kumar, April 09, 2004 - 3:44 am UTC

Hi Tom,
What can be the use of SQL Types?suppose if I create a sql
type as
sql>create type Names_t as table of varchar2(30);
and if I assign them the ename from EMP table,How can iterate over each value?Do the SQL Types have attributes like "count,exists,delete etc." when compared with PL/SQL
Types?Could you please clarify on this?
Thanks in advance.
Bye!



Tom Kyte
April 09, 2004 - 7:46 am UTC

</code> https://docs.oracle.com <code>

check out the plsql guide (they are called collections) and the applications developers guide to object relational features.


in plsql they work much like plsql index by tables. In sql, they work like 'tables'

inserting record types

dxl, November 02, 2004 - 12:48 pm UTC

Tom

I have a procedure which uses record types:


PROCEDURE P_myproc

IS

cursor t_pat is select * from t1;

TYPE pat_array IS TABLE OF t_pat%ROWTYPE index by binary_integer;

l_source pat_array;
l_good pat_array;
l_bad pat_array;



BEGIN

open t_pat ;
loop

fetch t_pat bulk collect into l_source limit 1000;
l_good.delete;
l_bad.delete;


for i in 1 .. l_source.count
loop

if ( F_Format__Data ( l_source(i) ) = 1 )
then


l_good(l_good.count+1) := l_source(i);
else


l_bad(l_bad.count+1) := l_source(i);
end if;

end loop;



forall i in 1 .. l_good.count

insert into t2 values l_good(i);


exit when t_pat%notfound;
end loop;

close t_pat;

END ;



T1 and t2 have the same structure however I would like create an extra field on t2 so that I can set it to a value later on.
So I attempted to change the insert into t2 to specify the field names that the record type would be inserting into eg:


forall i in 1 .. l_good.count

insert into t2 (c1, c2, c3, ...etc ) values l_good(i);


(ie not including my extra field)



but this did not compile, giving me a ORA-00947: not enough values error. Is this not allowed when you assign record types in this way??
Can you only assign a record type to match the exact same table structure?? Is there anyway to achieve this?

(this is 9.2.0.5)

Thanks


more info?

dxl, November 03, 2004 - 9:07 am UTC

Do you need anymore information for the above question?

Tom Kyte
November 03, 2004 - 10:29 am UTC

i've printed hundreds of times -- I don't see every review -- i don't read each and every one, i see "most of them".

but yes, I don't see to have an example I can cut and paste into my sqlplus session there. missing tables, data, et.al.

example:

dxl, November 03, 2004 - 10:47 am UTC

Ok here is a test case:

drop table t1;
drop table t2;
create table t1 (c1 number, c2 number, c3 number);
create table t2 (c1 number, c2 number, c3 number);

insert into t1 values (1,1,1);
insert into t1 values (2,2,2);
insert into t1 values (3,3,3);
insert into t1 values (4,4,4);

declare

cursor t_pat is select * from t1;

TYPE pat_array IS TABLE OF t_pat%ROWTYPE index by binary_integer;

l_source pat_array;
l_good pat_array;
l_bad pat_array;



BEGIN

open t_pat ;
loop

fetch t_pat bulk collect into l_source limit 1000;
l_good.delete;
l_bad.delete;


for i in 1 .. l_source.count
loop

l_good(l_good.count+1) := l_source(i);
end loop;


forall i in 1 .. l_good.count

insert into t2 values l_good(i);


exit when t_pat%notfound;
end loop;

close t_pat;

END ;
/


This should work fine. Now if i add a column to t2:


drop table t2;
create table t2 (c1 number, c2 number, c3 number, c4 number);

But I still want to insert into t2 so I specify which fields my insert into t2 will insert into:


declare

cursor t_pat is select * from t1;

TYPE pat_array IS TABLE OF t_pat%ROWTYPE index by binary_integer;

l_source pat_array;
l_good pat_array;
l_bad pat_array;



BEGIN

open t_pat ;
loop

fetch t_pat bulk collect into l_source limit 1000;
l_good.delete;
l_bad.delete;


for i in 1 .. l_source.count
loop

l_good(l_good.count+1) := l_source(i);
end loop;


forall i in 1 .. l_good.count

insert into t2 (c1, c2, c3) values l_good(i);


exit when t_pat%notfound;
end loop;

close t_pat;

END ;
/


But I get this error:


TYPE pat_array IS TABLE OF t_pat%ROWTYPE index by binary_integer;
*
ERROR at line 5:
ORA-06550: line 32, column 37:
PL/SQL: ORA-00947: not enough values
ORA-06550: line 32, column 9:
PL/SQL: SQL Statement ignored


So I'm asking why this is? Is this syntax not supported?
Is there no way to do this?


Tom Kyte
November 04, 2004 - 1:31 am UTC

l_good(l_good.count+1) := l_source(i);
end loop;


forall i in 1 .. l_good.count
insert into (select c1, c2, c3 from t2) values l_good(i);


exit when t_pat%notfound;


see

</code> https://www.oracle.com/technetwork/issue-archive/2013/13-jul/o43asktom-1958803.html <code>

"insert update from a record"



syntax definition

markus, November 05, 2004 - 12:55 pm UTC

referencing this one:

forall i in 1 .. l_good.count
insert into (select c1, c2, c3 from t2) values l_good(i);

1) what does the "(select c1, c2, c3 from t2)" do effectively? i think, this will only define a (new) valid record structure at parse time?

2) in our article, you wrote that this should not be used as the insert could get wrong if another one recreates the table with another column sequence. is there any way to run this without this explicit declaration?

regards,
markus

Tom Kyte
November 05, 2004 - 5:39 pm UTC

1) see the link above -- it demonstrates this

it set up an "inline view" -- just like:

create view v as select c1, c2, c3 from t2;

insert into v values l_good(i);

would have done.


2) nope, if you use records -- they are positional -- caveat emptor on that one.

problem with sql types

paul, November 15, 2004 - 10:33 am UTC

hi tom,

CREATE TYPE laps_t AS OBJECT
(client NUMBER, support NUMBER, editeur NUMBER, integrateur NUMBER, tempo NUMBER );
/

CREATE TABLE delay (reference NUMBER, etat VARCHAR2(20), date_chgt DATE,laps LAPS_T);

CREATE OR REPLACE TRIGGER UpdateCpt
AFTER UPDATE ON ICOUR
FOR EACH ROW

DECLARE

valeur NUMBER;
reference NUMBER;
etat VARCHAR2(20);

BEGIN
reference := :OLD.reference;
etat := :OLD.etat;
valeur := 10;

EXECUTE IMMEDIATE 'UPDATE delay d SET d.date_chgt = sysdate,
d.laps.support = valeur WHERE d.reference = reference AND d.etat = etat ';
END ;
/
trigger created

update icour set etat = 'Enregistrement' where reference = 20562;
ERROR at line 1:
ORA-00904: invalid column name
ORA-06512: at "SCOTT.UPDATECPT", line 12
ORA-04088: error during execution of trigger 'SCOTT.UPDATECPT'


I cannot find where the problem is :(
If I replace in the trigger definition d.laps.support = valeur by d.laps.support = 10, this works fine.

any ideas?

Thanks for your help,
Paul

Tom Kyte
November 15, 2004 - 3:48 pm UTC

my question is "why are you doing this"

why are you using dynamic sql for something that static sql would be correct for

why are you cascading an update -- seems you have the data in this table, why copy it?

use static sql if you must do this, else you want to read about dynamic sql and how it does bind variables:

execute immediate 'update .... set x = :x where y = :y' using some_variable_for_x, some_variable_for_y;



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