Определяне на недвусмислени колони/ограничения за външни ключове
Ако приемем, че имате предвид ограниченията на външния ключ , краткият отговор би бил просто не ги използвате .
И тук идва дългият:
Свикнали сме да наричаме колоните като външни ключове към други маси. Особено по време на процеса на нормализиране, фрази като "user_purchase.i_id
е външен ключ към items
маса" би било много често. Въпреки че това е напълно валиден начин да се опише връзката, тя може да стане малко размита, когато достигнем фазата на внедряване.
Да предположим, че сте създали своите таблици без FOREIGN KEY
клаузи:
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,
);
Забележете, че по отношение на връзката външният ключ колони все още се прилагат . Има колона, която препраща към user
таблица (id
) и друг, който препраща към items
таблица (i_id
) -- нека поставим name
колоната настрана за момент. Помислете за следните данни:
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 |
Връзката е налице. Реализира се с помощта на user_purchase
таблица, която съдържа информация за кой какво е купил . Ако трябва да запитаме базата данни за съответен отчет, бихме направили:
select * from user_purchase p
join user u on (p.id=u.id)
join items i on (p.i_id=i.i_id)
И така използваме релацията и колони на външния ключ участва.
Ами ако го направим:
insert into user_purchase (id,i_id) values (23,99)
Очевидно това е невалиден запис. Въпреки че има потребител с id=23
, няма елемент с i_id=99
. RDBMS ще позволи това да се случи, защото не знае нищо по-добре . Още.
Това е мястото, където ограниченията на външния ключ влезе в игра. Чрез посочване на FOREIGN KEY (i_id) REFERENCES items(i_id)
в user_purchase
дефиниране на таблица, ние по същество даваме на RDBMS правило, което да следва:записи с i_id
стойности, които не се съдържат в items.i_id
колона не са приемливи . С други думи, докато външен ключ колона прилага препратката , ограничение за външен ключ налага референтната цялост .
Имайте предвид обаче, че горният select
няма да се промени, само защото сте дефинирали FK ограничение. И така, вие не използвайте FK ограничения, RDBMS го прави, за да защитите вашите данни.
Съкращения
Запитайте се:Защо бихте искали това? Ако двата външни ключа трябва да служат за една и съща цел, излишъкът в крайна сметка ще ви създаде проблеми. Помислете за следните данни:
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 |
Какво не е наред с тази снимка? Потребителят 55
купи две шоколадови блокчета или шоколад и паста за зъби? Този вид неяснота може да доведе до много усилия за поддържане на синхронизиране на данните, което би било ненужно, ако просто запазим един от външните ключове. Всъщност защо не пуснете name
колона като цяло, тъй като се подразбира от релацията.
Разбира се, бихме могли да разрешим това, като внедрим композитен външен ключ, като зададем PRIMARY KEY(i_id,name)
за items
таблица (или дефиниране на допълнителен UNIQUE(i_id,name)
). индекс, това всъщност няма значение) и след това задаване на FOREIGN KEY(i_id,name) REFERENCES items(i_id,name)
. По този начин само (i_id,name) двойки, които съществуват в items
таблицата ще бъде валидна за user_purchases
. Отделно от това, че все пак ще имашен външен ключ , този подход е напълно ненужен, при условие че i_id
колоната вече е достатъчна за идентифициране на елемент (не може да се каже същото за name
колона...).
Въпреки това, няма правило срещу използването на множество външни ключове към таблица. Всъщност има обстоятелства, които изискват такъв подход. Помислете за person(id,name)
таблица и parent(person,father,mother)
едно, със следните данни:
person parent
| id name | | person father mother |
| 14 John | | 21 14 59 |
| 43 Jane | | 14 76 43 |
| 21 Mike |
| 76 Frank |
| 59 Mary |
Очевидно и трите колони на parent
таблицата са външни ключове за person
. Не за същата връзка , но за три различни :Тъй като родителите на дадено лице също са лица, двете съответни колони трябва да препращат към една и съща таблица person
прави. Имайте предвид обаче, че трите полета не само могат но също така трябва препращане към различен person
е в същия parent
ред, тъй като никой не е негов собствен родител и нечий баща е и негова майка.