Control constraints of a nested table of references in oracle - 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.

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.

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

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

ORA-22816 while updating Joined View with Instead of trigger

I read a lot about it but didn't found any help on that.
My Situation:
I've two database tables which belongs together. This tables I want to query with EntityFramework. Because Table B contains for EntityFramework the discriminator (for choosing the correct class for Table A) I've created a View which Joins Table A and Table B.
This join is quite simple. But: I want also to store data with that View. The issue is, that EntityFramework also wants to store the discriminator. But this isn't possible because it would update/insert into two tables.
So I've tried to create an "Instead of" trigger to just update/insert Table A (because Table B doesn't matter and will never be updated).
When I created the trigger - everything fine. If I insert something with an SQL Statement - everything is fine. But: If I'm inserting directly in the View (using Oracle SQL Developer) it throws the Exception as below:
ORA-22816 (unsupported feature with RETURNING clause).
If I do the same with EntityFramework I get the same error. Can someone help me?
Below my Code:
Table A and Table B:
CREATE Table "TableA"
(
"ID" Number NOT NULL,
"OTHER_VALUESA" varchar2(255),
"TableB_ID" number not null,
CONSTRAINT PK_TableA PRIMARY KEY (ID)
);
CREATE Table "TableB"
(
"ID" Number NOT NULL,
"NAME" varchar2(255),
"DISCRIMINATOR" varchar2(255),
CONSTRAINT PK_TableB PRIMARY KEY (ID)
);
The Joined View:
Create or Replace View "JoinTableAandB"
(
"ID",
"OTHER_VALUESA",
"TableB_ID",
"DISCRIMINATOR"
) AS
select tableA.ID, tableA.OTHER_VALUESA, tableA.TableB_ID, tableB.DISCRIMINATOR
from TABLEA tableA
inner join TABLEB tableB on tableA.TableB_ID = tableB.ID;
And finally the Trigger:
create or replace TRIGGER "JoinTableAandB_TRG"
INSTEAD OF INSERT ON "JoinTableAandB"
FOR EACH ROW
BEGIN
insert into TABLEA(OTHER_VALUESA, TABLEB_ID)
values (:NEW.OTHER_VALUESA, :NEW.TABLEB_ID);
END;
I've also tried it (to verify if the insert is correct just to enter "NULL" into the trigger instead of insert. But got the same error message.
Does anybody know how to solve this? Or does anybody have a good alternative (better Idea)?
Thanks!
Note: I've also defined a sequence for TableA's ID so that it will be generated automatically.
// Edit:
I found a possible Solution for MS SQL:
https://stackoverflow.com/a/26897952/3598980
But I don't know how to translate this to Oracle... How can I return something from a trigger?
Note: I've also defined a sequence for TableA's ID so that it will be generated automatically.
In EF StoreGenerated keys in Oracle are incompatible with INSTEAD OF triggers. EF uses a RETURNING clause to output the store generated keys, which doesn't work with INSTEAD OF triggers.

how to create foreign key at runtime using Triggers and/or procedures in Oracle environment

I have two tables named as patient and pharmacy. Each patient is uniquely associated with one pharmacy. I want to create the foreign key constraint at run-time between these tables.
Create table patient
(patient_Id varchar2(5) primary key,
patient_name varchar2(20));
Create table pharmacy
(pharmacy_Id varchar2(5) primary key,
pharmacy_name varchar2(20);
Create table patient_pharmacy_mapper
(patient_Id varchar2(5) references patient(patient_Id),
pharmacy_Id varchar2(5) references pharmacy(pharmacy_Id));
Instead of writing the "references" at design time, Can I create/delete these foreign key constraints at run-time (when any DML statement fires)?
I know little about creating a trigger where we have to call a procedure with the "Alter table statement".
DDL statements automatically commit the transaction. As you are not allowed to commit (or rollback) in a trigger, you can not run DDL statements in a trigger (neither with static SQL nor with dynamic SQL)
The whole idea does not make sense. The only sane way to do this, is to create the FK constraints when creating the tables. You gain no security from delaying this, absolutely none.
Let me just add another vote to the others about this being a Very Bad Idea (tm). FK relationships enforce fundamental business rules. They are part of the design, to be implemented when at the same time tables are created. Any time (and I emphasize ANY time) you find yourself wanting to execute DDL at run time, you need to step back, get a cup of coffee, and reconsider.
Like the other statements I also say it is a very bad idea.
Consider, you can enable/disable constraints or you can set them deferred: SET CONSTRAINT[S]
Perhaps this is a solution for you problem.

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.

Resources