Към съдържанието
wannacode

Външни ключове: връзки между таблиците

Накратко: Външният ключ (REFERENCES) пази връзката между две таблици, а ON DELETE казва какво става със свързаните редове при изтриване: CASCADE, SET NULL или RESTRICT.

Проблем

Изтрий ми профила

Мария Иванова пише: „Моля, изтрийте профила ми.“ Опитваш:

SQLбаза: магазин

Базата отказва. Мария има 12 поръчки, а всяка от тях сочи към нея. Ако клиентът изчезне, поръчките ще сочат към никого.

Какво трябва да стане с поръчките ѝ? А с отзивите ѝ? А със списъка ѝ с любими продукти? Отговорът е различен за всяка таблица. И се записва в схемата.

Идеята

REFERENCES

Външният ключ вече го познаваш: колона, която сочи към ред в друга таблица. В CREATE TABLE се пише с REFERENCES таблица(колона). Така са направени поръчките на магазина:

orders

  • PKidinteger
  • FKcustomer_idinteger *→ customers
  • ordered_attext *
  • statustext *

Ето нова таблица: любимите продукти на всеки клиент. Първият ред влиза, вторият сочи към клиент 99, който го няма:

SQLбаза: магазин

Сега базата сама пази връзките. Ред, който сочи към несъществуващ клиент или продукт, не влиза.

Пробвай

Любимите продукти

Таблицата wishlist вече има колоните си. Направи customer_id да сочи към customers, а product_id към products.

SQLбаза: магазин

Идеята

ON DELETE CASCADE

След REFERENCES може да кажеш какво да стане, когато редът, към който сочиш, се изтрие. Това е ON DELETE.

CASCADE значи „изтрий и мен“. Явор Пенев (клиент 20) има два любими продукта. Теодора Генова (клиент 19) има един. Явор изтрива профила си:

SQLбаза: магазин

Любимите на Явор изчезнаха с него. Тези на Теодора са си там. Списък с любими без клиента няма смисъл, затова тук CASCADE е правилно.

Идеята

SET NULL и RESTRICT

SET NULL значи „остави ме, но без връзка“. Въпросите към продуктите са полезни и за другите купувачи, дори когато авторът си е тръгнал:

SQLбаза: магазин

Въпросът остана, а customer_id стана NULL: въпрос от бивш клиент.

RESTRICT значи „не пускай изтриването“. Фактурите трябва да се пазят години наред по закон:

SQLбаза: магазин

Без ON DELETE поведението е почти същото: изтриването спира. Затова Мария не можа да изтрие профила си. Поръчките са история на магазина и не бива да изчезват.

По-точно, за любопитните

Без ON DELETE правилото е NO ACTION. Разликата с RESTRICT е само кога се проверява: RESTRICT спира веднага, а NO ACTION проверява в края на заявката (или на транзакцията, ако проверката е отложена). Има и ON UPDATE за промяна на ключа, но се ползва рядко, защото първичният ключ почти никога не се сменя. ON DELETE SET DEFAULT също е рядкост.

Виж го

SET NULL срещу NOT NULL

Някой е написал таблицата за въпроси така:

customer_id INTEGER NOT NULL REFERENCES customers(id) ON DELETE SET NULL

Явор пак изтрива профила си:

SQLбаза: магазин

SET NULL иска да запише NULL, а NOT NULL не го пуска. Изтриването спира. SQLite не предупреждава за това при CREATE TABLE, а чак когато някой се опита да изтрие. Колона със SET NULL трябва да може да е празна.

Пробвай

Адресите за доставка

Таблицата addresses пази адресите на клиентите. Когато клиентът изтрие профила си, адресите му трябва да изчезнат заедно с него. Поправи customer_id.

SQLбаза: магазин

Идеята

Проверката трябва да е включена

В курса базата проверява външните ключове. Питаш я с PRAGMA, командата за настройките на SQLite:

SQLбаза: магазин

1 значи „включено“. Ако я изключиш, REFERENCES вече не пази нищо:

SQLбаза: магазин

Поръчка на клиент 99, който го няма, влезе без грешка.

По-точно, за любопитните

В истинския SQLite проверката е изключена по подразбиране. Пусни sqlite3 на своя компютър и напиши PRAGMA foreign_keys;: отговорът е 0. Причината е старите програми, писани преди SQLite да проверява външни ключове. Настройката важи само за една връзка с базата. Затова програмата пуска PRAGMA foreign_keys = ON; всеки път, когато отваря базата. Тази страница го прави вместо теб. PostgreSQL, MySQL (с InnoDB) и SQL Server проверяват външните ключове по подразбиране.

Упражнение

Въпросите към продуктите

Таблицата questions има id, product_id, customer_id и body. Когато продуктът се махне от магазина, въпросите за него изчезват. Когато клиентът изтрие профила си, въпросите му остават, но без автор. Добави връзките.

SQLбаза: магазин

Тест

Провери се

1. Таблицата orders има customer_id REFERENCES customers(id) без ON DELETE. Какво става при DELETE на клиент с поръчки?
2. Клиентът изтрива профила си. Какво е подходящо за неговия списък с любими продукти?
3. Колоната е customer_id INTEGER NOT NULL REFERENCES customers(id) ON DELETE SET NULL. Какво става при изтриване на клиента?
4. Пускаш скрипт в истински SQLite и INSERT към несъществуващ клиент минава. Защо?

Създаден от Иво Гергов като част от кампанията на Evo Tech за достъпно обучение по програмиране ·