Cos'è la chiave esterna
La chiave esterna in Oracle è un modo per mettere in relazione più tabelle. È un collegamento incrociato tra le tabelle.
- Una chiave esterna è una colonna o un insieme di colonne che fa riferimento alla chiave primaria o alla chiave univoca nella stessa tabella o in un'altra tabella
- I valori delle chiavi esterne si basano sui valori dei dati e sono costrutti puramente logici, non puntatori fisici
- Il valore della chiave esterna deve corrispondere a un valore di chiave primaria o un valore di chiave univoco oppure è nullo.
I vincoli di chiave esterna sono chiamati vincoli di integrità referenziale. La tabella di riferimento è chiamata tabella padre mentre la tabella con la chiave esterna è chiamata tabella figlio.
come usare la chiave esterna
Verifichiamo con l'esempio di EMP e DEPT.
SQL>CREATE TABLE "DEPT" ( "DEPTNO" NUMBER(2,0), "DNAME" VARCHAR2(14), "LOC" VARCHAR2(13), CONSTRAINT "PK_DEPT" PRIMARY KEY ("DEPTNO") ) SQL>CREATE TABLE "EMP" ( "EMPNO" NUMBER(4,0), "ENAME" VARCHAR2(10), "JOB" VARCHAR2(9), "MGR" NUMBER(4,0), "HIREDATE" DATE, "SAL" NUMBER(7,2), "COMM" NUMBER(7,2), "DEPTNO" NUMBER(2,0), CONSTRAINT "PK_EMP" PRIMARY KEY ("EMPNO") ); SQL> desc emp Name Null? Type EMPNO NOT NULL NUMBER(4) ENAME VARCHAR2(10) JOB VARCHAR2(9) MGR NUMBER(4) HIREDATE DATE SAL NUMBER(7,2) COMM NUMBER(7,2) DEPTNO NUMBER(2) SQL> SQL> desc dept Name Null? Type DEPTNO NOT NULL NUMBER(2) DNAME VARCHAR2(14) LOC VARCHAR2(13) SQL> insert into DEPT values(10, 'ACCOUNTING', 'NEW YORK'); insert into dept values(20, 'RESEARCH', 'DALLAS'); insert into dept values(30, 'RESEARCH', 'DELHI'); insert into dept values(40, 'RESEARCH', 'MUMBAI'); insert into emp values( 7698, 'Blake', 'MANAGER', 7839, to_date('1-5-2007','dd-mm-yyyy'), 2850, null, 10 ); insert into emp values( 7782, 'Clark', 'MANAGER', 7839, to_date('9-6-2008','dd-mm-yyyy'), 2450, null, 10 ); insert into emp values( 7788, 'Scott', 'ANALYST', 7566, to_date('9-6-2012','dd-mm-yyyy'), 3000, null, 20 ); insert into emp values( 7789, 'TPM', 'ANALYST', 7566, to_date('9-6-2017','dd-mm-yyyy'), 3000, null, null ); insert into emp values( 7560, 'T1OM', 'ANALYST', 7567, to_date('9-7-2017','dd-mm-yyyy'), 4000, null, 20 ); insert into emp values( 7790, 'TOM', 'ANALYST', 7567, to_date('9-7-2017','dd-mm-yyyy'), 4000, null, null ); SQL> select from emp; EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO 7698 BLAKE MANAGER 7839 01-MAY-07 2850 10 7782 CLARK MANAGER 7839 09-JUN-08 2450 10 7788 SCOTT ANALYST 7566 09-JUN-12 3000 20 7789 TPM ANALYST 7566 09-JUN-17 3000 7790 TOM ANALYST 7567 09-JUL-17 4000 7560 T1OM ANALYST 7567 09-JUL-17 4000 20
La tabella EMP contiene la colonna DEPT_NO. e DEPT Table contiene anche la colonna DEPT_NO ed è la chiave primaria della tabella.
Ora non vogliamo voci nella tabella EMP in cui DEPT_NO non corrisponde a DEPT_NO nella colonna DEPT poiché non possiamo avere un emp il cui numero di reparto non esiste. Vediamo se riusciamo a farlo con la configurazione corrente
SQL> insert into emp values( 7790, 'TOM', 'ANALYST', 7567, to_date('9-7-2017','dd-mm-yyyy'), 4000, null, 50); 1 row created.
Ma questo è riuscito e la struttura ha causato un problema di integrità dei dati
Per evitare questo tipo di problemi con i dati, possiamo applicare i vincoli della chiave esterna alla tabella EMP.
Ci rivediamo
drop table emp; drop table dept; SQL>CREATE TABLE "DEPT" ( "DEPTNO" NUMBER(2,0), "DNAME" VARCHAR2(14), "LOC" VARCHAR2(13), CONSTRAINT "PK_DEPT" PRIMARY KEY ("DEPTNO") ) SQL>CREATE TABLE "EMP" ( "EMPNO" NUMBER(4,0), "ENAME" VARCHAR2(10), "JOB" VARCHAR2(9), "MGR" NUMBER(4,0), "HIREDATE" DATE, "SAL" NUMBER(7,2), "COMM" NUMBER(7,2), "DEPTNO" NUMBER(2,0), CONSTRAINT "PK_EMP" PRIMARY KEY ("EMPNO"), CONSTRAINT "FK_DEPTNO" FOREIGN KEY ("DEPTNO") REFERENCES "DEPT" ("DEPTNO") ENABLE ); SQL> desc emp Name Null? Type EMPNO NOT NULL NUMBER(4) ENAME VARCHAR2(10) JOB VARCHAR2(9) MGR NUMBER(4) HIREDATE DATE SAL NUMBER(7,2) COMM NUMBER(7,2) DEPTNO NUMBER(2) SQL> SQL> desc dept Name Null? Type DEPTNO NOT NULL NUMBER(2) DNAME VARCHAR2(14) LOC VARCHAR2(13) SQL> insert into DEPT values(10, 'ACCOUNTING', 'NEW YORK'); insert into dept values(20, 'RESEARCH', 'DALLAS'); insert into dept values(30, 'RESEARCH', 'DELHI'); insert into dept values(40, 'RESEARCH', 'MUMBAI'); insert into emp values( 7698, 'Blake', 'MANAGER', 7839, to_date('1-5-2007','dd-mm-yyyy'), 2850, null, 10 ); insert into emp values( 7782, 'Clark', 'MANAGER', 7839, to_date('9-6-2008','dd-mm-yyyy'), 2450, null, 10 ); insert into emp values( 7788, 'Scott', 'ANALYST', 7566, to_date('9-6-2012','dd-mm-yyyy'), 3000, null, 20 ); insert into emp values( 7789, 'TPM', 'ANALYST', 7566, to_date('9-6-2017','dd-mm-yyyy'), 3000, null, null ); insert into emp values( 7560, 'T1OM', 'ANALYST', 7567, to_date('9-7-2017','dd-mm-yyyy'), 4000, null, 20 ); insert into emp values( 7790, 'TOM', 'ANALYST', 7567, to_date('9-7-2017','dd-mm-yyyy'), 4000, null, null );
Ora proviamo a inserire la stessa riga
SQL> insert into emp values( 7790, 'TOM', 'ANALYST', 7567, to_date('9-7-2017','dd-mm-yyyy'), 4000, null, 50); insert into emp values( 7790, 'TOM', 'ANALYST', 7567, to_date('9-7-2017','dd-mm-yyyy'), 4000, null, 50) * ERROR at line 1: ORA-02291: integrity constraint (SCOTT.FK_DEPTNO) violated - parent key not found
Quindi ha evitato le voci dei dati errati.
Lo stesso è lo scenario con Elimina dalla tabella DEPT. Non dovremmo eliminare le righe del reparto in cui emp ha alcuni record. Senza vincoli di chiave esterna, accadrà e causerà dati errati. Ma con la chiave esterna, questo sarà evitato
SQL> delete from dept where deptno=10; delete from dept where deptno=10 * ERROR at line 1: ORA-02292: integrity constraint (SCOTT.FK_DEPTNO) violated - child record found
Clausole chiave esterne sull'opzione di eliminazione
CONSTRAINT "FK_DEPTNO" FOREIGN KEY ("DEPTNO") REFERENCES "DEPT" ("DEPTNO") ENABLE ON DELETE [CASCADE |SET NULL]
Caso 1: Chiave esterna definita senza l'opzione ON DELETE
Non sarai in grado di eliminare i record dalla tabella padre se i record vengono trovati nella tabella figlio
Caso -2 Chiave esterna definita con l'opzione ON DELETE SET NULL
Vediamo come funziona
SQL> alter table emp add CONSTRAINT "FK_DEPTNO" FOREIGN KEY ("DEPTNO") REFERENCES "DEPT" ("DEPTNO") ON DELETE SET NULL; Table altered. SQL> select * from emp where empno=7698; EMPNO DEPTNO ------- ---- 7698 10 SQL> delete from dept where deptno=10; 1 row deleted. SQL> commit; Commit complete. SQL> select * from emp where empno=7698; EMPNO DEPTNO ------- ---- 7698
Quindi, eliminando le righe dalla tabella padre, la colonna della chiave esterna delle righe figlio viene resa nulla
Caso -3 Chiave esterna definita con l'opzione ON DELETE CASCADE
SQL> alter table emp add CONSTRAINT "FK_DEPTNO" FOREIGN KEY ("DEPTNO") REFERENCES "DEPT" ("DEPTNO") ON DELETE cascade; Table altered. SQL> delete from dept where deptno=10; 1 row deleted. SQL> commit; Commit complete. SQL> select * from emp where deptno=10; ; no rows selected SQL>
Quindi, eliminando le righe dalla tabella padre, vengono eliminate anche le righe figlio
Alterare la chiave esterna della tabella
Possiamo creare una chiave esterna in Oracle anche dopo la creazione della tabella
alter table emp add CONSTRAINT "FK_DEPTNO" FOREIGN KEY ("DEPTNO") REFERENCES "DEPT" ("DEPTNO") ;
Come eliminare il vincolo di chiave esterna
SQL> alter table emp drop constraint "FK_DEPTNO"; Table altered.
Come disabilitare il vincolo
SQL> alter table emp disable constraint "FK_DEPTNO"; Table altered.
Come abilitare il vincolo
SQL> alter table emp enable constraint "FK_DEPTNO"; Table altered. SQL>
Legge anche
Verifica vincolo in Oracle
vincolo Not Null in Oracle
Come aggiungere la chiave primaria in Oracle:la chiave primaria identifica in modo univoco la riga nella tabella. Come aggiungere la chiave primaria in Oracle, come eliminare la chiave primaria, come creare una chiave composita
rilascia il vincolo della chiave esterna oracle
Chiave univoca in Oracle:la chiave univoca impone l'univocità nella colonna della tabella e aiuta identifichiamo rapidamente la riga. Oracle crea l'indice univoco per la chiave se non è disponibile alcun indice
elimina la query in Oracle
https://en.wikipedia.org/wiki/Foreign_key