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

Видове връзки: 1:1, 1:N, M:N

Накратко: Връзката между две таблици е едно към едно, едно към много или много към много, и от вида ѝ зависи къде е външният ключ и кога трябва отделна таблица за двойките.

Проблем

Карта и етикети

Магазинът пуска две новости. Първата е карта за лоялност: всеки клиент може да има една карта с точки. Втората са етикети на продуктите, като „веган“, „без глутен“ и „био“, за да ги филтрираш в сайта.

Къде да ги запишеш? Колона card_number в customers? Колона tags в products с текст „веган, био“? Отговорът зависи от един въпрос: колко неща от едната страна отговарят на колко от другата.

Идеята

Едно към много (1:N)

Един клиент има много поръчки. Всяка поръчка е на един клиент. Това е връзка едно към много, пише се 1:N.

Ключът е от страната на „много“-то. Всяка поръчка казва чия е с customer_id:

customers

  • PKidinteger
  • nametext *
  • emailtext *
  • citytext
  • joined_attext *

orders

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

Обратното не става. Колко колони order_1, order_2 да има клиентът? Мария има 12 поръчки, а утре ще са 13.

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

Това е най-честата връзка. В магазина са такива и категорията с продуктите, и продуктът с отзивите.

Пробвай

Продуктите по категории

Колко продукта има във всяка категория, в която има продукти? Покажи името на категорията и броя.

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

Идеята

Едно към едно (1:1)

Всеки клиент има най-много една карта, а всяка карта е на един клиент. Това е едно към едно, 1:1. Пази се като 1:N, с ключ към клиента, и с още едно правило: UNIQUE.

loyalty_cards

  • PKidinteger
  • FKcustomer_idinteger *→ customers
  • numbertext *
  • pointsinteger *
  • issued_attext *
SQLбаза: магазин

Пет клиенти имат карта. Опитай да дадеш на Мария втора:

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

UNIQUE на customer_id не пуска втори ред за същия клиент. Без него връзката щеше да е 1:N.

Защо не колони в customers? Може и така. Често 1:1 са още няколко колони в същата таблица. Отделна таблица има смисъл, когато повечето редове нямат втората част (15 от 20 клиенти нямат карта и щяха да имат празни клетки) или когато тя има свой живот: картата се губи, сменя се, има свои точки.

Пробвай

Кой още няма карта

Маркетингът иска да предложи карта на всеки клиент, който още няма. Покажи имената им.

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

Идеята

Много към много (M:N)

В една поръчка има много продукти. Един продукт е в много поръчки. Това е много към много, M:N.

Тук ключът не може да е в нито една от двете таблици. Решението е трета таблица, таблица за връзка, с по един ред за всяка двойка. В магазина това е order_items: всеки ред е един продукт в една поръчка, с броя и цената.

products

  • PKidinteger
  • nametext *
  • FKcategory_idinteger→ categories
  • pricereal *
  • stockinteger *
  • added_attext *

order_items

  • PKorder_idinteger→ orders
  • PKproduct_idinteger→ products
  • quantityinteger *
  • unit_pricereal *

В кои поръчки е кафето (продукт 17)?

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

Етикетите са същото. Продуктът има много етикети, а етикетът е на много продукти:

tags

  • PKidinteger
  • nametext *

product_tags

  • PKproduct_idinteger→ products
  • PKtag_idinteger→ tags
SQLбаза: магазин

Виж го

Двойката е ключът

Първичният ключ на order_items е двойката (order_id, product_id). Опитай да сложиш хляба втори път в поръчка 60, където вече го има:

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

Базата не пуска същата двойка два пъти. Продукт е в поръчката веднъж, а повече бройки се пишат в quantity. Иначе отчетът „колко пъти е поръчан хлябът“ щеше да брои един и същ продукт от една поръчка два пъти.

1. Всеки продукт има точно една категория, а в категорията има много продукти. Къде е ключът?

Пробвай

Етикетите в сайта

До всеки етикет в сайта пише колко продукта има. Покажи името на етикета и броя.

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

Упражнение

Две задачи

1. На страницата на ябълките се показват етикетите им. Кои са?

Етикетите на продукта „Ябълки“:

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

2. Клиентка търси продукти, които са и веган, и без глутен. Покажи имената им.

Продуктите с двата етикета, „веган“ и „без глутен“:

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

Тест

Провери се

1. Какво прави връзката между loyalty_cards и customers 1:1, а не 1:N?
2. Студент записва много курсове, а в курса има много студенти. Как се пази това?
3. Защо първичният ключ на product_tags е (product_id, tag_id)?
4. Защо заявката с WHERE t.name = 'веган' AND t.name = 'без глутен' не намира нищо?

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