Бази данни без мъгла

Таблици, редове и ключове

11 min
What you'll learn
  • да различаваш таблици, редове и колони и да обясняваш защо на всеки ред е нужен първичен ключ (обикновено id)
  • да намираш връзки между таблиците по външния ключ: orders.user_id → users.id
  • да различаваш сурогатен ключ (IDENTITY, ) от естествен (email, ISBN) и да обосноваваш защо първичният ключ не бива да се променя
  • да затвърждаваш уникалността на поле като email с ограничение UNIQUE, без да го правиш първичен ключ

Описът е отворен. КВЕРИ разгръща над работната маса холограма: хиляди записи увисват във въздуха в равна мрежа, а между някои се протягат тънки кехлибарени нишки. Посягаш към една — тя звънти като струна. Това не е купчина файлове. Това е тъкан.

Таблици, редове, колони

Релационната база прилича на спретнат каталог: данните са подредени по таблици, а вътре във всяка таблица има колони (какви свойства пазим) и редове (конкретните записи).

Вземи таблицата с купувачите users: всеки ред е един купувач от стара Земя, а колоните описват неговите id, full_name, email, country, city, signup_date.

За да не се бъркат хора с еднакви имена, всеки ред има първичен ключ () — уникален идентификатор, обикновено колоната id. Чрез него други таблици могат да сочат към този ред с помощта на външен ключ (). Например в поръчката orders има user_id — така поръчката помни своя купувач. Същите тези кехлибарени нишки на холограмата са именно връзките по ключове.

КВЕРИ: Докато ключът е цял — нишката е цяла. Век и половина минаха, а всяка поръчка още помни своя човек.

Пусни заявката и виж как изглеждат купувачите на «Kotomarket» — записи, които никой не е отварял от времената на старата Мрежа:

Холографска таблица от редове-капсули и колони; от записите на поръчки към записите на хора се протягат кехлибарени нишки-ключове
Редовете са записи, колоните — техните свойства, а нишката от поръчка към купувач е връзка по ключ.

Tables, rows, columns

A relational database is like a tidy catalog: the data is sorted into tables, and inside each table there are columns (what properties we store) and rows (the individual records).

Take the buyers’ table users: each row is one buyer from old Earth, and the columns describe their id, full_name, email, country, city, signup_date.

So that people with the same name don’t get confused, every row has a — a unique identifier, usually the id column. Through it, other tables can reference this row using a . For example, an order in orders has a user_id — that’s how an order remembers its buyer. Those amber threads on the hologram are exactly these key-based links.

QUERY: As long as the key holds, the thread holds. A century and a half on, every order still remembers its person.

Run the query and see what Kotomarket’s buyers look like — records no one has opened since the days of the old Net:

Първите купувачи на «Kotomarket» в таблицата:
Query result
idfull_namecitysignup_date
1Артём ВолковСанкт-Петербург2024-10-20
2Екатерина АлексеевЕкатеринбург2025-01-25
3Николай НикитинАлматы2024-09-21
4Екатерина ИвановНовосибирск2024-05-04
5Елена ПетровКазань2025-01-05
6Ирина КузнецовНовосибирск2024-09-12

Първичният ключ помага безпогрешно да намериш един ред (обикновено id). Външният ключ свързва таблиците: например orders.user_id → users.id показва чия е поръчката. По-нататък КВЕРИ ще разгърне пред теб цялата карта на снимката — петте таблици изцяло.

usersidfull_namecityordersiduser_idstatususer_id → id
Външният ключ orders.user_id сочи към първичния ключ users.id — така поръчката помни своя купувач.

Естествен или сурогатен ключ

Откъде идва първичният ключ? Пътищата са два. Естественият ключ е реален атрибут, който и без друго е уникален: email на купувача, ISBN на книга, код на валута. Сурогатният ключ е изкуствен идентификатор без смисъл във външния свят: автономериране или . В «Kotomarket» навсякъде се използват сурогатни id — и това е типово решение:

-- Суррогатный ключ: база сама выдаёт следующий номер (PostgreSQL)
CREATE TABLE users (
  id        BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  email     TEXT NOT NULL UNIQUE,  -- натуральный кандидат живёт рядом как UNIQUE
  full_name TEXT NOT NULL
);

Защо така? Главното свойство на първичния ключ: той не бива да се променя. Към PK сочат външните ключове на други таблици и смяната на стойността би повлякла обновяване на всички нишки наведнъж — в orders, в events, навсякъде. А «вечни» естествени атрибути почти няма: хората сменят email и фамилии, телефоните се преразпределят, дори ISBN се преиздават. Сурогатният id не се променя никога — именно защото не означава нищо.

Изисквания към всеки първичен ключ: уникален, не NULL, стабилен. Естествените ключове остави за малки непроменими справочници — например кода на валута 'RUB' от ISO 4217. А уникалността на естествен кандидат като email фиксирай с отделно ограничение UNIQUE, както в примера по-горе: връзките се запазват, данните остават честни и пак не е забранено на купувача да си смени имейла.

Изпреварваме малко: самият синтаксис за създаване на таблици и ограничения (CREATE TABLE, PRIMARY KEY, UNIQUE) е тема на Глава 9. Тук гледай структурата на ключа, а не командата: че сурогатният id е станал първичен ключ, а email живее до него като UNIQUE.

Interview question

Въпрос от интервю: по какво се различава сурогатният ключ от естествения и кой ще избереш за таблица с потребители?

Силен отговор: естественият е реален уникален атрибут (email, ISBN), сурогатният е изкуствен идентификатор (IDENTITY колона или ). За потребители — сурогатен: първичният ключ не бива да се променя, защото към него сочат външните ключове, а email хората сменят. Уникалността на email при това се затвърждава с отделно UNIQUE ограничение. Естественият ключ е оправдан в стабилни справочници като кодовете на валути ISO 4217.

Check yourself
Защо в базата е нужен външен ключ (foreign key)?