How to insert data into table which has a ref and scope - sql

This is my user defined Type which i have created.
create or Replace TYPE cust_address_typ_new AS OBJECT
( add_id NUMBER,
street_address VARCHAR2(40)
, postal_code VARCHAR2(10)
, city VARCHAR2(30)
, state_province VARCHAR2(10)
, country_id CHAR(2)
);
and the below is the table of new type
CREATE TABLE address_table OF cust_address_typ_new;
Now i created another table as below
CREATE TABLE customer_addresses (
add_id NUMBER,
address REF cust_address_typ_new
SCOPE IS address_table);
and now i'm trying to insert values into customer_addresses table
insert into customer_addresses
values(1,SYSTEM.CUST_ADDRESS_TYP_NEW(1,'hi','87987','city','state',''))

Using sqlcl (Oracle 12.1):
create or Replace TYPE cust_address_typ_new AS OBJECT (
add_id NUMBER
, street_address VARCHAR2(40)
, postal_code VARCHAR2(10)
, city VARCHAR2(30)
, state_province VARCHAR2(10)
, country_id CHAR(2)
);
/
-- Type CUST_ADDRESS_TYP_NEW compiled
CREATE TABLE address_table OF cust_address_typ_new ;
-- Table ADDRESS_TABLE created.
CREATE TABLE customer_addresses (
add_id NUMBER
, address REF cust_address_typ_new SCOPE IS address_table
);
-- Table CUSTOMER_ADDRESSES created.
Errors
insert into customer_addresses
values ( 1, SYSTEM.CUST_ADDRESS_TYP_NEW(1,'hi','87987','city','state','') ) ;
-- ORA-00904: "SYSTEM"."CUST_ADDRESS_TYP_NEW": invalid identifier
insert into customer_addresses
values ( 1, CUST_ADDRESS_TYP_NEW( 1,'hi','87987','city','state','' ) ) ;
-- ORA-00932: inconsistent datatypes: expected REF ...CUST_ADDRESS_TYP_NEW got ...CUST_ADDRESS_TYP_NEW
From the documentation:
REF takes as its argument a correlation variable (table alias)
associated with a row of an object table or an object view. A REF
value is returned for the object instance that is bound to the
variable or row.
The following examples my help you:
-- {1} insert into the address_table ( 3 examples )
insert into address_table
values ( 1,'hi','87987','city','state','' ) ;
-- 1 row inserted.
insert into address_table
values( cust_address_typ_new( 2,'hi again','12345','city2','state2','' ) ) ;
-- 1 row inserted
insert into address_table
values( new cust_address_typ_new( 3,'hmpf','23456','city3','state3','' ) ) ;
-- 1 row inserted.
-- result
SQL> select * from address_table;
ADD_ID STREET_ADDRESS POSTAL_CODE CITY STATE_PROVINCE COUNTRY_ID
1 hi 87987 city state NULL
2 hi again 12345 city2 state2 NULL
3 hmpf 23456 city3 state3 NULL
Maybe you don't need the sequence (just added to fill the add_id column in the customer_addresses table).
-- {2} select from the address_table, use ref(),
-- insert into customer_addresses
SQL> create sequence ca_seq start with 1000 increment by 1;
Sequence CA_SEQ created.
insert into customer_addresses
select ca_seq.nextval, ref(AT) from address_table AT ;
-- result
select * from customer_addresses;
ADD_ID
----------
ADDRESS
------------------------------------------------------------------------
1000
2202086FC2AC912CD41038E0530100007F525D6FC2AC912CCD1038E0530100007F525D
1001
2202086FC2AC912CD51038E0530100007F525D6FC2AC912CCD1038E0530100007F525D
1002
2202086FC2AC912CD61038E0530100007F525D6FC2AC912CCD1038E0530100007F525D

Related

Oracle Database - REF unsupported data type

So I have three tables, Staff, Book, and Sale.
For Staff:
CREATE TYPE StaffType AS OBJECT (
ID VARCHAR2(5),
Name VARCHAR2(30)
);
/
CREATE TABLE Staff of StaffType;
For Book:
CREATE TYPE BookType AS OBJECT (
B_ID VARCHAR2(8));
/
CREATE TABLE Book of TicketType;
For Sale:
CREATE TYPE SaleType AS OBJECT (
S_ID VARCHAR2(8),
S_Date VARCHAR2(10),
Price NUMBER(10),
With REF StaffType,
For REF BookType );
/
CREATE TABLE Sale of SaleType (
Scope for (With) is Staff,
Scope for (For) is Book);
So I inserted a row in Sale table like this
insert into Sale VALUES(SaleType('S12','33th',22,(SELECT REF(c) FROM Staff c WHERE c.ID='C13'),(SELECT REF(t) FROM Book t WHERE t.B_ID='T18'));
however, I get the following error:
ORA-00917: missing comma
I don't understand why I am getting this error.. What comma did I miss?
EDIT: I followed the solution of #thatjeffsmith and although the insert statement works, when I try to view my table, I get the following error:
ORA-00932: inconsistent datatypes: expected CHAR got REF SQL_VTJOLYEBVKAOJEHORTCXVPTBP.STAFFTYPE
here is the code.. I removed HR. before Book and Staff from sale table declaration because that was causing the worksheet to show an error stating that Staff and Book are out of scope. Here is the code:
CREATE TYPE STAFFTYPE AS OBJECT (
ID VARCHAR2(5),
NAME VARCHAR2(30)
);
/
CREATE TABLE STAFF OF STAFFTYPE;
/
INSERT INTO STAFF VALUES('C13','James');
/
CREATE TYPE BOOKTYPE AS OBJECT (
B_ID VARCHAR2(8)
);
/
CREATE TABLE BOOK OF BOOKTYPE;
/
INSERT INTO BOOK VALUES('T18');
/
CREATE TYPE SALETYPE AS OBJECT (
S_ID VARCHAR2(8),
S_DATE VARCHAR2(10),
PRICE NUMBER(10),
WITHS REF STAFFTYPE,
FORS REF BOOKTYPE
);
/
CREATE TABLE SALE OF SALETYPE (
SCOPE FOR ( WITHS ) IS STAFF,
SCOPE FOR ( FORS ) IS BOOK
);
INSERT INTO SALE VALUES ( SALETYPE(
'S12', '33th',
22,
(
SELECT REF(C)
FROM STAFF C
WHERE C.ID = 'C13'
),
(
SELECT REF(T)
FROM BOOK T
WHERE T.B_ID = 'T18'
)
) );
SELECT * FROM SALE;
WITH and FOR are keywords, not available as a table or column name. You could "QUOTE" these, but DO NOT DO THAT - it will make your life much harder going forward.
Your BOOK table is wrong, you're using a TYPE that doesn't exist per your example.
And your INSERT is missing the last ')'
CREATE TYPE STAFFTYPE AS OBJECT (
ID VARCHAR2(5),
NAME VARCHAR2(30)
);
/
CREATE TABLE STAFF OF STAFFTYPE;
CREATE TYPE BOOKTYPE AS OBJECT (
B_ID VARCHAR2(8)
);
/
CREATE TABLE BOOK OF BOOKTYPE;
CREATE TYPE SALETYPE AS OBJECT (
S_ID VARCHAR2(8),
S_DATE VARCHAR2(10),
PRICE NUMBER(10),
WITHS REF STAFFTYPE,
FORS REF BOOKTYPE
);
/
CREATE TABLE SALE OF SALETYPE (
SCOPE FOR ( WITHS ) IS HR.STAFF,
SCOPE FOR ( FORS ) IS HR.BOOK
);
INSERT INTO SALE VALUES ( SALETYPE(
'S12', '33th',
22,
(
SELECT REF(C)
FROM STAFF C
WHERE C.ID = 'C13'
),
(
SELECT REF(T)
FROM BOOK T
WHERE T.B_ID = 'T18'
)
) );

ORA-22814: attribute or element value is larger than specified in type

SQL> create or replace type societe
as object (nom_societe varchar2(20),ville_societe varchar2(20));
/
create or replace type produit as object(
nom varchar2(20),
poids number(9),
couleur varchar2(20),
composants varchar2(2));
/
SQL> insert into commande(NUMERO,DATE_SOUMISSION,DATE_ENVOI,SOCIETE,PRODUIT) values(
2 1,to_date('2013/03/11','yyyy/mm/dd'),to_date('2014/05/12','yyyy/mm/dd'),
3 societe('BME','FES'),produit('prod1',12,'noir','aluminium'));
insert into commande(NUMERO,DATE_SOUMISSION,DATE_ENVOI,SOCIETE,PRODUIT) values(
*
ERROR at line 1:
ORA-22814: attribute or element value is larger than specified in type
SQL> create table commande(
2 numero number(9),
3 date_soumission date,
4 date_envoi date,
5 societe societe,
6 produit produit);
composants varchar2(2)
'aluminium'
Clearly the fourth element 'aluminium' you are trying to insert into composants attribute, is larger than 2 characters/bytes as the size of data type is VARCHAR2(2). Increase the size of composants so that it can store the element.
CREATE OR REPLACE TYPE societe AS OBJECT (
nom_societe VARCHAR2(20),
ville_societe VARCHAR2(20)
)
/
CREATE OR REPLACE TYPE produit AS OBJECT (
nom VARCHAR2(20),
poids NUMBER(9),
couleur VARCHAR2(20),
composants VARCHAR2(20)
)
/
CREATE TABLE commande (
numero NUMBER(9),
date_soumission DATE,
date_envoi DATE,
society societe,
product produit
);
Now you can insert in following way:
INSERT INTO commande (
numero,
date_soumission,
date_envoi,
society,
product
) VALUES (
1,
TO_DATE('2013/03/11', 'yyyy/mm/dd'),
TO_DATE('2014/05/12', 'yyyy/mm/dd'),
societe('BME', 'FES'),
produit('prod1', 12, 'noir', 'aluminium')
);
You can check the data inserted:
SELECT * FROM commande;
NUMERO DATE_SOU DATE_ENV SOCIETY(NOM_SOCIETE, PRODUCT(NOM, POIDS, COULEUR, COMPOSANTS)
------ -------- -------- --------------------- -----------------------------------------
1 11-03-13 12-05-14 SOCIETE('BME', 'FES') PRODUIT('prod1', 12, 'noir', 'aluminium')

How to create an Oracle audit trigger?

CREATE OR REPLACE TRIGGER EVALUATION
BEFORE INSERT OR UPDATE OR DELETE ON BOOKING
FOR EACH ROW
DECLARE
BEGIN
SELECT BOOKING_EVALUATION FROM BOOKING WHERE BOOKING_EVALUATION > 2;
SELECT BOOKING_EVALUATION INTO EVALUATIONAUDIT FROM BOOKING;
IF INSERTING THEN
INSERT INTO EVALUATIONAUDIT (VOYAGES_ID,CUSTOMER_NAME,START_DATE,SHIP_NAME,BOOKING_EVALUATION)
VALUES(:NEW.VOYAGES_ID,:NEW.CUSTOMER_NAME,:NEW.START_DATE,:NEW.SHIP_NAME,:NEW.BOOKING_EVALUATION);
END IF;
IF UPDATING THEN
INSERT INTO EVALUATIONAUDIT (VOYAGES_ID,CUSTOMER_NAME,START_DATE,SHIP_NAME,BOOKING_EVALUATION)
VALUES(:OLD.VOYAGES_ID,:OLD.CUSTOMER_NAME,:OLD.START_DATE,:OLD.SHIP_NAME,:OLD.BOOKING_EVALUATION);
END IF;
IF DELETING THEN
INSERT INTO EVALUATIONAUDIT (VOYAGES_ID,CUSTOMER_NAME,START_DATE,SHIP_NAME,BOOKING_EVALUATION)
VALUES(:OLD.VOYAGES_ID,:OLD.CUSTOMER_NAME,:OLD.START_DATE,:OLD.SHIP_NAME,:OLD.BOOKING_EVALUATION);
END IF;
END;
This is my audit table:
desc evaluationaudit;
Name Null? Type
----------------------------------------- -------- -----------------------
AUDITT_ID NOT NULL NUMBER(10)
VOYAGES_ID NOT NULL NUMBER(10)
CUSTOMER_NAME NOT NULL VARCHAR2(20)
START_DATE NOT NULL DATE
SHIP_NAME NOT NULL VARCHAR2(20)
BOOKING_EVALUATION NOT NULL NUMBER(20)
and this is my show error output:
SQL> SHOW ERRORS;
Errors for TRIGGER EVALUATION:
LINE/COL ERROR
-------- -------------------------------------------------------------
12/24 PLS-00049: bad bind variable 'NEW.CUSTOMER_NAME'
12/43 PLS-00049: bad bind variable 'NEW.START_DATE'
12/59 PLS-00049: bad bind variable 'NEW.SHIP_NAME'
18/24 PLS-00049: bad bind variable 'OLD.CUSTOMER_NAME'
18/43 PLS-00049: bad bind variable 'OLD.START_DATE'
18/59 PLS-00049: bad bind variable 'OLD.SHIP_NAME'
24/24 PLS-00049: bad bind variable 'OLD.CUSTOMER_NAME'
24/43 PLS-00049: bad bind variable 'OLD.START_DATE'
24/59 PLS-00049: bad bind variable 'OLD.SHIP_NAME'
I wanted to add to the audit table. If a customer gives a poor evaluation of 2 or less, the details of their voyage (customer_name, name and date of the cruise, ship name and evaluation) but I'm getting error
Warning: Trigger created with compilation errors.
And the audit table is empty, showing no rows selected. I can't seem to find the problem where I am going wrong.
Maybe the following code snippets will help you. Suppose we have 2 tables: BOOKING, and EVALUATION_AUDIT (everything written in uppercase letters is taken from the code in your question).
Tables
create table booking (
VOYAGES_ID number primary key
, CUSTOMER_NAME VARCHAR2(20) NOT NULL
, START_DATE DATE NOT NULL
, SHIP_NAME VARCHAR2(20) NOT NULL
, BOOKING_EVALUATION NUMBER(20) NOT NULL
) ;
create table evaluationaudit (
AUDITT_ID number generated always as identity start with 5000 primary key
, trg_cond_pred varchar2( 64 ) default 'Row not added by evaluation trigger!'
, VOYAGES_ID NUMBER(10) NOT NULL
, CUSTOMER_NAME VARCHAR2(20) NOT NULL
, START_DATE DATE NOT NULL
, SHIP_NAME VARCHAR2(20) NOT NULL
, BOOKING_EVALUATION NUMBER(20) NOT NULL
) ;
Trigger
-- "updating" and "deleting" code omitted for clarity
CREATE OR REPLACE TRIGGER EVALUATION_trigger
BEFORE INSERT OR UPDATE OR DELETE ON BOOKING
FOR EACH ROW
BEGIN
case
when INSERTING then
if :new.booking_evaluation <= 2 then
INSERT INTO EVALUATIONAUDIT
( trg_cond_pred,
VOYAGES_ID, CUSTOMER_NAME, START_DATE, SHIP_NAME, BOOKING_EVALUATION )
VALUES (
'INSERTING'
, :NEW.VOYAGES_ID
, :NEW.CUSTOMER_NAME
, :NEW.START_DATE
, :NEW.SHIP_NAME
, :NEW.BOOKING_EVALUATION
);
end if ;
end case ;
END ;
/
Testing
One of your requirements (in your question) is:
I wanted to add to the audit table. If a customer gives a poor
evaluation of 2 or less, the details of their voyage (customer_name,
name and date of the cruise, ship name and evaluation)
delete from evaluationaudit ;
delete from booking ;
-- booking_evaluation greater than 2 -> no entry in audit table
insert into booking
( VOYAGES_ID, CUSTOMER_NAME, START_DATE, SHIP_NAME, BOOKING_EVALUATION )
values ( 1111, 'customer1', date '2018-05-24', 'ship1', 9999 ) ;
select * from evaluationaudit ;
-- no rows selected
-- booking_evalution = 2 -> insert a row into the audit table
insert into booking
( VOYAGES_ID, CUSTOMER_NAME, START_DATE, SHIP_NAME, BOOKING_EVALUATION )
values ( 1112, 'customer1', date '2018-05-24', 'ship1', 2 ) ;
select * from evaluationaudit ;
AUDITT_ID TRG_COND_PRED VOYAGES_ID CUSTOMER_NAME START_DATE SHIP_NAME BOOKING_EVALUATION
5000 INSERTING 1112 customer1 24-MAY-18 ship1 2
__Update__
If - as you wrote in your comment - you need to pull in some more data from other tables, maybe you want to try the following approach: keep the trigger code rather brief, and use it to call a procedure for the more complicated stuff eg
Tables
create table evaluationaudit (
AUDITT_ID number generated always as identity start with 7000 primary key
, trg_cond_pred varchar2( 64 ) default 'Row not added by evaluation trigger!'
, VOYAGES_ID NUMBER NOT NULL
, CUSTOMER_NAME VARCHAR2(20) NOT NULL
, SHIP_NAME VARCHAR2(20) NOT NULL
, BOOKING_EVALUATION NUMBER(20) NOT NULL
) ;
create table ships ( name varchar2( 64 ), id number unique ) ;
create table customers ( name varchar2( 64 ), id number unique ) ;
insert into ships ( name, id ) values ( 'ship1', 501 );
insert into ships ( name, id ) values ( 'ship2', 502 );
insert into ships ( name, id ) values ( 'ship3', 503 );
insert into customers ( name, id ) values ( 'customer1', 771 ) ;
insert into customers ( name, id ) values ( 'customer2', 772 ) ;
insert into customers ( name, id ) values ( 'customer3', 773 ) ;
create table bookings (
id number generated always as identity start with 5000 primary key
, voyagesid number
, shipid number
, customerid number
, evaluation number
, bookingdate date
);
Trigger
create or replace trigger bookingeval
before insert on bookings
for each row
when ( new.evaluation <= 2 ) -- Use NEW without colon here! ( see documentation )
begin
auditproc( :new.voyagesid, :new.customerid, :new.shipid, :new.evaluation ) ;
end ;
/
Procedure
create or replace procedure auditproc (
voyagesid_ number
, customerid_ number
, shipid_ number
, evaluation_ number
)
as
customername varchar2( 64 ) := '' ;
shipname varchar2( 64 ) := '' ;
begin
-- need to find the customername and shipname before INSERT
select name into customername from customers where id = customerid_ ;
select name into shipname from ships where id = shipid_ ;
insert into evaluationaudit
( trg_cond_pred,
voyages_id, customer_name, ship_name, booking_evaluation )
values (
'INSERTING'
, voyagesid_
, customername
, shipname
, evaluation_
);
end ;
/
Testing
-- evaluation > 2 -> no INSERT into evaluationaudit
insert into bookings
( voyagesid, customerid, shipid, evaluation, bookingdate )
values ( 1111, 771, 501, 9999, sysdate ) ;
select * from evaluationaudit ;
-- no rows selected
-- evaluation = 2
-- -> trigger calling audit procedure -> inserts into evaluationaudit
insert into bookings
( voyagesid, customerid, shipid, evaluation, bookingdate )
values ( 1112, 772, 502, 2, sysdate ) ;
select * from evaluationaudit ;
AUDITT_ID TRG_COND_PRED VOYAGES_ID CUSTOMER_NAME SHIP_NAME BOOKING_EVALUATION
7000 INSERTING 1112 customer2 ship2 2

Check if ID of parent table's record is contained in just one of the child tables

To preface this, I have 3 tables, there is table
Product
- id
- name
- availability
Then is has 2 child tables:
Tables
- id
- product_id (foreign key to product(id))
- size
Chairs
- id
- product_id (foreign key to product(id))
- color
What I want to do is everytime I insert a new record into the chairs/tables table, I want to check whether it is not already contained in one of them. Or in other words, one product cannot be chair and table at once. How do I do this?
Thank you.
You could use a CHECK constraint for this, which, in combination with some other constraints, may give you the required behaviour. There are some restrictions on check constraints, one of them being:
The condition of a check constraint can refer to any column in the
table, but it cannot refer to columns of other tables.
( see the documentation )
In the following example, the ID columns "chairs.id" and "tables.id" have been moved into the "products" table, which contains the CHECK constraint. The UNIQUE constraints enforce a one-to-one relationship as it were ( allowing only one value for each of the REFERENCED ids ). The DDL code looks a bit busy, but here goes:
Tables
create table products (
id number generated always as identity primary key
, name varchar2(128)
, availability varchar2(32)
);
-- product_id removed
create table tables (
id number primary key
, size_ number
) ;
-- product_id removed
create table chairs (
id number primary key
, color varchar2(32)
);
Additional columns and constraints
alter table products
add (
table_id number unique
, chair_id number unique
, check (
( table_id is not null and chair_id is null )
or
( table_id is null and chair_id is not null )
)
);
alter table tables
add constraint fkey_table
foreign key ( id ) references products ( table_id ) ;
alter table chairs
add constraint fkey_chairs
foreign key ( id ) references products ( chair_id ) ;
Testing
-- {1} Add a chair: the chair_id must exist in PRODUCTS.
insert into chairs ( id, color ) values ( 1000, 'maroon' ) ;
-- ORA-02291: integrity constraint ... violated - parent key not found
-- Each chair needs an entry in PRODUCTS first:
insert into products ( name, availability, chair_id )
values ( 'this is a chair', 'in stock', 1000 ) ;
insert into chairs ( id, color ) values ( 1000, 'maroon' ) ;
-- okay
-- {2} We cannot add another chair that has the same chair_id. Good.
insert into products ( chair_id ) values ( 1000 ) ;
-- ORA-00001: unique constraint ... violated
-- {3} Add a table.
insert into products ( name, availability, table_id )
values ( 'this is a table', 'unavailable', 1000 ) ;
-- okay
insert into tables ( id, size_ ) values ( 1000, 60 ) ;
-- {4} Is it possible to add another table, with the same table_id? No. Good.
insert into tables ( id, size_ ) values ( 1000, 60 ) ;
-- ORA-00001: unique constraint ... violated
insert into products ( name, availability, table_id )
values ('this is a table', 'unavailable', 1000 ) ;
-- ORA-00001: unique constraint ... violated
-- {5} We cannot add something that is a chair _and_ a table (at the same time).
insert into products ( name, availability, table_id, chair_id )
values ( 'hybrid', 'awaiting delivery', 2000, 2000 ) ;
-- ORA-02290: check constraint ... violated
Resultset
SQL> select * from products;
ID NAME AVAILABILITY TABLE_ID CHAIR_ID
21 this is a chair in stock NULL 1000
23 this is a table unavailable 1000 NULL
NOTE: The product ID (NOT the table_id or the chair_id) "identifies" a particular table/chair. The values in the TABLE_ID and CHAIR_ID columns are only used to "link" to the (unique) IDs in the child table(s).
Alternative: object-relational approach.
This solution may be more suitable for solving the problem. Here, we create a supertype (product_t) first, and then 2 subtypes (chair_t and table_t, respectively). This allows us to create a table PRODUCTS_, using product_t for storing the data we need.
Types and table
create or replace type product_t as object (
name varchar2(64)
, availability varchar2(64)
)
not final;
/
create or replace type chair_t under product_t (
color varchar2(64)
)
/
create or replace type table_t under product_t (
size_ number
)
/
create table products_ (
id number generated always as identity primary key
, product product_t
);
Testing
-- "standard" INSERTs
begin
insert into products_ ( product )
values ( chair_t( 'this is a chair', 'in stock', 'maroon' ) );
insert into products_ ( product )
values ( table_t( 'this is a table', 'not available', 60 ) );
end;
/
-- unknown types cannot be inserted
insert into products_ ( product )
values ( unknown_t( 'type unknown!', 'not available', 999 ) );
-- ORA-00904: "UNKNOWN_T": invalid identifier
insert into products_ ( product )
values ( product_t( 'supertype', 'not available', 999 ) );
-- ORA-02315: incorrect number of arguments for default constructor
-- object of SUPERtype can be inserted
insert into products_ ( product )
values ( product_t( 'supertype', 'not available' ) );
-- 1 row inserted.
Query
select
id
, treat( product as table_t ).name as name_of_table
, treat( product as chair_t ).name as name_of_chair
, case
when treat( product as table_t ) is not null
then 'TABLE_T'
when treat( product as chair_t ) is not null
then 'CHAIR_T'
when treat( product as product_t ) is not null
then 'PRODUCT_T'
else
'TYPE unknown :-|'
end which_type_is_it
from products_ ;
-- result
ID NAME_OF_TABLE NAME_OF_CHAIR WHICH_TYPE_IS_IT
1 NULL this is a chair CHAIR_T
2 this is a table NULL TABLE_T
3 NULL NULL PRODUCT_T -- neither a chair nor a table ...

Referring a nested table in a relational insert query

Below are the object types I have. Basically I have a person table and a child table as a nested table of person table.
I have a School table with a M:N Relationship with child table (nested). So I'm creating a intermediate table to insert child_school data.
How can I create that intermediate table and insert data?
create type school_t as object(
sid number(5,2),
name varchar(20))
/
create type child_t as object(
cid number(5,2),
name varchar(20))
/
create type childtable_t as table of child_t
/
create type person_t as object(
pid number(5,2),
name varchar(20),
child childtable_t)
/
create table person_tab of person_t(
pid primary key
)nested table child store as child_table
/
create table school_tab of school_t
/
--there's some problem. Below does not work.
create type school_child_t as object(
cid ref person_t,
sid ref school_t)
/
create table school_child_tab of school_child_t(
cid references person_tab,
sid references school_tab
)
/
--Here's what I want to do
create table school_child_tab(
cid number(5,2) references childtable_t,
sid number(5,2) references school_tab
)
/
cid reference should be the cid in nested table. The problem is referring it.
I saw your edit, and I was about to tell you it is impossible to reference a nested table externally.
The nested table is physically created as a distinct table that holds data separately from the parent table:
SQL> SELECT object_name, object_type
2 FROM all_objects
3 WHERE created > trunc(sysdate)
4 AND object_type = 'TABLE';
OBJECT_NAME OBJECT_TYPE
------------------------------ -------------------
SCHOOL_TAB TABLE
CHILD_TABLE TABLE
PERSON_TAB TABLE
Here you can see that Oracle has created a CHILD_TABLE table, however it is hidden from us and can only be worked internally by Oracle:
SQL> select * from child_table;
ORA-22812: cannot reference nested table column's storage table
In this case I was pretty sure that you couldn't reference the child table in any way, however to my surprise this seems to work (we can't select from CHILD_TABLE, however we can reference to it):
SQL> alter table child_table add constraint pk_child_table primary key (cid);
Table altered
SQL> CREATE TABLE school_child_tab (
2 cid REFERENCES child_table,
3 sid REFERENCES school_tab
4 );
Table created
You could build your inserts like this (I don't really like to store to store data as objects, but here you go):
SQL> insert into school_tab values (school_t(1, 'school A'));
1 row inserted
SQL> insert into person_tab values (
2 person_t(1, 'person A', childtable_t(child_t(1, 'child A'))));
1 row inserted
SQL> insert into school_child_tab values (1, 1);
1 row inserted
I have slightly altered your data model:
SQL> create type school_t as object(
2 sid number(5,2),
3 name varchar(20))
4 /
Type created.
SQL> create type child_t as object(
2 cid number(5,2),
3 name varchar(20))
4 /
Type created.
SQL> create table school_tab of school_t
2 /
Table created.
SQL> create table child_tab of child_t
2 /
Table created.
SQL>
Let's populate the nested tables:
SQL> insert into child_tab
2 values (111, 'Fred')
3 /
1 row created.
SQL> insert into child_tab
2 values (112, 'Ayesha')
3 /
1 row created.
SQL> insert into child_tab
2 values (113, 'Aadil')
3 /
1 row created.
SQL> insert into school_tab
2 values (222, 'Bash Street')
3 /
1 row created.
SQL> insert into school_tab
2 values (223, 'Greyfriars')
3 /
1 row created.
SQL>
Here is a nested table:
SQL> create type school_child_t as object(
2 cid ref child_t,
3 sid ref school_t)
4 /
Type created.
SQL> create table school_child_tab of school_child_t
2 /
Table created.
SQL>
We populate the intersection table like this:
SQL> insert into school_child_tab
2 select cid, sid
3 from
4 ( select ref(c) as cid from child_tab c where c.cid = 111 )
5 , ( select ref(s) as sid from school_tab s where s.sid = 222 )
6 /
1 row created.
SQL> insert into school_child_tab
2 select cid, sid
3 from
4 ( select ref(c) as cid from child_tab c where c.cid = 112 )
5 , ( select ref(s) as sid from school_tab s where s.sid = 222 )
6 /
1 row created.
SQL> insert into school_child_tab
2 select cid, sid
3 from
4 ( select ref(c) as cid from child_tab c where c.cid = 113 )
5 , ( select ref(s) as sid from school_tab s where s.sid = 222 )
6 /
1 row created.
SQL> insert into school_child_tab
2 select cid, sid
3 from
4 ( select ref(c) as cid from child_tab c where c.cid = 113 )
5 , ( select ref(s) as sid from school_tab s where s.sid = 223 )
6 /
1 row created.
SQL>
Query back the results
SQL> select c.name as child_name
2 , s.name as school_name
3 from school_child_tab sc
4 join child_tab c
5 on ( ref(c) = sc.cid )
6 join school_tab s
7 on ( ref(s) = sc.sid )
8 /
CHILD_NAME SCHOOL_NAME
-------------------- --------------------
Fred Bash Street
Ayesha Bash Street
Aadil Greyfriars
Aadil Bash Street
SQL>
Of course, that raises a question: if you're going to use the object's REF do you need the ID column? Certainly I think it is misleading to have a attribute called CID of type NUMBER for the CHILD_T type and an attribute with the same name but a datatype of REF for the SCHOOL_CHILD_T type.