Buitenlandse sleutelkolommen/beperkingen ondubbelzinnig maken
Ervan uitgaande dat u verwijst naar de externe sleutelbeperkingen , zou het korte antwoord zijn:je gebruikt ze gewoon niet .
En hier komt de lange:
We zijn gewend om te verwijzen naar kolommen als externe sleutels naar andere tafels. Vooral tijdens het normalisatieproces kunnen zinnen als "user_purchase.i_id
is een externe sleutel voor de items
tafel" zou heel gebruikelijk zijn. Hoewel dat een perfect geldige manier is om de relatie te beschrijven, kan het een beetje vaag worden wanneer we de implementatiefase bereiken.
Stel dat u uw tabellen zonder . heeft gemaakt de FOREIGN KEY
clausules:
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,
);
Merk op dat de externe sleutel kolommen zijn nog steeds geïmplementeerd . Er is een kolom die verwijst naar de user
tabel (id
) en een andere die verwijst naar de items
tabel (i_id
) -- laten we de name
kolom even opzij. Houd rekening met de volgende gegevens:
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 |
De relatie is er. Het wordt geïmplementeerd door middel van de user_purchase
tabel, die informatie bevat over wie wat heeft gekocht . Als we de database zouden opvragen voor een relevant rapport, zouden we het volgende doen:
select * from user_purchase p
join user u on (p.id=u.id)
join items i on (p.i_id=i.i_id)
En zo gebruiken we de relatie en de refererende sleutel kolommen betrokken.
Wat als we nu doen:
insert into user_purchase (id,i_id) values (23,99)
Blijkbaar is dit een ongeldige invoer. Hoewel er een gebruiker is met id=23
, er is geen item met i_id=99
. Het RDBMS zou dat mogelijk maken, omdat het niet beter weet . Nog.
Dat is waar beperkingen voor buitenlandse sleutels in het spel komen. Door FOREIGN KEY (i_id) REFERENCES items(i_id)
op te geven in de user_purchase
tabeldefinitie, geven we het RDBMS in wezen een regel die moet worden gevolgd:invoeren met i_id
waarden die niet zijn opgenomen in de items.i_id
kolom zijn niet acceptabel . Met andere woorden, terwijl een externe sleutel kolom implementeert de referentie , een beperking . met een externe sleutel handhaaft de referentiële integriteit .
Merk echter op dat de bovenstaande select
niet zou veranderen, alleen omdat je een FK-beperking definieerde. Dus, jij gebruik geen FK-beperkingen, het RDBMS wel, om uw gegevens te beschermen.
Ontslagen
Stel jezelf de vraag:waarom zou je dat willen? Als de twee externe sleutels hetzelfde doel dienen, zal de redundantie u uiteindelijk in de problemen brengen. Houd rekening met de volgende gegevens:
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 |
Wat is er mis met deze foto? Heeft gebruiker 55
twee chocoladerepen kopen, of een chocoladereep en een tandpasta? Dit soort ambiguïteit kan leiden tot veel moeite om gegevens synchroon te houden, wat niet nodig zou zijn als we slechts een van de externe sleutels zouden behouden. In feite, waarom laat je de name
niet vallen? kolom helemaal, omdat het wordt geïmpliceerd door de relatie.
We kunnen dit natuurlijk oplossen door een samengestelde externe sleutel te implementeren, door PRIMARY KEY(i_id,name)
in te stellen voor de items
tabel (of het definiëren van een extra UNIQUE(i_id,name)
index, het maakt niet echt uit) en stel vervolgens een FOREIGN KEY(i_id,name) REFERENCES items(i_id,name)
in . Op deze manier zijn alleen (i_id,name) koppels die voorkomen in de items
tabel zou geldig zijn voor user_purchases
. Afgezien van het feit dat je nog steeds één . zou hebben buitenlandse sleutel , is deze aanpak totaal overbodig, op voorwaarde dat de i_id
kolom is al voldoende om een item te identificeren (kan niet hetzelfde zeggen voor de name
kolom...).
Er is echter geen regel tegen het gebruik van meerdere externe sleutels voor een tabel. In feite zijn er omstandigheden die een dergelijke benadering vereisen. Overweeg een person(id,name)
tafel en een parent(person,father,mother)
één, met de volgende gegevens:
person parent
| id name | | person father mother |
| 14 John | | 21 14 59 |
| 43 Jane | | 14 76 43 |
| 21 Mike |
| 76 Frank |
| 59 Mary |
Het is duidelijk dat alle drie de kolommen van de parent
tabel zijn externe sleutels naar person
. Niet voor dezelfde relatie , hoewel, maar voor drie verschillende :Aangezien de ouders van een persoon ook personen zijn, moeten de twee corresponderende kolommen verwijzen naar dezelfde tabel person
doet. Merk echter op dat de drie velden niet alleen kunnen maar ook moeten verwijs andere person
s in dezelfde parent
rij, aangezien niemand zijn eigen ouder is en niemands vader ook zijn moeder is.