Disambiguazione vincoli/colonne chiave esterna
Supponendo che tu ti riferisca ai vincoli della chiave esterna , la risposta breve sarebbe semplicemente non li usi .
Ed ecco che arriva quello lungo:
Siamo abituati a fare riferimento a le colonne sono chiavi esterne ad altri tavoli. Soprattutto durante il processo di normalizzazione, frasi come "user_purchase.i_id
è una chiave esterna per gli items
tabella" sarebbe molto comune. Anche se questo è un modo perfettamente valido per descrivere la relazione, può diventare un po' confuso quando raggiungiamo la fase di implementazione.
Supponi di aver creato le tue tabelle senza la FOREIGN KEY
clausole:
CREATE TABLE user(
id INT(11) NOT NULL AUTO_INCREMENT,
username VARCHAR(50) NOT NULL,
password VARCHAR(20) NOT NULL,
PRIMARY KEY (id)
);
CREATE TABLE items(
i_id INT(11) NOT NULL AUTO_INCREMENT,
name TINYTEXT NOT NULL,
price DECIMAL(8,2) NOT NULL,
PRIMARY KEY (i_id)
);
CREATE TABLE user_purchase(
i_id INT(11) NOT NULL,
name TINYTEXT NOT NULL,
id INT(11) NOT NULL,
);
Si noti che, dal punto di vista delle relazioni, la chiave esterna colonne sono ancora implementati . C'è una colonna che fa riferimento all'user
tabella (id
) e un altro che fa riferimento agli items
tabella (i_id
) -- mettiamo il name
colonna a parte per un momento. Considera i seguenti dati:
user user_purchase items
| id username | | id i_id | | i_id name price |
| 23 john | | 55 10 | | 10 chocolate bar 3.42 |
| 55 mary | | 70 10 | | 33 mobile phone 82.11 |
| 70 fred | | 70 33 | | 54 toothpaste 8.67 |
| 55 10 | | 26 toy car 6.00 |
| 70 26 |
La relazione c'è. È implementato tramite user_purchase
tabella, che contiene informazioni su chi ha acquistato cosa . Se dovessimo interrogare il database per un rapporto pertinente, faremmo:
select * from user_purchase p
join user u on (p.id=u.id)
join items i on (p.i_id=i.i_id)
Ed è così che usiamo la relazione e la chiave esterna colonne coinvolti.
E se lo facessimo:
insert into user_purchase (id,i_id) values (23,99)
Apparentemente, questa è una voce non valida. Sebbene sia presente un utente con id=23
, non ci sono articoli con i_id=99
. L'RDBMS permetterebbe che ciò avvenga, perché non sa di meglio . Ancora.
Ecco dove i vincoli della chiave esterna entrare in gioco. Specificando FOREIGN KEY (i_id) REFERENCES items(i_id)
nel user_purchase
definizione della tabella, diamo essenzialmente all'RDBMS una regola da seguire:voci con i_id
valori che non sono contenuti in items.i_id
colonna non sono accettabili . In altre parole, mentre è una chiave esterna colonna implementa il riferimento , una chiave esterna vincolo applica l'integrità referenziale .
Nota, tuttavia, che quanto sopra select
non cambierebbe, solo perché hai definito un vincolo FK. Pertanto, tu non utilizzare vincoli FK, lo fa RDBMS, per proteggere i tuoi dati.
Esuberi
Chiediti:perché lo vorresti? Se le due chiavi esterne devono servire allo stesso scopo, la ridondanza alla fine ti metterà nei guai. Considera i seguenti dati:
user_purchase items
| id i_id name | | i_id name price |
| 55 10 chocolate bar | | 10 chocolate bar 3.42 |
| 70 10 chocolate bar | | 33 mobile phone 82.11 |
| 70 33 mobile phone | | 54 toothpaste 8.67 |
| 55 10 toothpaste | | 26 toy car 6.00 |
| 70 26 toy car |
Cosa c'è di sbagliato in questa immagine? Ha fatto l'utente 55
comprare due barrette di cioccolato o una barretta di cioccolato e un dentifricio? Questo tipo di ambiguità può comportare molti sforzi per mantenere i dati sincronizzati, il che non sarebbe necessario se mantenessimo solo una delle chiavi esterne. Infatti, perché non eliminare il name
colonna del tutto, poiché è implicita nella relazione.
Ovviamente, potremmo risolverlo implementando una chiave esterna composita, impostando PRIMARY KEY(i_id,name)
per gli items
tabella (o definendo un extra UNIQUE(i_id,name)
index, non importa) e poi impostando un FOREIGN KEY(i_id,name) REFERENCES items(i_id,name)
. In questo modo, solo le coppie (i_id,name) che esistono negli items
la tabella sarebbe valida per user_purchases
. A parte il fatto che ne avresti ancora uno chiave esterna , questo approccio è del tutto superfluo, a condizione che i_id
la colonna è già sufficiente per identificare un elemento (non posso dire lo stesso per il name
colonna...).
Tuttavia, non esiste una regola contro l'utilizzo di più chiavi esterne in una tabella. In effetti, ci sono circostanze che richiedono un tale approccio. Considera una person(id,name)
tabella e un parent(person,father,mother)
uno, con i seguenti dati:
person parent
| id name | | person father mother |
| 14 John | | 21 14 59 |
| 43 Jane | | 14 76 43 |
| 21 Mike |
| 76 Frank |
| 59 Mary |
Ovviamente, tutte e tre le colonne del parent
table sono chiavi esterne per person
. Non per la stessa relazione , però, ma per tre diversi :Poiché anche i genitori di una persona sono persone, le due colonne corrispondenti devono fare riferimento alla stessa tabella person
fa. Nota, tuttavia, che i tre campi non solo possono ma anche devono fare riferimento a person
diverse s nello stesso parent
fila, dal momento che nessuno è il suo stesso genitore e il padre di nessuno è anche sua madre.