Type without body in Oracle PL/SQL - oracle

I'm having problems tracking an array initialized to an empty Type (table of varchar2) object. It's inside a loop and outputs indexes from what I think is coming from the database. I've done my research with the "as table of varchar2" and I think it just simply means a column of a table with varchar as a type.
From what I understood, the "invArry" declared as the type "item_val" in the "item_inv" header just basically means invArry is a varchar, since item_val is a varchar right? But I got confused when in the item_inv body, the invArry is initialized to item_val again. Was it initialized to a varchar again? Or does the type item_val already pointing out to a column in the database? If it's the latter, I'm not sure how it got pointed to the database.
create or replace TYPE "item_inv" AS OBJECT
(invArry item_val, --invArry declared as item_val
CONSTRUCTOR FUNCTION item_inv
RETURN SELF AS RESULT,
CONSTRUCTOR FUNCTION item_inv( recrd VARCHAR2 )
RETURN SELF AS RESULT,
) FINAL;
=========
create or replace TYPE BODY "item_inv" AS
CONSTRUCTOR FUNCTION item_inv
RETURN SELF AS RESULT
IS
BEGIN
invArry := item_val --invArry initialized to item_val. Whut
RETURN;
END;
=========
create or replace TYPE "item_val" AS TABLE OF VARCHAR2( 240 );
--item_val object, does this points already to the database or just an empty object

You've defined item_val as a nested table collection.
In your object type invArry is of that type, so it is a nested table - that is, an unordered collection of strings, each of which is up to 240 characters.
In your object type body you're initialising the invArry to an empty collection:
invArry := item_val();
It is not initialised to a varchar, it's initialised to an empty nested table of varchars. It isn't pointing to any data, table or column in the database. It's a collection which has no elements in it. You can now write code to add elements to that collection. The values could come from elsewhere in the database but there is no automatic link.

Related

Is it possible to create a pipeline table function returning a table of a record of record

create package pa as
type ra1 is record (
one integer,
two integer
);
type ra2 is record (
r1 ra1,
three integer,
fore integer
);
type ta1 is table of ra1;
type ta2 is table of ra2;
function pa1 return ta1 pipelined;
function pa2 return ta2 pipelined; --pipelined functions must have a supported collection return type
end;
It doesn't seem possible too create a table of a record.
I explain why I want to do that. Perhaps you a another solution.
I have a big query with a "with statement" with n part.
Some parts are reused in others queries. I could rewrite these parts as views. But views doesn't accept parameters and the what is in the where block is long.
I want to define each step like that:
function f_stepn(arg integer) return t_stepn
is
for c in (
select r_stepnMinus1(stepnMinus1.* ) , o.f1,o.f2
from
f_stepnMinus1(arg) stepnMinus1 join othertable o on .....
) loop
pipe row(c)
end loop
In the end I do this this select :
select skip(t.r_stepMinus1.r_stepMinus1.*), skip(t.r_stepMinus1.*), skip(t.*))
where skip in a polymophich function that delete the fields that are records.
P.S.
the function in example in simplified. I can't do that : select r_stepnMinus1(stepnMinus1.* )
I know that I could rewrite the whole definition of r1 inside r2 but I don't want to write 2 times the same thing
A Record is a PL/SQL-only data type and CANNOT be used in SQL statements.
A pipelined function is designed to be used in SQL statements and MUST return a collection that can be used in SQL.
When you return a collection of records, Oracle will implicitly create an OBJECT data-type that reflects the attributes of the record and will return a collection of this object rather than the record (and a collection of object can be used in SQL statements).
However, an OBJECT cannot contain an attribute with a RECORD data type. So when you try to create pipelined function returning a collection of records with a nested record attribute then Oracle cannot implicitly create an Object that reflects the record as the nested record is incompatible and so creating a PIPELINED function will fail.
Either:
Use OBJECT data types created in the SQL scope (instead of records); or
Do not nest records inside records.

Accessing table from an object

Is it possible to access an existing table from an object?
Here the simplified snippet:
CREATE OR REPLACE TYPE MYOBJ AS OBJECT(
MEMBER PROCEDURE MYEXPORT( ERRORS.ERRORS_ID%TYPE));
ERRORS is a table. When I write it like above I'm getting error:
PLS-00201 - identifier must be declared.
Any clue? Thanks!
You have three issues:
The syntax is
MEMBER PROCEDURE procedure_name (argument_name data_type)
You have specified the data type but not an argument name which is why you get the error message PLS-00201 - identifier must be declared. as you need to specify an identifier for the argument.
table_name.column_name%TYPE declarations can be used in the PL/SQL scope but not in the SQL scope. Your object declaration is in the SQL scope so you need to fully define the data type rather than referring to a column.
An object must have at least one attribute.
You want:
CREATE OR REPLACE TYPE MYOBJ AS OBJECT(
attr1 NUMBER,
MEMBER PROCEDURE MYEXPORT( v_errors_id NUMBER )
);

Alter/Evolve Type User Defined Constructor Function Signature (PL/SQL)

How does one evolve a user defined constructor function signature?
Given an Oracle PL/SQL user defined type that has table dependents, instead of replacing them with create/replace statements I need to evolve these types. I found Oracle documentation on how to drop/add attributes, and drop/add member functions via alter statements, but I do not see information on how to evolve a constructor function signature. I need to do this without creating a new table/type and migrating data over to the new updated type. In my case, using FORCE does not work either.
For example, given the type below, how could I update the user defined constructor signature to include a new parameter to use during initialization?
-- Create new type
CREATE OR REPLACE TYPE test_type AS OBJECT (
test_attribute NUMBER(1, 0),
CONSTRUCTOR FUNCTION test_type(
p_test_attribute NUMBER DEFAULT NULL
)
RETURN SELF AS RESULT
);
-- Make this new type have table dependents
CREATE OR REPLACE TYPE test_type_table
AS TABLE OF test_type;
CREATE TYPE test_child_obj AS OBJECT (
test_type_field test_type_table
);
-- Add new attribute via alter statement
ALTER TYPE test_type
ADD ATTRIBUTE (new_attribute NUMBER)
CASCADE NOT INCLUDING TABLE DATA;
I would like to update the constructor signature to the following:
CONSTRUCTOR FUNCTION test_type(
p_test_attribute NUMBER DEFAULT NULL,
p_new_attribute NUMBER DEFAULT NULL
)
RETURN SELF AS RESULT
I was hoping there would be an alter statement like the following, but I cannot find a proper alter statement. Please help.
ALTER TYPE test_type
ADD CONSTRUCTOR FUNCTION test_type(
p_test_attribute NUMBER DEFAULT NULL,
p_new_attribute NUMBER DEFAULT NULL
)
RETURN SELF AS RESULT
CASCADE NOT INCLUDING TABLE DATA;
It turns out that the alter statement is in fact the one stated above and shown below. However, you can run into "too many declarations of 'test_type' match this call". In my real problem, the issue was all my constructor parameters have default NULL values and conflicted with my original constructor that all had default NULL parameters. If I take away the DEFAULT NULL, I can add new constructors.
ALTER TYPE test_type
ADD CONSTRUCTOR FUNCTION test_type(
p_test_attribute NUMBER DEFAULT NULL,
p_new_attribute NUMBER DEFAULT NULL
)
RETURN SELF AS RESULT
CASCADE NOT INCLUDING TABLE DATA;

How to create Oracle object type with collection as attrubuteobject type with collection as attrubute

In oracle database I have created type
CREATE OR REPLACE TYPE DOSSIER_RESULT AS OBJECT
(
id number,
user_id number
)
Then I created the collection of this type
CREATE OR REPLACE TYPE DOSSIER_RESULTS_ARRAY AS TABLE OF DOSSIER_RESULT
Then I added one more attribute in first type definition like this
CREATE OR REPLACE TYPE DOSSIER_RESULT AS OBJECT
(
id number,
user_id number,
child DOSSIER_RESULTS_ARRAY
)
But it compiled with error
Error: PLS-00201: identifier 'DOSSIER_RESULTS_ARRAY' must be declared
The question is: How can I create an Object type with collection of objects of this type in it?

Create Type based on an exiting Table

As the title said : I want to create a type in oracle based on an existing Table.
I did as follow :
create or replace type MY_NEW_TYPE as object( one_row EXISTING_TABLE%rowtype);
The Aim is to be able to use this into a function which will return a table containing sample row of the table EXISTING_TABLE :
create or replace function OUTPUT_FCT() return MY_NEW_TYPE AS
...
If you only need to create a function that returns a row from your table, you could try something like the following, without creating types.
setup:
create table EXISTING_TABLE( a number, b varchar2(100));
insert into EXISTING_TABLE values (1, 'one');
function:
create or replace function OUTPUT_FCT return EXISTING_TABLE%rowtype AS
retVal EXISTING_TABLE%rowType;
begin
select *
into retVal
from EXISTING_TABLE
where rownum = 1;
--
return retVal;
end;
function call
SQL> begin
2 dbms_output.put_line(OUTPUT_FCT().a);
3 dbms_output.put_line(OUTPUT_FCT().b);
4 end;
5 /
1
one
However, I would not recommend such an approach, because things like select * can be really dangerous; I would much prefer defining a type with the fields I need, and then explicitly query my table for the needed columns.
No, you can't do that, you'll get a compilation error:
create or replace type my_new_type as object(one_row t42%rowtype);
/
Type MY_NEW_TYPE compiled
Errors: check compiler log
show errors
Errors for TYPE STACKOVERFLOW.MY_NEW_TYPE:
LINE/COL ERROR
-------- -----------------------------------------------------------------------
0/0 PL/SQL: Compilation unit analysis terminated
1/36 PLS-00329: schema-level type has illegal reference to MYSCHEMA.T42
You will need to specify each field in the object type, and you will have to specify the data types manually too - you can't use table.column%type either.
You could create the type dynamically based on column and data type information from the data dictionary, but as this will (hopefully) be a one-off task and not something you'd do at runtime, that doesn't really seem worth it.
You can create a PL/SQL table type based on your table's rowtype, but you would only be able to call a function returning that from PL/SQL, not from plain SQL - so you couldn't use it in a table collection expression for example. If you were only returning a single sample row you could return a record rather than a table, but the same applies. You can also have a function that returns a ref cursor which could match the table's structure, but you wouldn't be able to treat that as a table either.
Read more about object type creation in the documentation. Specifically the attribute and datatype sections.

Resources