PLS-00355 error whike creating a new table type - oracle

I'm getting the PLS-00355 error while trying to create the new type like this:
CREATE OR REPLACE TYPE DAYS_T IS TABLE OF VARCHAR(250) INDEX BY BINARY_INTEGER;
Any clue what is wrong?
Many thanks!

This is what you did and how Oracle responded:
SQL> CREATE OR REPLACE TYPE DAYS_T IS TABLE OF VARCHAR(250) INDEX BY BINARY_INTEGER;
2 /
Warning: Type created with compilation errors.
SQL> show err
Errors for TYPE DAYS_T:
LINE/COL ERROR
-------- -----------------------------------------------------------------
0/0 PL/SQL: Compilation unit analysis terminated
1/16 PLS-00355: use of pl/sql table not allowed in this context
On the other hand:
SQL> CREATE OR REPLACE TYPE DAYS_T IS TABLE OF VARCHAR2(250);
2 /
Type created.
SQL>
Responding to your comment: if you declared type at PL/SQL level (not SQL), then your code (without create or replace, though) would be OK (line #2 is what you used, literally):
SQL> declare
2 TYPE DAYS_T IS TABLE OF VARCHAR(250) INDEX BY BINARY_INTEGER;
3 begin
4 null;
5 end;
6 /
PL/SQL procedure successfully completed.
SQL>

You can define a nested table collection type in the SQL scope using:
CREATE OR REPLACE TYPE DAYS_T IS TABLE OF VARCHAR(250);
You can define an associative array collection type in a PL/SQL scope using:
DECLARE
TYPE DAYS_T IS TABLE OF VARCHAR(250) INDEX BY BINARY_INTEGER;
BEGIN
NULL;
END;
/
You could also locally define a nested-table collection type in a PL/SQL scope using:
DECLARE
TYPE DAYS_T IS TABLE OF VARCHAR(250);
BEGIN
NULL;
END;
/
However, you cannot define an associative array collection type in the SQL scope as it is a PL/SQL only data type.
You then asked in comments:
But how can I add an index?
They both have an index.
For example, after declaring the type in SQL, you can use the nested table collection in PL/SQL like this:
DECLARE
v_days DAYS_T;
BEGIN
v_days := DAYS_T(); -- Initialise the collection.
v_days.EXTEND(3); -- Extend the collection by 3 elements.
v_days(1) := 'Monday'; -- Set the first element.
v_days(3) := 'Wednesday'; -- Set the third element.
FOR i IN 1 .. v_days.COUNT LOOP
DBMS_OUTPUT.PUT_LINE( i || ' = ' || v_days(i) );
END LOOP;
END;
/
Which outputs:
1 = Monday
2 =
3 = Wednesday
db<>fiddle here

Related

Oracle table function on multi-layer-collection

I have a need for two Collection types in my program. I've made a simplified example.
type Trec1 is record (Tval1 number);
type Ttab1 is table of Trec1;
type Trec2 is record
(
Tval1 number,
Tval2 Ttab1
);
type Ttab2 is table of Trec2;
This Query Works fine:
select Max (Tval1) from table (Ttab1);
Whereas
select Max (Tval1) from table (Ttab2);
gives me
[Error] PLS-00382 (40: 44): PLS-00382: expression is of wrong type
[Error] ORA-22905 (40: 37): PL/SQL: ORA-22905: cannot access rows from a non-nested table item
I've concluded that the Collection with a nested Collection is what causes the errors. Is there any way to do table functions on this type of Collection, or should i loop through it normally?
To be this works perfectly.
But I have created it as SQL types, not a PL/SQL type.
Added sample code for the same
Case 1:
create type SUBTYP1 as OBJECT
(
AGE NUMBER,
NAME VARCHAR2(10)
);
/
create type TABLETYP1 AS TABLE OF SUBTYP1;
/
DECLARE
ty1 TABLETYP1 := TABLETYP1() ;
v_age number;
v_name varchar2(10);
BEGIn
ty1.extend;
ty1(1) := SUBTYP1(12,'Mahesh');
SELECT * into v_age,v_name from TABLE(ty1);
dbms_output.put_line(v_age||':'||v_name);
END;
/
Case 2:
create or replace type SUBTYP2 as OBJECT
(
AGE NUMBER,
typ1 TABLETYP1
);
/
create type TABLETYP2 AS TABLE OF SUBTYP2;
/
DECLARE
ty2 TABLETYP2 := TABLETYP2() ;
ty1 TABLETYP1 := TABLETYP1() ;
v_age number;
v_name varchar2(10);
BEGIn
ty1.extend;
ty1(1) := SUBTYP1(12,'Mahesh');
ty2.extend;
ty2(1) := SUBTYP2(14,ty1);
SELECT AGE into v_age from TABLE(ty2);
dbms_output.put_line(v_age);
END;
/
What you described are PL/SQL types and they work only in PL/SQL not in SQL. So I doubt that
select Max (Tval1) from table (Ttab1);
works fine. Can you show full creation script and output please?
If you need to have complex types returned by your query you need to create SQL collection (aka nested table) and SQL Object Type (instead of record). They are created with individual CREATE statement and they are persistent objects stored in data dictionary.

Oracle table type to nested table cast error

I declared table type and set a value in it with using loop. I am having an error while I was casting this t_table
DECLARE
TYPE t_row IS RECORD
(
id NUMBER,
description VARCHAR2(50)
);
TYPE t_table IS TABLE OF t_row;
l_tab t_table := t_table();
BEGIN
FOR i IN 1 .. 10 LOOP
l_tab.extend();
l_tab(l_tab.last).id := i;
l_tab(l_tab.last).description := 'Description for ' || i;
END LOOP;
SELECT * from TABLE(CAST(l_tab AS t_table));
END
Best regards
Why do you want to do a select onto the the type? You would use the the TABLE() and the CAST rather if you have a collection in a column stored in a table.
You could just loop through the table in your code. Example:
for i in l_tab.first .. l_tab.last
loop
dbms_output.put_line(l_tab(i).id||' '||l_tab(i).description);
end loop;
Since l_tab is of type t_table, there's no need for the cast. But that's not your problem.
Your problem is that you're trying to reference a PL/SQL type in SQL, which you simply can't do. You can either remove the select as #hol suggested or make the type a database object (which will allow SQL to access it):
CREATE OR REPLACE TYPE t_row AS OBJECT
(
id NUMBER,
description VARCHAR2 (50)
);
CREATE OR REPLACE TYPE t_table AS TABLE OF t_row;
DECLARE
l_tab t_table := t_table ();
BEGIN
FOR i IN 1 .. 10 LOOP
l_tab.EXTEND ();
l_tab (l_tab.LAST) := t_row (i, 'Description for ' || i);
END LOOP;
FOR r IN (SELECT * FROM TABLE (l_tab)) LOOP
DBMS_OUTPUT.put_line (r.id);
END LOOP;
END;
There is a second problem with the initial code, in that you are running a select without telling the code what to do with it. Unlike some other procedural SQL extensions, PL/SQL does not allow you to implicitly return a handle to a resultset (prior to 12c). You must either handle it directly or explicitly return a ref_cursor that points to it. The code above has been update to primitively handle the result of the query.

Oracle PL/SQL - Show results of declared table

I am using Toad. I have a declaration of a table in a package as follows:
TYPE MyRecordType IS RECORD
(ID MyTable.ID%TYPE
,FIELD1 MyTable.FIELD1%TYPE
,FIELD2 MyTable.FIELD2%TYPE
,FIELD3 MyTable.FIELD3%TYPE
,ANOTHERFIELD VARCHAR2(80)
);
TYPE MyTableType IS TABLE OF MyRecordType INDEX BY BINARY_INTEGER;
There is a procedure (lets say MyProcedure), that is using an object of this table type as input/output. I want to run the procedure and see the results (how the table is filled). So I am thinking I will select the results from the table:
declare
IO_table MyPackage.MyTableType;
begin
MyPackage.MyProcedure (IO_table
,parameter1
,parameter2
,parameter3);
select * from IO_table;
end;
I get the message:
Table or view does not exist (for IO_table). If I remove the select line, the procedure runs successfully, but I cannot see its results. How can I see the contents of IO_table after I call the procedure?
You cannot see the results for a PL/SQL table by using Select * from IO_table
You will need to loop through the collection in the annonymous block.
do something like, given in pseudo code below...
declare
IO_table MyPackage.MyTableType;
l_index BINARY_INTEGER;
begin
MyPackage.MyProcedure (IO_table
,parameter1
,parameter2
,parameter3);
l_index := IO_table.first;
While l_index is not null
loop
dbms_output.put_line (IO_table(l_index).id);
.
.
.
.
l_index :=IO_table.next(l_index_id);
end loop;
end;
You have to do it like this:
select * from TABLE(IO_table);
and, of course you missed the INTO or BULK COLLECT INTO clause
1) You can not use associated arrays in SELECT statement, Just nested tables or varrays declared globally.
2) You should use TABLE() expression in SELECT statement
3) You can't simply use SELECT in PL/SQL code - cursor FOR LOOP or REF CURSOR or BULK COLLECT INTO or INTO must be used.
4) The last but not least - please study the manual:
http://docs.oracle.com/cd/B28359_01/appdev.111/b28371/adobjcol.htm#ADOBJ00204
Just an example:
SQL> create type t_obj as object( id int, name varchar2(10));
2 /
SQL> create type t_obj_tab as table of t_obj;
2 /
SQL> var rc refcursor
SQL> declare
2 t_var t_obj_tab := t_obj_tab();
3 begin
4 t_var.extend(2);
5 t_var(1) := t_obj(1,'A');
6 t_var(2) := t_obj(2,'B');
7 open :rc for select * from table(t_var);
8 end;
9 /
SQL> print rc
ID NAME
---------- ----------
1 A
2 B

oracle table of records declared in package can't use index by?

Thanks for your kindness
I Declare a record type and table of records in spec of package, I need to use this table type as a return of in pipeline function.
If I add INDEX BY (something) to a table declaration, an error compilation in a pipeline function caused. Why can't use INDEX BY?
It's documented that you cannot use index-by (associative arrays) in pipelined functions. you have to use a nested table (either a pl/sql array defined without "index by" or an SQL type).
SQL> create or replace package testpkg
2 as
3 type test_rec is record(id number, id2 number);
4 type test_tab is table of test_rec index by binary_integer;
5
6 function test return test_tab pipelined;
7
8 end;
9 /
Warning: Package created with compilation errors.
SQL> show errors
Errors for PACKAGE TESTPKG:
LINE/COL ERROR
-------- -----------------------------------------------------------------
6/12 PLS-00630: pipelined functions must have a supported collection
return type
SQL> create or replace package testpkg
2 as
3 type test_rec is record(id number, id2 number);
4 type test_tab is table of test_rec;
5
6 function test return test_tab pipelined;
7
8 end;
9 /
Package created.
SQL>

How to populate an array in an oracle stored procedure?

How to use array( Varray) in store procedure. Actually,i have make a stored procedure from which i retrieve a list of elements.
For example:
create or replace procedure GetTargetFields ( fileformat in varchar2,
filefields out Varray(4) )
IS
BEGIN
SELECT id
INTO filefields
FROM tablename;
END;
use BULK COLLECT INTO:
SQL> CREATE OR REPLACE TYPE vrray_4 AS VARRAY(4) OF VARCHAR2(10);
2 /
Type created
SQL> CREATE OR REPLACE PROCEDURE GetTargetFields(fileformat IN VARCHAR2,
2 filefields OUT vrray_4) IS
3 BEGIN
4 SELECT dummy BULK COLLECT INTO filefields FROM dual;
5 END;
6 /
Procedure created
SQL> DECLARE
2 x vrray_4;
3 BEGIN
4 GetTargetFields(NULL, x);
5 END;
6 /
PL/SQL procedure successfully completed
Also make sure that your query doesn't return more than 4 rows (for a VARRAY(4)) or you will run into ORA-22165
Niraj. You should use the principles Vincent provided, but I suggest you use nested table type instead of varray in case you don't need exactly varray type in your logic. This will save you from ORA-22165 error if the query returns more then 4 rows - nested tabled will be automatically expanded to the size needed. You define nested table type as follows:
declare
type TStrTab is table of varchar2(10);
fStrTab TStrTab := TStrTab();
begin
select ... bulk collect into fStrTab from...
end;
More information about PL/SQL collection types can be found in official Oracle PL-SQL User's Guide and Reference Chapter 5.
Two things:
You need to declare a named type -- you can't use VARRAY directly in a parameter declaration. (Unless this has changed in 11g.)
You need to use BULK COLLECT to use a single query to populate a collection.
Example:
CREATE TYPE fieldlist AS VARRAY(4) OF NUMBER;
CREATE PROCEDURE GetTargetFields( filefields OUT fieldlist )
AS
BEGIN
SELECT id BULK COLLECT INTO filefields FROM tablename;
END;

Resources