Zjednodušení sloupců/omezení cizího klíče
Za předpokladu, že máte na mysli omezení cizího klíče , stručná odpověď by byla prostě je nepoužíváte .
A tady přichází ten dlouhý:
Jsme zvyklí označovat sloupce za cizí klíče na další stoly. Zejména během procesu normalizace se fráze jako "user_purchase.i_id
je cizí klíč k items
tabulka" by bylo velmi časté. I když je to dokonale platný způsob, jak popsat vztah, může to být trochu nejasné, když se dostaneme do fáze implementace.
Předpokládejme, že jste své tabulky vytvořili bez FOREIGN KEY
klauzule:
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,
);
Všimněte si, že ve vztahu k cizímu klíči sloupce jsou stále implementovány . Je tam sloupec, který odkazuje na user
tabulka (id
) a další, který odkazuje na items
tabulka (i_id
) -- dodejme name
sloup na chvíli stranou. Zvažte následující údaje:
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 |
Vztah tam je. Je implementován pomocí user_purchase
tabulka, která obsahuje informace o tom, kdo co koupil . Pokud bychom v databázi požádali o relevantní zprávu, udělali bychom:
select * from user_purchase p
join user u on (p.id=u.id)
join items i on (p.i_id=i.i_id)
A tak používáme vztah a sloupce cizího klíče zapojeni.
A teď, co když uděláme:
insert into user_purchase (id,i_id) values (23,99)
Zdá se, že se jedná o neplatný záznam. Ačkoli existuje uživatel s id=23
, není zde žádná položka s i_id=99
. RDBMS by to umožnil, protože nezná nic lepšího . Dosud.
To je místo, kde cizí klíč omezuje Pojď do hry. Zadáním položky FOREIGN KEY (i_id) REFERENCES items(i_id)
v user_purchase
definice tabulky, v podstatě dáváme RDBMS pravidlo, které se má dodržovat:položky s i_id
hodnoty, které nejsou obsaženy v items.i_id
sloupec nejsou přijatelné . Jinými slovy, zatímco cizí klíč sloupec implementuje odkaz , omezení cizího klíče vynucuje referenční integritu .
Pamatujte však, že výše uvedený select
by se nezměnilo jen proto, že jste definovali omezení FK. Tedy vy nepoužívejte omezení FK, to dělá RDBMS, abyste ochránili svá data.
Propouštění
Zeptejte se sami sebe:Proč byste to chtěli? Pokud mají dva cizí klíče sloužit stejnému účelu, redundance vás nakonec dostane do problémů. Zvažte následující údaje:
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 |
Co je na tomto obrázku špatného? Udělal uživatel 55
koupit dvě čokoládové tyčinky, nebo čokoládovou tyčinku a zubní pastu? Tento druh nejednoznačnosti může vést k velkému úsilí udržovat data v synchronizaci, což by bylo zbytečné, pokud bychom si ponechali pouze jeden z cizích klíčů. Vlastně proč nevypustit name
sloupec úplně, protože je implikován vztahem.
Samozřejmě bychom to mohli vyřešit implementací složeného cizího klíče nastavením PRIMARY KEY(i_id,name)
pro items
tabulka (nebo definování extra UNIQUE(i_id,name)
index, na tom opravdu nezáleží) a poté nastavením FOREIGN KEY(i_id,name) REFERENCES items(i_id,name)
. Tímto způsobem pouze (i_id,name) páry, které existují v items
tabulka bude platná pro user_purchases
. Nehledě na to, že by jste ještě měli jednu cizí klíč , je tento přístup zcela zbytečný za předpokladu, že i_id
sloupec je již dostatečný k identifikaci položky (nelze říci totéž pro name
sloupec...).
Neexistuje však žádné pravidlo proti použití více cizích klíčů v tabulce. Ve skutečnosti existují okolnosti, které takový přístup vyžadují. Zvažte person(id,name)
stůl a parent(person,father,mother)
jedna s následujícími údaji:
person parent
| id name | | person father mother |
| 14 John | | 21 14 59 |
| 43 Jane | | 14 76 43 |
| 21 Mike |
| 76 Frank |
| 59 Mary |
Je zřejmé, že všechny tři sloupce parent
tabulka jsou cizí klíče pro person
. Ne pro stejný vztah , ale pro tři různé :Protože rodiče osoby jsou také osoby, dva odpovídající sloupce musí odkazovat na stejnou tabulku person
dělá. Upozorňujeme však, že tato tři pole nejen umí ale také musíte odkazovat na jinou person
s ve stejném parent
řádek, protože nikdo není jeho vlastním rodičem a nikoho otce není jeho matka.