Cizí klíče jsou nedílnou součástí vytváření vztahu v relačních databázích. Zde je důvod a jak je vytvořit.
Takže jsme zjistili, že primární klíč poskytuje jedinečný identifikátor pro tabulku. Primární klíče však nejsou jediným typem „klíče“. Naše databáze může obsahovat i cizí klíče.
Co je cizí klíč?
cizí klíč je sloupec (nebo kolekce sloupců) v jedné tabulce, který jednoznačně identifikuje řádek jiné tabulky. Toto definuje vztah mezi dvěma tabulkami.
Cizí klíč umožňuje křížové odkazy na související data napříč tabulkami. To se hodí, když sloupec obsahuje data, která jsou reprezentována v jiné tabulce.
Příklad
Zde je schéma našeho FruitShopu databáze zobrazující vztah mezi Ovoce tabulka a Jednotky stůl.
Černá čára, která spojuje dvě tabulky, označuje cizí klíč. UnitId v poli Ovoce tabulka je cizí klíč k UnitId v poli Jednotky stůl. Tedy hodnotu, kterou vložíme do Fruit.UnitId musí odpovídat hodnotě v Units.UnitId . To aktivuje Fruit.UnitId odkazovat na data v ostatních sloupcích daného záznamu (tj. záznam, který má odpovídající UnitId ).
Data
Pokud tedy naše Ovoce tabulka obsahuje záznam, jako je tento:
FruitId | Název ovoce | Inventář | UnitId | DateEntered | Datum aktualizováno |
---|---|---|---|---|---|
1 | Apple | 10 | 3 | 27. 11. 2012 12:42:10 | 27. 11. 2012 12:42:10 |
A naše Jednotky tabulka obsahuje následující záznamy:
UnitId | UnitName | DateEntered | Datum aktualizováno |
---|---|---|---|
1 | Kus | 2011-12-30 12:46:15 | 2011-12-30 12:46:15 |
2 | Skupina | 2011-12-30 12:46:15 | 2011-12-30 12:46:15 |
3 | Kilogram | 2011-12-30 12:46:15 | 2011-12-30 12:46:15 |
4 | Kontejner | 2011-12-30 12:46:15 | 2011-12-30 12:46:15 |
5 | Libra | 2011-12-30 12:46:15 | 2011-12-30 12:46:15 |
6 | Unce | 2011-12-30 12:46:15 | 2011-12-30 12:46:15 |
Můžete vidět, že
Fruit.UnitId
pole obsahuje 3
. Nyní se podívejte na
Jednotky
tabulka pro záznam, který obsahuje 3
v
UnitId
pole. Můžete vidět, že tento záznam představuje
Kilogram
. Proto nyní víme, že jablka se měří v kilogramech.
Dobrá věc na nastavení databáze tímto způsobem je, že nemusíme opakovat "Kilogramy" pro každý záznam, který používá tuto jednotku. Omezení duplikace je klíčovou výhodou systémů pro správu relačních databází.
Zobrazení co největšího počtu záznamů v Ovoce tabulka bude sdílet stejný název jednotky (např. "Kilogramy", "Kontejner", "Bunch" atd.), měli bychom si před přidáním duplikátů do naší databáze dobře rozmyslet. Bez použití vztahu cizího klíče bychom mohli jednoduše napsat názvy jednotek přímo do Ovoce tabulky (a případně nazvat sloupec "Unit", "UnitType" nebo "UnitName"). Pak bychom skončili s mnoha záznamy sdílejícími stejnou hodnotu pro sloupec názvu jednotky. Viděli bychom "Kilogram" opakující se znovu a znovu proti mnoha záznamům. Také bychom viděli opakování „Bunch“ a jakýkoli jiný oblíbený typ jednotky.
I když to nemusí být nutně „špatné“, je obecně efektivnější uložit jeden záznam pro každý z těchto názvů jednotek do samostatné tabulky a poté na tuto tabulku odkazovat pomocí UnitId sloupec. Je to efektivnější než opakování těchto názvů jednotek znovu a znovu pro každý záznam vytvořený v Fruits stůl. Usnadní to také, pokud se někdy rozhodneme aktualizovat název jednotky (například změnit „Kilogramy“ na „Kila“). Pokud aktualizujeme název jednotky, neovlivní to Ovoce tabulka, protože UnitId zůstane stejný. Navíc to také pomáhá předcházet tomu, aby se v naší databázi objevovala nekonzistentní data.
Omezení cizího klíče
Omezení cizího klíče je databázový objekt, který pomáhá udržovat data cizího klíče konzistentní. Chcete-li zachovat referenční integritu, vytvoříte omezení cizího klíče. Vytvořením omezení cizího klíče říkáte MySQL, aby prosazovala určitá pravidla nad daty. Když jsou data vložena, odstraněna nebo aktualizována, MySQL zkontroluje, zda se drží cizího klíče, který jste vytvořili mezi tabulkami. Pokud ne, zabrání to zápisu/přepsání/vymazání dat, čímž se zachová referenční integrita.
Pokud se například uživatel pokusí zadat hodnotu UnitId do Fruit.UnitId ale v Units.UnitId není žádný odpovídající záznam sloupec, pak MySQL zabrání uživateli zadat tuto hodnotu.
Když jsme vytvořili naše dvě tabulky, přidali jsme do Ovoce omezení cizího klíče stůl. Zde je kód, který jsme použili k vytvoření omezení:
CONSTRAINT fkFruitUnits FOREIGN KEY (UnitId) REFERENCES Units (UnitId) ON DELETE RESTRICT ON UPDATE CASCADE
Když rozbalíte uzly v levém SCHÉMA můžete vidět cizí klíč, který jsme vytvořili (a také primární klíče):
Pokud se pokusíte vložit data, která neodpovídají omezení cizího klíče, měla by se zobrazit chyba.
Pokud se například pokusím vložit záznam do Ovoce tabulky pomocí UnitId hodnota, která neexistuje v Jednotkách tabulky, zobrazí se mi následující chyba:
K tomu dochází, protože se snažím vložit hodnotu 5
do
UnitId
pokud v
Units.UnitId
není žádná odpovídající hodnota pole.
Aby to uspělo, musel bych zajistit, aby byl záznam v
Units
tabulka s
UnitId
z 5
.
Cizí klíč nefunguje?
Občas se můžete setkat se situací, kdy se zdá, že cizí klíč nefunguje. Můžete například úspěšně vložit data do tabulky, i když existuje cizí klíč, který by měl zabránit vložení těchto dat.
V této situaci můžete zkontrolovat několik věcí.
- Ujistěte se, že jste přidali
ON DELETE
aON UPDATE
klauzule ve vašem kódu. NapříkladON DELETE RESTRICT ON UPDATE CASCADE
. Podívejte se na náš příklad CREATE TABLE, kde je uvedeno, kdy tento kód umístit. - Ujistěte se, že tabulka je InnoDB . Můžete to udělat přidáním
ENGINE=InnoDB
na konec vašíCREATE TABLE
příkaz (viz můj příklad z doby, kdy jsme vytvářeli naše tabulky). Některé motory (například MyISAM ) nepodporují omezení cizího klíče, ale neposkytují na to žádné varování, když se pokusíte vytvořit omezení cizího klíče. Pokud váš výchozí engine není InnoDB pak je pravděpodobné, že vaše cizí klíče nebudou podporovány. - Ujistěte se, že MySQL skutečně kontroluje cizí klíče. Můžete to provést spuštěním následujícího kódu:
SET FOREIGN_KEY_CHECKS=1
.
Zakázat kontrolu cizího klíče
Mohou nastat situace, kdy se omezení cizích klíčů mohou stát zbytečně omezujícími – do té míry, že vážně naruší vaše úsilí při načítání dat. Například když jste právě vytvořili databázi a potřebujete načíst počáteční data. Nebo pokud potřebujete odstranit spoustu tabulek a znovu načíst data.
Pokud nenačtete data ve správném pořadí, budete pravděpodobně stále dostávat chyby cizího klíče v důsledku načítání dat ve špatném pořadí (tj. pokoušíte se načíst podřízené tabulky dříve, než budou mít nadřazené tabulky své data načtena).
Toto není problém pouze při načítání data. S tímto problémem se také můžete setkat při vytváření databáze. Pokud nevytvoříte tabulky ve správném pořadí, můžete narazit na chyby kvůli omezení cizího klíče.
Pokud neznáte správné pořadí rodič-dítě, může stanovení správného pořadí vytvoření databáze nebo načtení dat zabrat spoustu času a úsilí. V případech, jako jsou tyto, možná bude lepší říct MySQL dočasně, aby prozatím nekontrolovala cizí klíče.
Kontrolu cizího klíče můžete zakázat pomocí následujícího kódu:
FOREIGN_KEY_CHECKS=0
Chcete-li jej znovu aktivovat, postupujte takto:
FOREIGN_KEY_CHECKS=1