Init REFs in constructor in Oracle database object - oracle

I have a problem with initialization of REF values in Oracle. When trying to set them in constructor I get errors, no matter how I try it. Is there any way to init them on construction in situation like that?
CREATE TYPE tSomething AS OBJECT (
Name Varchar(30)
);
CREATE TYPE tSomethingElse AS OBJECT (
Something REF tSomething
);

Ref is unique identifier of existing object. You have to create object table to get this unique identifier.
CREATE TYPE tSomething AS OBJECT (
Name Varchar(30)
);
create table tSomething_table of tSomething;
CREATE TYPE tSomethingElse AS OBJECT (
Something REF tSomething
);
declare
tSomethingElse_obj tSomethingElse;
tSomething_ref REF tSomething;
tSomething_obj tSomething;
begin
-- insert objects into tSomething_table
insert into tSomething_table values('abc');
insert into tSomething_table values('yyy');
-- get ref one object.
select ref(p) into tSomething_ref from tSomething_table p where p.name = 'abc';
-- initialize tSomethingElse_obj;
tSomethingElse_obj := new tSomethingElse(tSomething_ref);
-- extract get real tSomething object from ref
select deref(tSomething_ref) into tSomething_obj from dual;
end;

Related

Define a record type in PL/SQL block that references a collection of itself

How to define a record type in PL/SQL anonymous block that contains a property that is a collection of itself? Look at the following example:
DECLARE
type t_item is record (
name varchar2(64),
children t_items -- referencing t_items type
);
type t_items is table of t_item; -- referencing t_item type
BEGIN
-- script code
END
PL/SQL has no type hoisting so Oracle engine raises an exception:
PLS-00498: illegal use of a type before its declaration
How to define a record t_item that contains a table of t_item in its property children?
You can use objects defined in the SQL Scope using inheritance:
SQL Fiddle
Oracle 11g R2 Schema Setup:
CREATE TYPE abstract_item IS OBJECT (
name VARCHAR2(64)
) NOT FINAL NOT INSTANTIABLE
/
CREATE TYPE t_items IS TABLE OF abstract_item
/
CREATE TYPE t_item UNDER abstract_item (
children t_items
) INSTANTIABLE
/
Query 1:
SELECT t_item(
'1',
t_items(
t_item( '1.1', t_items() ),
t_item(
'1.2',
t_items(
t_item( '1.2.1', null )
)
),
t_item( '1.3', null )
)
)
FROM DUAL
Results: (SQLFiddle doesn't display it nicely - but it runs without errors)
| T_ITEM('1',T_ITEMS(T_ITEM('1.1',T_ITEMS()),T_ITEM('1.2',T_ITEMS(T_ITEM('1.2.1',NULL))),T_ITEM('1.3',NULL))) |
|-------------------------------------------------------------------------------------------------------------|
| oracle.sql.STRUCT#2a094aab |
You could use a similar declaration in PL/SQL:
DECLARE
items t_item;
BEGIN
items = t_item( 'Item Name', t_items( /* ... */ ) );
END;
/
An example with reference to objects:
create or replace type item; -- forward declaration
/
create or replace type l_item_ref is table of ref item;
/
create or replace type item is object( a number, list l_item_ref)
/
CREATE TABLE t_item OF item nested table list store as ref_items
/
declare
v_list l_item_ref;
begin
insert into t_item values(1,null);
insert into t_item values(2,null);
insert into t_item values(3,null);
select ref(p) bulk collect into v_list from t_item p;
insert into t_item values(123,v_list);
commit;
end;
select p.a,p.list from t_item p;
Below is an example of create a custom record type and then create table type using the custom record type.
In your spec file you can define the custom type as below.
TYPE STUDENT IS RECORD
("ID" NUMBER,
"NAME" VARCHAR2(100)
);
TYPE STUDENT_TABLE IS TABLE OF STUDENT;
Now in your package body you can use the custom table which you have defined as below.
students STUDENT_TABLE; (Declaration of variable of type student_table)
As this does not work as a table you can not do direct insert on this. And one more thing to remember as in table if you insert record one after another it basically makes a new entry but in case of custom record type will replace the old one.
**SELECT
123 AS ID,
abc AS NAME
BULK COLLECT INTO STUDENT_TABLE FROM DUAL;** --(This is how we insert)
Consider if we execute same statement with different values again it will override the previous one as explained above.
So if you have a requirement to append records then you can follow the below approach.
students STUDENT_TABLE;
studentsTemp STUDENT_TABLE; (Declare a temp also to store the previous value)
**SELECT
123 AS ID,
abc AS NAME
BULK COLLECT INTO STUDENT_TABLE FROM DUAL;
studentsTemp := STUDENT_TABLE;
SELECT
789 AS ID,
xyz AS NAME
BULK COLLECT INTO STUDENT_TABLE FROM DUAL;
studentsTemp := students multiset union all studentsTemp;** --(This is how you can append)
Below is the way to return it through cursor.
OPEN CursorStudent FOR
SELECT ID,
NAME,
FROM TABLE(studentsTemp); (Will return all records.)
Advantage of using this is you can avoid temporary tables and less scripts to maintain when moving to higher environments.

Oracle use defined type in package as record added to table of defined type

I have the following package.
CREATE OR REPLACE PACKAGE offer_actions AS
TYPE opis_oferty_type IS RECORD (nazwa varchar(11), rocznik number(4), cena decimal(10,2), imie_klienta varchar(32), nazwisko_klienta varchar(32));
TYPE opis_ofert_table IS TABLE OF varchar(100);
komis_id komisy.idk%TYPE :=0;
CURSOR c_oferty RETURN opis_oferty_type;
FUNCTION find_oferrs(komis_id number) RETURN opis_ofert_table;
END offer_actions;
/
CREATE OR REPLACE PACKAGE BODY offer_actions AS
CURSOR c_oferty RETURN opis_oferty_type IS
SELECT mar.nazwa, sze.rok_produkcji, ofe.cena_aktualna, kli.imie, kli.nazwisko FROM oferty ofe, szczegoly_oferty sze, modele modd, marki mar, klienci kli WHERE ofe.klient_id = kli.idk AND sze.oferta_id = ofe.idk AND ofe.model_id = modd.idk AND modd.marka_id = mar.idk AND ofe.komis_id = komis_id;
FUNCTION find_oferrs(komis_id number) RETURN opis_ofert_table IS
l_offers opis_ofert_table := opis_ofert_table();
BEGIN
FOR i in c_oferty LOOP
l_offers.EXTEND;
l_offers(l_offers.COUNT) := i.nazwa;
END LOOP;
RETURN l_offers;
END find_oferrs;
END offer_actions;
When I run script I get the following error.
PLS-00222: no function with name 'OPIS_OFERTY_TYPE' exists in this scope
How can I define opis_oferty_type to allow adding new record in operation
l_offers(l_offers.COUNT) := (opis_oferty_type(i.nazwa,i.rocznik,i.cena,i.imie_klienta, i.nazwisko_klienta));
Declared types.
CREATE OR REPLACE TYPE opis_oferty_type AS OBJECT
(nazwa varchar(11),
rocznik number(4),
cena decimal(10,2),
imie_klienta varchar(32),
nazwisko_klienta varchar(32)
);
/
CREATE OR REPLACE TYPE opis_ofert_table AS TABLE OF opis_oferty_type;
You are trying to use a record type like an object type. It's impossible.
Object types declared only at SQL level, record types only at PL/SQL level.
Either create type opis_oferty_type in SQL using create type ... as object, or continue to use a record type, but initialize every field of a record, like that:
Declare
l_v opis_oferty_type;
...
Begin
...
l_v.nazwa:= ...;
l_v.rocznik:= ...;
...
l_offers(l_offers.COUNT) := l_v;
Here's a pair of links for reference: Declaring Object Types, Initial Values of Record Variables

create a collection with 2 columns and insert all the rows at once PL/SQL

I have reference data which I want to use in a PL/SQL package.
This is a collection with two columns:
type table_info IS RECORD (
table_name VARCHAR2(50),
join_column VARCHAR2(50)
);
type config_tables_type is table of table_info; -- list of the config tables
I would like to add several rows at once to this collection, I tried this:
config_tables config_tables_type := config_tables_type (table_info('Commands','object_id'),
table_info('Contact_notificationcommands','command_object_id'),
table_info('Contactgroup_members','contact_object_id'),
table_info('Contactgroups','contact_object_id'),
table_info('Contactnotificationmethods','command_object_id'),
table_info('customvariables','object_id'),
table_info('Host_contactgroups','host_id'),
table_info('Host_contacts','host_id'),
table_info('Hostescalation_contactgroups','contactgroup_object_id'),
table_info('Hostescalation_contacts','contact_object_id'),
table_info('Host_parenthosts','parent_host_object_id'),
table_info('Hostdependencies','host_object_id'),
table_info('Hostdependencies','dependent_host_object_id'),
table_info('Hostescalations','host_object_id'),
table_info('Hostgroup_members','host_object_id'),
table_info('Hostgroups','hostgroup_object_id'),
table_info('Hosts','host_object_id'),
table_info('Service_contactgroups','contactgroup_object_id'),
table_info('Service_contacts','contact_object_id'),
table_info('Servicedependencies','service_object_id'),
table_info('Serviceescalation_contactgroups','contactgroup_object_id'),
table_info('Serviceescalation_contacts','contact_object_id'),
table_info('Serviceescalations','service_object_id'),
table_info('Servicegroup_members','service_object_id'),
table_info('Servicegroups','servicegroup_object_id'),
table_info('Services','service_object_id'),
table_info('Timeperiods','timeperiod_object_id')
);
But I have the following compilation error:
PLS-00222: no function with name 'TABLE_INFO' exists in this scope.
This type is declared in the package description and the initialisation of the config_tables collection is done in the package body.
Thanks
The below "hack" should do the trick!
declare
type table_info IS RECORD (
table_name VARCHAR2(50),
join_column VARCHAR2(50)
);
type config_tables_type is table of table_info;
config_tables config_tables_type;
function table_info_constructor(table_name VARCHAR2, join_column VARCHAR2) return table_info
is
t_i table_info;
begin
t_i.table_name := table_name;
t_i.join_column := join_column;
return(t_i);
end;
begin
config_tables := config_tables_type(table_info_constructor('Commands','object_id'),
table_info_constructor('Contact_notificationcommands','command_object_id'),
table_info_constructor('Contactgroup_members','contact_object_id'),
table_info_constructor('Contactgroups','contact_object_id'),
table_info_constructor('Contactnotificationmethods','command_object_id'),
table_info_constructor('customvariables','object_id'),
table_info_constructor('Host_contactgroups','host_id'),
table_info_constructor('Host_contacts','host_id'),
table_info_constructor('Hostescalation_contactgroups','contactgroup_object_id'),
table_info_constructor('Hostescalation_contacts','contact_object_id'),
table_info_constructor('Host_parenthosts','parent_host_object_id'),
table_info_constructor('Hostdependencies','host_object_id'),
table_info_constructor('Hostdependencies','dependent_host_object_id'),
table_info_constructor('Hostescalations','host_object_id'),
table_info_constructor('Hostgroup_members','host_object_id'),
table_info_constructor('Hostgroups','hostgroup_object_id'),
table_info_constructor('Hosts','host_object_id'),
table_info_constructor('Service_contactgroups','contactgroup_object_id'),
table_info_constructor('Service_contacts','contact_object_id'),
table_info_constructor('Servicedependencies','service_object_id'),
table_info_constructor('Serviceescalation_contactgroups','contactgroup_object_id'),
table_info_constructor('Serviceescalation_contacts','contact_object_id'),
table_info_constructor('Serviceescalations','service_object_id'),
table_info_constructor('Servicegroup_members','service_object_id'),
table_info_constructor('Servicegroups','servicegroup_object_id'),
table_info_constructor('Services','service_object_id'),
table_info_constructor('Timeperiods','timeperiod_object_id')
);
end;
Let me know how it works out for you.
For any further clarifications don't hesitate to ask me.
Ted.
There is an another alternative where you can basically create a schema level object i.e OBJECT type and TABLE Type and then call it in the plsql block as shown below. Hope this helps too.
--Create object type
CREATE OR REPLACE TYPE table_info
IS
OBJECT
(
table_name VARCHAR2(50),
join_column VARCHAR2(50))
/
--Create table type on Object type
CREATE OR REPLACE TYPE config_tables_type
IS
TABLE OF table_info
/
--PLSQL block of code
DECLARE
config_tables config_tables_type;
BEGIN
config_tables config_tables_type := config_tables_type (table_info('Commands','object_id'),
table_info('Contact_notificationcommands','command_object_id'),
table_info('Contactgroup_members','contact_object_id'),
table_info('Contactgroups','contact_object_id'),
table_info('Contactnotificationmethods','command_object_id'),
table_info('customvariables','object_id'),
table_info('Host_contactgroups','host_id'),
table_info('Host_contacts','host_id'),
table_info('Hostescalation_contactgroups','contactgroup_object_id'),
table_info('Hostescalation_contacts','contact_object_id'),
table_info('Host_parenthosts','parent_host_object_id'),
table_info('Hostdependencies','host_object_id'),
table_info('Hostdependencies','dependent_host_object_id'),
table_info('Hostescalations','host_object_id'),
table_info('Hostgroup_members','host_object_id'),
table_info('Hostgroups','hostgroup_object_id'),
table_info('Hosts','host_object_id'),
table_info('Service_contactgroups','contactgroup_object_id'),
table_info('Service_contacts','contact_object_id'),
table_info('Servicedependencies','service_object_id'),
table_info('Serviceescalation_contactgroups','contactgroup_object_id'),
table_info('Serviceescalation_contacts','contact_object_id'),
table_info('Serviceescalations','service_object_id'),
table_info('Servicegroup_members','service_object_id'),
table_info('Servicegroups','servicegroup_object_id'),
table_info('Services','service_object_id'),
table_info('Timeperiods','timeperiod_object_id')
);
END;
/

"cannot INSERT object view REF or user-defined REF"

I have a C_table and M_table and there is a m to 1 relationship between C_table and M_table, also I have L_table which Is A C_table type, , I'm trying to use OODBMS using oracle SQL Developer. I have the following types and tables:
create type C_table as object
(
se number(10),
sp number(10),
pr number(15),
me number(3),
ste S_type,
name ref M_type
)not final;
create type m_type as object
(
name varchar2(25),
add varchar(25)
);
type L_type under computer_type
(
w number(5)
);
and I have created their tables, as well, now I'm trying to insert into thhe L_table as follow and I'm getting the following error:
insert into l_tab select 500,2,1600,4, S_type('Ms','Me'), REF(d),1.5 from m_tab d where
d.name= 'Int';
SQL Error: ORA-22979: cannot INSERT object view REF or user-defined REF
22979. 00000 - "cannot INSERT object view REF or user-defined REF"
*Cause: Attempt to insert an object view REF or user-defined REF in a
REF column created to store system generated REF values"
*Action: Make sure the REF to be inserted is not from an object view
or from a user-defined REF column
I'm sorry I can't load the full script because of the confidential rights. But I'm happy to share the solution to this problem.
create type C_table as object
(
se number(10),
sp number(10),
pr number(15),
me number(3),
ste S_type,
name ref M_type
)not final;
create type m_type as object
(
name varchar2(25),
add varchar(25)
);
type L_type under computer_type
(
w number(5)
);
Based on ERD we have already knew that L_type Is-A C_type, and we know C_type has a reference to M_type. When I created the table out of these types, I did't know I have to define a foreign key from M_table in L_table as well, and I was thinking since L_table derived from C_table, if I define the foreign key in the C_table is enough, but it was not enough and I had to define a foreign key from M_table in L_table as well like this
create table C_table of C_type
(foreign key (name) references M_table)
object id primary key
and also :
create table l_table of l_type
(foreign key (name) references M_table)
object id primary key
now if I use this query I won't have any problem or error:
insert into l_tab select 500,2,1600,4, S_type('Ms','Me'), REF(d),1.5 from m_tab d where
d.name= 'Int';
also I read in some blogs that we have to be careful to don't use system names, and predefined name as an attribute in a table, like in this example I used name in M_table, which is not a good way, so finally I changed it to M_name instead of name.

ORA-00947 Not enough values while declaring type globally

create table foo(
id number,
status varchar2(10)
);
Table created.
insert into foo values( 1, 'open' );
insert into foo values( 2, 'close' );
insert into foo values( 3, 'open' );
insert into foo values( 4, 'open' );
insert into foo values( 5, 'close' );
create type foo_obj is object (
id number,
status varchar2(10)
);
/
create type foo_nt
as table of foo_obj;
/
create or replace package test_bulk
is
procedure temp;
end;
/
create or replace package body test_bulk
is
procedure temp
is
v_nt foo_nt;
begin
select id ,status
bulk collect into v_nt
from foo;
end temp;
end test_bulk;
This is a very odd situation, when I create a type object and nested table of that type Globally and create a variable of the nested table type and bulk collect into that variable I get
ORA-00947: not enough values error
However, when I declare a record type and nested table of that record type And then a variable of the nested table Inside the package , then the above bulk collect works and it will not throw error
Can anyone help me out with this?
You can't just put values into a table of objects - you need to convert the values into objects of the appropriate type and then insert the objects. Try
procedure temp is
v_nt foo_nt;
begin
select FOO_OBJ(id ,status)
bulk collect into v_nt
from foo;
end temp;
Not tested on animals - you'll be first!
Share and enjoy.

Resources