How to create a nested table of refs in Oracle SQL? - oracle

Consider the following problem:
There's the Transaction type and the Service type. Each transaction covers one or more services at a time. However, two different transactions may cover same services.
Now, it's pretty easy to consolidate this using relational database design. You'd have a table for transactions transaction id, and then some data fields, a table for services service id, some data fields and a third table that links transaction id's to service id's. This way, the service data is not duplicated and if you ever needed to, say, retrieve all services implicated in a transaction, you just do two joins transactions join third_table join service.
As far as I understand, ref simply stores the id of the record (object) it's pointing to and implicitly does a join upon deref(). So, say, if any of the transactions had to cover just one of the services, I could use a ref to the service object instead of the service id + an explicit join.
A nested table, as far as I understand, is just a private table that links the id of one object to a whole another object and that is shared among all objects of the type that declared the nested table. This concept also uses joins under the hood, if I'm not being horribly wrong. So if the services were unique among all transactions, I could in principle just use a nested table of services inside the transaction.
However, the problem is that there could be more than one service for every transaction and they could repeat. So the object-oriented solution, in my mind, is a nested table of ref to service inside of the transaction. However, I'm not able to find any clues on the Internet for the syntax for this idea and whether it is at all possible to do this.
Here's Oracle SQL sort of pseudocode (it doesn't work) of what I'm aiming for:
create type Service_Type as object(
id number(5),
-- some other data --
cost number(4),
name varchar2(32),
description varchar2(32)
---------------------
);
/
create table Service_Table of Service_Type (id primary key);
/
create type Service_Reference_Type as ref Service_Type scope is Service_Table;
/
create type Service_Reference_Table_Type as table of Service_Reference_Type;
/
create type Transaction_Type as object(
id number(5),
services Service_Reference_Table_Type,
-- some other data --
name varchar2(32),
description varchar2(32)
---------------------
);
nested table services store as Transaction_Service_Nested_Reference_Table;
/
As a sidenote: I know Object Oriented DBMS is garbage and I'm not planning on using it in any real project. This is for a university assignment (I wonder why they teach this stuff).

I don't think you're too far off, but you don't need Service_Reference_Type, you can create a table of refs in one step:
create type Service_Type as object(
id number(5),
-- some other data --
cost number(4),
name varchar2(32),
description varchar2(32)
---------------------
);
/
create table Service_Table of Service_Type (id primary key);
create type Service_Reference_Table_Type as table of ref Service_Type;
/
create type Transaction_Type as object(
id number(5),
services Service_Reference_Table_Type,
-- some other data --
name varchar2(32),
description varchar2(32)
---------------------
)
/
create table Transaction_Table of Transaction_Type
nested table services store as Transaction_Service_Nested_Reference_Table;
db<>fiddle including inserting and querying the data.
Is there a way one could scope the refs too?
As in the answer #MTO linked to:
alter table Transaction_Service_Nested_Reference_Table
add scope for (column_value) is Service_Table;
db<>fiddle

Related

I've created a nested table. Is it possible to make a query on the table that really memorize the data of the nested table (STUDEN_NT_TAB)

CREATE TYPE STUDENT_T AS OBJECT (
NOME VARCHAR2(30),
COGNOME VARCHAR2(20),
MATRICOLA INT(6));
CREATE TYPE STUDENT_NT IS TABLE OF STUDENT_T;
CREATE TABLE CORSO_DI_LAUREA (
NOME_CORSO VARCHAR2(50),
STUDENTI STUDENT_NT )
NESTED TABLE STUDENTI STORE AS STUDEN_NT_TAB;
Check out https://asktom.oracle.com/pls/apex/asktom.search%3Ftag%3Daccessing-nested-tables-elements.
From that page we can see that your query would be somthing on the order of:
select nome_corso from coroso_id_laurea, table(studenti)
I highly agree with what they say immediately after the example:
"Finally, while you can store multiple values using nested tables, in
the vast majority of cases you're better off using regular tables
instead. This makes it easier to query and work with your data!"
I have done some experimentation with nested tables. For me they became a nightmare of complexity so I switched back to the standard relational model.

Tables showing up with two: 'one to many' relationships in oracle sql developer

I'm looking through our data and there's a handful of tables in our oracle database that show up with two one to many relationships: http://i.stack.imgur.com/icGcV.png
I'm not sure why this would be happening, and is it something I should look into getting changed or fixed?
(I did not create this database, I am only trying to understand it!)
Too long for a comment, let's see a very simple example:
CREATE TABLE persons
(
id NUMBER PRIMARY KEY,
name VARCHAR2(10)
)
/
CREATE TABLE marriages
(
wife NUMBER REFERENCES persons(id),
husband NUMBER REFERENCES persons(id)
)
/
CREATE TABLE dogs
(
id NUMBER PRIMARY KEY,
name VARCHAR2(10),
owner NUMBER REFERENCES persons(id)
)
/
Here you have one table with two different FKs to the same table. At the same time you have another table with a single FK to the same table.
So, it's not a problem to fix, but a part of DB design to understand;
your DB can be well or bad designed, but the existence of such situations does not say anything about that.

Meaning of STORE AS in nested table in PL/SQL

I referred many examples of "Creating a SQL Type Corresponding to a PL/SQL Nested Table" such as
CREATE TYPE CourseList AS TABLE OF VARCHAR2(64);
CREATE TABLE department (
name VARCHAR2(20),
director VARCHAR2(20),
office VARCHAR2(20),
courses CourseList)
NESTED TABLE courses STORE AS courses_tab;
I referred many materials regarding this but I am not getting what is purpose of storing courses into courses_tab. Where will this courses_tab use? Please help me.
courses_tab is used to name the physical table which stores the data for the nested table. You can find it by querying dba_nested_tables. The column table_name will have the value 'COURSES_TAB'. In addition, you can get the structure of the table by issuing the command DESC COURSES_TAB.

Control constraints of a nested table of references in oracle

I'm doing some Object-Relational stuff in oracle. I'm having problems with a nested table of references, in which I cannot control the PK as usual, so I have to create a trigger to control it.
The types are:
CREATE OR REPLACE TYPE Tipo_Persona AS OBJECT (
id number(5),
nombre varchar2(20),
apellidos varchar2(30),
dni varchar2(9),
telefonos ListaTelefonos,
fecha_alta date,
MAP MEMBER FUNCTION getPID RETURN NUMBER
)NOT FINAL;
/
CREATE OR REPLACE TYPE Tipo_HoraActividad AS OBJECT
(
idact NUMBER(3),
Hora_Inicio DATE,
Dia VARCHAR2(10),
Duracion NUMBER(4,2),
...
Monitor REF Tipo_Monitor
);
/
CREATE OR REPLACE TYPE Tipo_Monitor_Horas AS TABLE OF REF Tipo_HoraActividad;
/
CREATE OR REPLACE TYPE Tipo_Monitor UNDER Tipo_Persona
(
Actividades Tipo_Monitor_Horas,
Sueldo_Hora NUMBER(4,2),
MEMBER FUNCTION sueldo return NUMBER,
PRAGMA RESTRICT_REFERENCES (sueldo, WNDS)
);
/
-- Creation of Tables
...
CREATE TABLE Tabla_Monitor OF Tipo_Monitor
(
constraint PK_MONITOR PRIMARY KEY(id),
constraint UNIQUE_DNI_MONITOR UNIQUE(dni),
dni NOT NULL,
fecha_alta NOT NULL,
nombre NOT NULL
)
NESTED TABLE Actividades STORE AS Actividades_Impartidas;
...
So now... my trigger:
CREATE OR REPLACE TRIGGER TRG_name
BEFORE INSERT OR UPDATE ON Actividades_Impartidas
FOR EACH ROW
...
-- I can deref the :new row of Tipo_HoraActividad and check if
-- their values are NULL. But I don't know how to control if
-- it exists any other ref within the current table pointing to
-- the same HoraActividad(unique constraint). My main problem is
-- that I cannot access to this current table (Actividades_Impartidas)
-- because it is a nested table of a concrete row of Tabla_Monitor.
Can anyone help me?
Thanks in advance.
I myself looked for an answer for this a lot but couldn't find it. Visited the URL that Martin Drautzbug provided in that URL and my opinion changed about this question. You should not make things complicated just because you can. That's one of the foremost rules of database design- reduce anomalies for DML statements as much as possible.
It has been my personal experience that using nested tables as a table column just makes things more complicated and difficult to process with simple SQL statements. I read it here and they confirm this. We try to denormalize database design for saving some amount of efforts by using nested tables but it just results into us putting more efforts trying to un-nest them all the time. Plus, it is difficult to enforce constraints on these nested tables.
One good solution would be to use separate tables instead of the nested tables and normalize as much as you can. If you are designing a real transactional database and going to do a lot of DML you should always escape the un-nesting of tables all the time.
Nested tables is a great option in PL/SQL where you have to bulk collect results from a query temporarily in a collection and process it. It is not the same with creating tables with nested table columns.
I am posting this URL again here for you to visit for more details.

How to Create a Foreign Key from a Table to a Custom Datatype

Working with Oracle Express 11g, learning the interactions for object-relational databases.
Running into trouble while trying to create a foreign key from a normal table, to a table of a custom object (customers)
The customer object is as follows (customer_id NUMBER, fname VARCHAR2, lname VARCHAR2), for our setup, we wish to join a table Applications via customer_id NUMBER. Within the SQL Workshop, selecting the customers table is not even an option, and we cannot find syntax to manually create this relationship.
Any experts have some clues to help figure this one out?
create or replace type customer is object
(
customer_id NUMBER,
fname VARCHAR2(100),
lname VARCHAR2(100)
);
/
create table customers of customer
(
constraint customer_pk primary key(customer_id)
);
create table applications
(
application_id number,
customer_id number,
constraint applications_fk1 foreign key (customer_id)
references customers(customer_id)
);

Resources