A FOREIGN KEY (idegen kulcs) egy olyan adatbázis-megszorítás, amely két tábla között kapcsolatot hoz létre, és biztosítja a kapcsolódó adatok érvényességét.
A FOREIGN KEY segítségével megadhatjuk, hogy egy tábla egyik oszlopa egy másik tábla egy meghatározott oszlopára hivatkozik.
Például egy webáruházban:
vasarlok tábla, amely a vásárlókat tárolja;rendeles tábla, amely a rendeléseket tárolja.Egy rendelésnek tudnia kell, hogy melyik vásárlóhoz tartozik.
Erre használjuk a FOREIGN KEY-t.
Van két táblánk, a vásárlókat és a rendeléseket tároló tábla:
CREATE TABLE vasarlok (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
nev VARCHAR(100) NOT NULL
);
CREATE TABLE rendelesek (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
vasarlo_id INT UNSIGNED NOT NULL,
FOREIGN KEY (vasarlok_id) REFERENCES vasarlok(id)
);
A kapcsolat:
vasarlok
┌────┬───────────────┐
│ id │ nev │
├────┼───────────────┤
│ 1 │ Kovács Péter │
│ 2 │ Nagy Anna │
│ 3 │ Szabó Béla │
└────┴───────────────┘
↑
│
│ hivatkozás
│
Rendelesek │
┌────┬─────────────┐
│ id │ vasarlo_id │
├────┼─────────────┤
│ 1 │ 1 │
│ 2 │ 2 │
│ 3 │ 1 │
└────┴─────────────┘
Az rendelesek.vasarlo_id az vasarlok.id mezőre hivatkozik.
Ez azt jelenti, hogy az rendelesek táblában szereplő vasarlo_id értéknek léteznie kell a vasarlok táblában.
Tegyük fel, hogy a vasarlok tábla tartalma:
id nev
----------------
1 Kovács Péter
2 Nagy Anna
3 Szabó Béla
Ezért a következő INSERT helyes:
INSERT INTO rendelesek (vasarlo_id) VALUES (2);
Hiszen a vasarlok táblában létezik a 2 azonosító.
A következő viszont hibás:
INSERT INTO orders (customer_id) VALUES (99);
A 99 azonosító nem létezik a vasarlok táblában.
A FOREIGN KEY ezért megakadályozza az adat beszúrását.
Ezzel biztosítható az úgynevezett referenciális integritás.
A referenciális integritás azt jelenti, hogy egy táblában nem hivatkozhatunk olyan rekordra, amely a hivatkozott táblában nem létezik.
Például:
A rendelesek.vasarlo_id csak olyan érték lehet, amely megtalálható a vasarlok.id mezőben.
FOREIGN KEY (vasarlo_id) REFERENCES vasarlok(id)
Két fontos rész található benne.
FOREIGN KEY (vasarlo_id)
Ez megadja, hogy melyik oszlop lesz az idegen kulcs.
REFERENCES vasarlok(id)
Ez megadja, hogy melyik tábla melyik oszlopára hivatkozunk.
Tehát:
FOREIGN KEY (vasarlo_id) REFERENCES vasarlok(id)
↓ ↓
hivatkozó oszlop hivatkozott oszlop
A hivatkozott oszlopnak általában PRIMARY KEY vagy megfelelő UNIQUE kulcsnak kell lennie.
❗ A PRIMARY KEY és a FOREIGN KEY nem ugyanaz.
| PRIMARY KEY | FOREIGN KEY |
|---|---|
| Egy rekord azonosítására szolgál | Másik tábla rekordjára hivatkozik |
| Egy táblában egy PRIMARY KEY lehet | Több FOREIGN KEY is lehet |
| Értéke egyedi | Nem feltétlenül egyedi |
Nem lehet NULL |
Lehet NULL, ha az oszlop engedi |
| A tábla saját kulcsa | Másik tábla kulcsára hivatkozik |
A FOREIGN KEY és a hivatkozott kulcs adattípusának kompatibilisnek kell lennie.
Például:
vasarlok.id INT UNSIGNED
esetén:
rendelesek.vasarlo_id INT UNSIGNED
a megfelelő választás.
Nem célszerű például:
vasarlok.id INT UNSIGNED
rendelesek.vasarlo_id VARCHAR(20)
A UNSIGNED tulajdonságra is figyelni kell.
Ha egy idegen kulcs egy INT UNSIGNED elsődleges kulcsra hivatkozik, akkor maga az idegen kulcs is legyen INT UNSIGNED.
A FOREIGN KEY-t már a tábla létrehozásakor megadhatjuk.
CREATE TABLE rendelesek (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
vasarlo_id INT UNSIGNED NOT NULL,
rendeles_datum DATE NOT NULL,
CONSTRAINT fk_rendelesek_vasarlo
FOREIGN KEY (vasarlo_id)
REFERENCES vasarlok(id)
);
A CONSTRAINT után megadhatjuk a megszorítás nevét: "fk_rendelesek_vasarlo"
Ez a név segít később azonosítani a FOREIGN KEY-t.
Ha a táblák már léteznek, később is létrehozhatjuk a kapcsolatot.
ALTER TABLE rendelesek ADD
FOREIGN KEY (vasarlo_id) REFERENCES vasarlok(id);
Ezzel hozzáadjuk a FOREIGN KEY megszorítást az rendelesek táblához.
Fontos kérdés:
Mi történjen akkor, ha törölni akarunk egy olyan rekordot, amelyre másik tábla hivatkozik?
Például:
Mi történjen, ha ezt végrehajtjuk?
DELETE FROM vasarlok WHERE id = 1;
A FOREIGN KEY beállításától függően többféle viselkedés lehetséges.
ON DELETE RESTRICT
A RESTRICT megakadályozza a szülőrekord törlését, ha még van rá hivatkozás.
FOREIGN KEY (vasarlo_id)
REFERENCES vasarlok(id)
ON DELETE RESTRICT
Ha az 1 azonosítójú vásárlónak vannak rendelései, akkor:
DELETE FROM vasarlok WHERE id = 1;
nem hajtható végre.
Ez biztonságos megoldás lehet olyan adatoknál, amelyeket nem szeretnénk véletlenül törölni.
ON DELETE CASCADE
A CASCADE azt jelenti, hogy a szülőrekord törlésekor a kapcsolódó gyermekrekordok is törlődnek.
FOREIGN KEY (vasarlo_id)
REFERENCES vasarlok(id)
ON DELETE CASCADE
Ha töröljük:
DELETE FROM vasarlok WHERE id = 1;
akkor a hozzá tartozó rendelések is törlődnek.
Ezért a CASCADE használatával óvatosan kell bánni.
ON DELETE SET NULL
A SET NULL esetén a gyermekrekord megmarad, de a FOREIGN KEY értéke NULL lesz.
FOREIGN KEY (vasarlo_id)
REFERENCES vasarlok(id)
ON DELETE SET NULL
Ehhez a mezőnek engednie kell a NULL értéket:
ON DELETE NO ACTION
A NO ACTION azt jelenti, hogy a hivatkozott rekord törlése nem történhet meg, ha az sértené a FOREIGN KEY szabályát.
MySQL esetén az InnoDB tárolómotornál a NO ACTION gyakorlatilag a RESTRICT-hez hasonló viselkedést eredményez.
ON UPDATE
Nemcsak törlésre, hanem módosításra is meghatározhatjuk, mi történjen.
CONSTRAINT fk_orders_customer
FOREIGN KEY (customer_id)
REFERENCES customers(id)
ON DELETE CASCADE
ON UPDATE CASCADE
Ha a szülőtábla kulcsértéke megváltozik, akkor a kapcsolódó FOREIGN KEY értékek is követik a változást.
Egy táblának nem csak egy idegen kulcsa lehet.
Például egy rendeléshez tartozhat vásárló és termék:
CREATE TABLE rendelesi_elemek (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
rendeles_id INT UNSIGNED NOT NULL,
termek_id INT UNSIGNED NOT NULL,
FOREIGN KEY (rendeles_id)
REFERENCES rendelesek(id),
FOREIGN KEY (termek_id)
REFERENCES termekek(id)
);
FOREIGN KEY több oszlopból is állhat.
Például:
FOREIGN KEY (iranyitoszam, vasarlo_szam)
REFERENCES vasarlok(iranyitoszam, vasarlo_szam)
Ilyenkor a két oszlop együtt alkotja a hivatkozást.
A hivatkozott oldalon ennek megfelelő összetett PRIMARY KEY vagy UNIQUE kulcs szükséges.
Ha egy meglévő FOREIGN KEY-t el szeretnénk távolítani, ismernünk kell a constraint nevét.
Például:
ALTER TABLE rendelesek
DROP FOREIGN KEY fk_rendelesek_vasarlo;
Ez eltávolítja a FOREIGN KEY megszorítást.
A FOREIGN KEY-t általában nem közvetlenül módosítjuk.
Gyakori megoldás:
FOREIGN KEY-t akkor érdemes használni, amikor két tábla között valódi adatbázis-szintű kapcsolat van.
A FOREIGN KEY előnye, hogy nem csak a programozóra bízzuk az adatok helyességét.
Az adatbázis maga is ellenőrzi a kapcsolatot.
Készíts egy adatbázist egy iskola számára.
students táblaHozd létre a következő mezőkkel:
id – INT UNSIGNED, automatikusan növekvő, PRIMARY KEYname – legfeljebb 100 karakter, kötelezőemail – legfeljebb 150 karakter, kötelezőcourses táblaid – INT UNSIGNED, automatikusan növekvő, PRIMARY KEYname – legfeljebb 100 karakter, kötelezőenrollments táblaEz tárolja, hogy melyik diák melyik kurzusra jelentkezett.
student_idcourse_idenrolled_atFeladat:
enrollments.student_id legyen FOREIGN KEY a students.id mezőre.enrollments.course_id legyen FOREIGN KEY a courses.id mezőre.enrollments táblában a student_id és course_id együtt legyen PRIMARY KEY.Készíts egy adatbázist egy iskola számára, amelyben a diákok, tanárok, tantárgyak, vizsgák és vizsgaeredmények adatait tároljuk.
students táblaHozd létre a következő mezőkkel:
id – nem negatív egész szám, automatikusan növekszik, elsődleges kulcsname – legfeljebb 100 karakterből álló szöveg, kötelezőemail – legfeljebb 150 karakterből álló szöveg, kötelező és egyedibirth_date – dátum, kötelezőteachers táblaid – nem negatív egész szám, automatikusan növekszik, elsődleges kulcsname – legfeljebb 100 karakterből álló szöveg, kötelezőemail – legfeljebb 150 karakterből álló szöveg, kötelező és egyedisubjects táblaEz a tábla az iskola tantárgyait tárolja.
id – nem negatív egész szám, automatikusan növekszik, elsődleges kulcsname – legfeljebb 100 karakterből álló szöveg, kötelező és egyediteacher_id – nem negatív egész szám, kötelezőFeladat:
teacher_id legyen FOREIGN KEY, amely a teachers tábla megfelelő rekordjára hivatkozik.exams táblaEz tárolja, hogy egy adott tantárgyból mikor kerül sor vizsgára.
id – nem negatív egész szám, automatikusan növekszik, elsődleges kulcssubject_id – nem negatív egész szám, kötelezőexam_date – dátum, kötelezőmax_points – nem negatív egész szám, kötelezőTovábbi követelmény:
Feladat:
subject_id legyen FOREIGN KEY, amely a subjects tábla megfelelő rekordjára hivatkozik.exam_results táblaEz a tábla tárolja, hogy egy adott diák egy adott vizsgán hány pontot ért el.
student_id – nem negatív egész szám, kötelezőexam_id – nem negatív egész szám, kötelezőpoints – nem negatív egész szám, kötelezőFeladat:
student_id legyen FOREIGN KEY, amely a students tábla megfelelő rekordjára hivatkozik.exam_id legyen FOREIGN KEY, amely az exams tábla megfelelő rekordjára hivatkozik.student_id és az exam_id együtt legyenek az elsődleges kulcs.id mező automatikusan növekedjen.NULL értéket tárolni.