Skip to Main Content
  • Questions
  • difference between sql type and plsql types

Breadcrumb

Question and Answer

Tom Kyte

Thanks for the question, R.

Asked: June 13, 2003 - 1:12 pm UTC

Last updated: January 06, 2006 - 2:22 pm UTC

Version: 9.0.1.0

Viewed 1000+ times

You Asked

you create an sql type using create type
e.g.

create or replace table_of_numbers as table of number;


or you can declare a plsql type inside a package as

...
type plsql_table_of_numbers is table of number;

Are there any differences between the two apart from the fact that
you cant do select from plsql type (e.g. in your example
of creating variable in list?)
When do you use one or the other (or does that q not make any
sense?)

Also, just like sys_refcursor plsql type is provided, are there
any other default commonly used sql or plsql types that
come in by default. E.g. a varchar2_table or a number_table would
be examples of commonly used sql or plsql types? If so where
in general are they defined?

Thanx - Please keep up the great work!:)

Menon:)




and Tom said...

one is a SQL type -- known to sql, 3gls, plsql -- everyone.

The other is a PLSQL type only, known only to plsql, limited 3gl access, cannot be used as is in sql and so on.


If I need to have access to this type from 3gls and in SQL, there is only one type to consider.

If I do not need that access, the other type is prefered -- it is hidden in the package and does not create yet another thing in the data dictionary, its use is limited in scope (as I deemed it to be)

DBMS_SQL has some table types I borrow frequently.

Rating

  (18 ratings)

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

Comments

Does it mean anything?

Kamal Kishore, June 14, 2003 - 1:37 pm UTC

Hi Tom,
I have heard this argument:
"It is better to define your own table types in PL/SQL package than to use those defined in DBMS_SQL package, because if you use types defined in DBMS_SQL pacakge, this pacakge will also be loaded in memory (even if you are not going to use its procedures) along with your own package. This would cause your application to require more memory than may be necessary. So, to make less memory footprint and an efficient program, declare your own types and DO NOT use DBMS_SQL table types."

Should we be concerned?
Using DBMS_SQL types instead of defining our own within the package will have a negative effect on performance? Is this true?
Thanks,


Tom Kyte
June 14, 2003 - 2:18 pm UTC

I have yet to see a database that doesn't use dbms_sql, so it is probably a moot point. dbms_sql is used under the covers by so many things. It is a micro-optimization at best.


Truth be told, you would probably be best off with your own types though, but not for those reasons.

Oracle owns DBMS_SQL. We can change those types any time we want to.

You would own "Kamals_Types_Pkg", you would change them only when you want to.

thanx for the answer to the original question!

A reader, June 14, 2003 - 5:17 pm UTC


Pitty that there is no namespace for SQL types

A reader, June 19, 2003 - 4:06 pm UTC

PLSQL types are neat because they are encapsulated (package name acts like object type name or namespace).

SQL types do not have namespaces and if one would like to use them in real application one would end up complete mess with hundreds of types.


Tom Kyte
June 20, 2003 - 3:58 pm UTC

why would you have hundreds of types?

Why I have hundreds of types

A reader, June 25, 2003 - 5:27 am UTC

I put all my SQL into procedures and client side just calls these procuderes to select, update, insert or delete.

Typical "select" would be packaged procedure with typed ref cursor. These packages form interface layer between database (PLSQL) and client programm (c/s or web based client). There interface procedures are built from viewpoint of GUI (this is not typical object oriented interface used in 3-tier model).

Simplified example of SELECT and UPDATE procedure:

create or replace package ONE_INTERFACE_PACKAGE is

type TPersonNameRec is record
( ID number(10,0) -- person ID
, NAME varchar2(50) -- person full name to display
);
type TPersonNameCur is ref cursor return TPersonNameRec;

procedure FIND_PERSON
( sNameToSearch IN varchar2
, curOut out TPersonNameCur
);

procedure UPDATE_PERSON
( iID in number(10,0) -- person ID
, sName in varchar2(50) -- person full name to update
);


end ONE_INTERFACE_PACKAGE;
/

create or replace package body ONE_INTERFACE_PACKAGE is

procedure FIND_PERSON
( sNameToSearch IN varchar2
, curOut out TPersonNameCur
) is
begin

open curOut for
select ID, NAME
from PERSONS
where NAME like sNameToSearch;

end;

procedure UPDATE_PERSON
( iID in number(10,0) -- person ID
, sName in varchar2(50) -- person full name to update
) is
begin

update PERSONS
set NAME = sName
where ID = iID;

end;

end ONE_INTERFACE_PACKAGE;
/


So... for each SELECT statement I would have one PLSQL record and one typed cursor. And few hundred types collect up very rapidly.

I would like to use SQL type - because it would be supported by application client side (by client I mean Java, Delphi, PHP etc):
* same type in database and client;
* nested tables could be useful;
* I could use same type in insert/update procedures;
* I could use array types more easily.

Some of this could be implemented with PL/SQL types also but it would be messy at client side. SQL types would make this much easier. But I have no means to partition SQL types at database side.



Tom Kyte
June 25, 2003 - 12:05 pm UTC

I don't get why you would create a type for a select still.

just return ref cursors -- no types? not getting it.

those clients do not actually SUPPORT types very well. ref cursors -- sure, object types -- not.

so, still not getting it I guess.

Need your help

Devan, March 04, 2004 - 12:51 am UTC

Hi Tom,
In the create type body statement,I came across the clause
"return self as result is pl/sql block or call spec"?How to
use this clause?Does 'self' keyword point to the attributes
defined with in the type declaration?If you have any simple
example, please do write a followup.
Thanks in advance.


Tom Kyte
March 04, 2004 - 11:01 am UTC

It provides a method to create your own constructor, your own procedural logic to setup the object type:


ops$tkyte@ORA9IR2> create or replace type myType
  2  as object
  3  ( x int,
  4    y date,
  5    z varchar2 (25),
  6    constructor function myType return self as result,
  7    constructor function myType( some_number in number ) return self as result
  8  )
  9  /
 
Type created.
 
ops$tkyte@ORA9IR2>
ops$tkyte@ORA9IR2> create or replace type body myType
  2  as
  3
  4  constructor function myType return self as result
  5  is
  6  begin
  7     x := 55;
  8     y := sysdate;
  9     z := 'Hello World';
 10     return;
 11  end;
 12
 13  constructor function myType( some_number in number ) return self as result
 14  is
 15  begin
 16     x := some_number;
 17     y := sysdate+some_number;
 18     z := 'Hello World ' || some_number;
 19     return;
 20  end;
 21
 22  end;
 23  /
 
Type body created.
 
ops$tkyte@ORA9IR2>
ops$tkyte@ORA9IR2>
ops$tkyte@ORA9IR2>
ops$tkyte@ORA9IR2> declare
  2          x myType := myType();
  3          y myType := myType(2);
  4  begin
  5          dbms_output.put_line( x.x || ', ' || x.y || ', ' || x.z );
  6          dbms_output.put_line( y.x || ', ' || y.y || ', ' || y.z );
  7  end;
  8  /
55, 04-MAR-04, Hello World
2, 06-MAR-04, Hello World 2
 
PL/SQL procedure successfully completed.
 

Nice as usual

Jim, March 05, 2004 - 1:32 am UTC

Dear Tom,
In creating types we find "map or order member function"
What is the diff. between "map or order keywords"?.
Please do reply.
Bye!

Nice

Ram, March 08, 2004 - 10:21 am UTC

Dear Sir,
Please have a look at the following objects.
sql>create type address_ty as object(door_no number,streetname varchar2(30),city varchar2(30));
Now if we create a table as
create table customer(
custname varchar2(30),
address address_ty);
or
create table customer(
custname varchar2(30),
address REF address_ty);

Are both statements equivalent?
What role can REF play in the 2nd statement?what is the
difference between two statements?
Please do reply.

Tom Kyte
March 08, 2004 - 1:56 pm UTC

no, they are not remotely similar. the first creates a table capable of holding a custname and an address (the data of an address). the second can store a custname and a POINTER to an address object stored in some other table.


the REF is like a pointer - it points to an object instance, typically an instance in another table.

it is "like" a foreing key, only not as good (no RI)



NN

A reader, April 14, 2005 - 1:38 pm UTC

Hi Tom,

I have these external types:

create or replace TYPE cas_to_ec_crdt_app_addr IS RECORD (
qualifier VARCHAR2(40),
addr_line_1 VARCHAR2(40),
addr_line_2 VARCHAR2(40),
city_name VARCHAR2(30),
state_code VARCHAR2(2),
zip_code VARCHAR2(9),
cnty_name VARCHAR2(10)
);
create or replace TYPE cas_to_ec_crdt_app_addr_typ IS TABLE OF cas_to_ec_crdt_app_addr;



create or replace TYPE cas_to_ec_aplcnt_rec IS RECORD (
prim_aplcnt_ind CHAR(1),
aplcnt_frst_name VARCHAR2(15),
aplcnt_mid_name VARCHAR2(15),
aplcnt_last_name VARCHAR2(35),
name_sfx_code VARCHAR2(10),
aplcnt_brth_date DATE,
address_table
cas_to_ec_crdt_app_addr_typ);



create or replace TYPE cas_to_ec_aplcnt_tab IS TABLE OF cas_to_ec_aplcnt_rec;



create or replace TYPE cas_to_ec_vehicle IS RECORD(
vhcl_mdl_year NUMBER(4),
vhcl_make_name VARCHAR2(70),
vhcl_mdl_name VARCHAR2(70),
trad_in_ind CHAR(1)
);



create or replace TYPE cas_to_ec_vehicle_typ IS TABLE OF cas_to_ec_vehicle;

create or replace TYPE copy_ca is record (
crdt_aplcn_oid NUMBER(20),
crdt_aplcn_type_code VARCHAR2(10),
vin VARCHAR2(25),
cas_veh_tab cas_to_ec_vehicle_typ,
trad_in_owed_amt NUMBER(16,2),
trad_alow_on_trad_in_amt NUMBER(16,2),
cash_down_pymt_amt NUMBER(16,2),
mfr_rbt_amt NUMBER(16,2),
vhcl_mdl_year NUMBER(4),
vhcl_make_name VARCHAR2(70),
vhcl_mdl_name VARCHAR2(70),
vhcl_sty_name VARCHAR2(70),
fnc_src_oid NUMBER(20),
rte_one_fnc_src_id VARCHAR2(20),
fnc_src_dba_name VARCHAR2(70),
fnc_term_qty NUMBER(10),
applcnt_table
cas_to_ec_aplcnt_tab
);

And in my package, i am declaring a function which uses that record type:

FUNCTION copy_ca_ssp(
i_crdt_aplcn_oid IN NUMBER,
o_error_cd OUT PLS_INTEGER,
o_error_desc OUT VARCHAR2 ,
o_error_msg OUT VARCHAR2 ,
o_error_type OUT VARCHAR2
) RETURN copy_ca;

When I compile my code; I am getting this error:

PLS-00905: object R1OWNER.COPY_CA is invalid

Could you please guide me?







Tom Kyte
April 14, 2005 - 1:41 pm UTC

ops$tkyte@ORA9IR2> create or replace TYPE copy_ca is record    ( x number )
  2  /
 
Warning: Type created with compilation errors.
 


because "is record" is "not valid"

create or replace type copy_ca as OBJECT (...... ) would be

record is PLSQL specific 

A reader, April 14, 2005 - 1:47 pm UTC

Thanks Tom,

I did what you suggested:

create or replace TYPE copy_ca as object(x nnumber).
I am still get the same error.

Can I use types in an object?
I mean can be a record type in the above statement?

Thanks in advance!

Tom Kyte
April 14, 2005 - 1:59 pm UTC

records only work in PLSQL, not in create or replace type's.




A reader, April 14, 2005 - 1:50 pm UTC

can X be a record type in above statement?

Tom Kyte
April 14, 2005 - 1:59 pm UTC

yes, but the record type would be defined in the scope of PLSQL, not SQL.

that is, it would be a type inside of a package specificiation.

A reader, April 14, 2005 - 2:12 pm UTC

Thanks a lot Tom!
I have another issue:
Here are the details:

type A as object(
c1 number;
my_B type1
);

type type1 is table of B;

type B is object(
c2 number,
c3 varchar2,
my_C type2
);

type type2 is table of C;


type C is object(
c4 date
);


-------------

In my procedure I am giving following statement:

my_A A;

select data1,data2,..
bulk collect into my_A.my_B.my_C
from table1
where <conditions>

And I am getting following error:

PLS-00302: component 'my_C' must be declared


Could you please help me!

Tom Kyte
April 14, 2005 - 2:16 pm UTC

small, concise, yet 100% complete.... and in the order needed to execute.

make it as short as possible, yet runnable by anyone on the planet and I'll have a look. use scott/tiger tables for example

A reader, April 14, 2005 - 2:27 pm UTC

Sorry about that! Hope the following is clear, I have nested types, so cannot simplify the type structure:

I have declared following types at schema level:

create or replace type C is object(
start_date date,
end_date date
);

create or replace type table2 is table of C;

create or replace type B is object(
c2 number,
c3 varchar2,
my_C table2
);

create or replace type table1 is table of B;

create or replace type A as object(
c1 number;
my_B table1
);

----

In my procedure I am giving following statement:

procedure p1
is
my_A A;

begin

select sysdate,hiredate
bulk collect into my_A.my_B.my_C
from emp;

end;


And I am getting following error:

PLS-00302: component 'my_C' must be declared

Thanks a lot!

Tom Kyte
April 14, 2005 - 2:47 pm UTC

(always nice to have a script that runs!  varchar2, does not compile... c1 number; does not compile.....)

anyway  

my_a is a scalar object.

my_a.my_b is a TABLE (collection).  A.my_b(1).my_c would be valid.  A.my_b.my_c is not.  you are missing a subscript (and some initialization)

after fixing up script....


ops$tkyte@ORA9IR2> declare
  2  my_A A;
  3  begin
  4
  5  my_a := a( null, table1( b(null,null, null ) ) );
  6
  7  select c(sysdate,hiredate)
  8    bulk collect into my_A.my_B(1).my_C
  9    from emp;
 10  end;
 11  /
 
PL/SQL procedure successfully completed.
 

A reader, April 14, 2005 - 2:57 pm UTC

Once again thanks a lot.
But, I am still getting the following error:
PL/SQL: ORA-00947: not enough values

I am selecting data for all the columns, what could be the issue?

A reader, April 14, 2005 - 3:00 pm UTC

Can I use Bulk into with objects?

Tom Kyte
April 14, 2005 - 3:08 pm UTC

yes

A reader, April 14, 2005 - 3:06 pm UTC

Here is what I am trying to do:

declare
my_A A;
begin

my_a := a( null, table1( b(null,null, null ) ) );

select c(ename,sal)
bulk collect into my_A.my_B
from emp;
end;

What is the mistake?

Tom Kyte
April 14, 2005 - 3:11 pm UTC

ops$tkyte@ORA9IR2> set describe depth all
ops$tkyte@ORA9IR2> desc a
 Name                                     Null?    Type
 ---------------------------------------- -------- ----------------------------
 C1                                                NUMBER
 MY_B                                              TABLE1
   C2                                              NUMBER
   C3                                              VARCHAR2(25)
   MY_C                                            TABLE2
     START_DATE                                    DATE
     END_DATE                                      DATE
 


my_a.my_b is a table of three thnigs.  You select 1 thing.


Not really sure what your ultimate goal here is, but the shape of what you are trying to select comes no where near the shape of the thing you are selecting INTO. 

A reader, April 14, 2005 - 3:20 pm UTC

Very useful information!

I want to bulk collect My_B (including My_C).
How can I do it?
There can be multiple rows in My_B and My_C.

Thanks in advance!

Tom Kyte
April 14, 2005 - 3:38 pm UTC

well, you sort of would need a result set that fits into it?

You seem to be going backwards in this respect. Normally, you know what you are retrieving and you build a data structure to hold it, here we seem to have a data structure that you want to fill with data?

seems backwards no?

A reader, April 14, 2005 - 3:36 pm UTC

Please help me, it is very urgent!

Tom Kyte
April 14, 2005 - 3:39 pm UTC

see above, it really does seem backwards. you need simply to select out data that fits the data structure YOU invented?

difference between sql type and plsql type

Magesh, January 06, 2006 - 11:32 am UTC

Tom,
I was trying to get the hang of CAST and hit upon this. Can you please explain what is happening here? When I declare the type in SQL everything works fine but when I try to declare the same as a plsql type, it doesn't seem to work. I understand when I declare the type in plsql, it becomes local to the block and SQL wouldn't recognize it outside the scope of it but I am using the Select .. into inside the plsql block. 

SQL> create or replace type num_tab as table of number(10);
  2  /

Type created.

SQL> declare
  2  --type num_tab is table of number;
  3  v_num_tab num_tab;
  4  a number;
  5  begin
  6  v_num_tab := num_tab(10,20,30,40,50);
  7  dbms_output.put_line('The numbers are: ');
  8  /*for a in (select column_value nums from table(cast(v_num_tab as num_tab))) loop
  9  dbms_output.put_line(a.nums);
 10  end loop;*/
 11  select sum(column_value) into a from table(cast(v_num_tab as num_tab));
 12  dbms_output.put_line(a);
 13  end;
 14  /
The numbers are:
150

PL/SQL procedure successfully completed.

SQL> drop type num_tab;

Type dropped.

SQL> declare
  2  type num_tab is table of number;
  3  v_num_tab num_tab;
  4  a number;
  5  begin
  6  v_num_tab := num_tab(10,20,30,40,50);
  7  dbms_output.put_line('The numbers are: ');
  8  /*for a in (select column_value nums from table(cast(v_num_tab as num_tab))) loop
  9  dbms_output.put_line(a.nums);
 10  end loop;*/
 11  select sum(column_value) into a from table(cast(v_num_tab as num_tab));
 12  dbms_output.put_line(a);
 13  end;
 14  /
select sum(column_value) into a from table(cast(v_num_tab as num_tab));
                                                             *
ERROR at line 11:
ORA-06550: line 11, column 62:
PL/SQL: ORA-00902: invalid datatype
ORA-06550: line 11, column 1:
PL/SQL: SQL Statement ignored 

Tom Kyte
January 06, 2006 - 2:22 pm UTC

because CAST is a sql function, CAST sees only things "sql", CAST called from SQL like that doesn't see "num_tab" when "num_tab" is a private PLSQL type.

to use a type in SQL, you use SQL to create the type. In general, plsql types are NOT visible outside of PLSQL

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