
Оксана Соболевская (Давыдович)
Системный аналитик EvApps
Всем привет! Меня зовут Оксана, я системный аналитик из компании EvApps. Что побудило меня написать эту статью? Я обучаю стажеров – системных аналитиков, и недавно столкнулась с такими вопросами, о которых раньше даже не задумывалась.
Вопросы были связаны с разными видами ключей в базе данных и с тем, как они связаны между собой (тему с реляционными CREATE TABLE public.user ( id int, "name" varchar, age int );
Далее хочу создать таблицу Order и связать ее с таблицей User. И при выполнении запроса получаю ошибку. Для наглядности создадим две таблицы. Но в одном случае для поля сделаем ограничение уникальности, а в другом случае установим для этого поля первичный ключ. Вариант с использованием UNIQUE: Вариант с использованием PRIMARY KEY: Теперь попробуем создать запись в таблице user1, но для id установим значение null: Как видим, запись в таблицу добавилась успешно. Теперь попробуем то же самое сделать в таблице user2: И видим, что при создании записи возникает ошибка. Какие выводы можно сделать: PRIMARY KEY – первичный ключ, позволяет сделать запись уникальной и включает в себя ограничение NOT NULL. UNIQUE – ограничение уникальности, обеспечивает уникальность значений в столбце/столбцах, при этом не имеет проверку на NULL. Чтобы этого избежать, нужно использовать UNIQUE NOT NULL. По факту, вместо PRIMARY KEY можно использовать UNIQUE NOT NULL и Postgres позволяет это сделать, но рекомендуют следовать теории реляционных баз данных и устанавливать первичные ключи. Да, можно, но это бессмысленно. В данном случае учитывается ограничение первичного ключа, а UNIQUE считается избыточным и отбрасывается. Например, я создаю таблицу: Но в DDL можем увидеть, что в ограничениях остался только первичный ключ. При этом можно использовать и первичный ключ и ограничение уникальности в рамках одной таблицы. Да, можно. Пример: Создаем таблицу, где установлено ограничение уникальности: Далее создаем таблицу с ссылкой на таблицу user1: Таблица создана успешно, связь настроена. И если мы попытаемся в таблицу Order добавить запись с пользователем, которого нет в таблице user1, то получим ошибку. Можно ли установить связь между таблицами без внешнего ключа? Нет, это невозможно. Для установления связи между таблицами обязательно использование REFERENCES. Примечание: Ответ на оба вопроса – да. Давайте для примера рассмотрим два случая: и В первом случае при добавлении записи будет проверяться каждое значение на уникальность в столбцах, где установлен UNIQUE. Например, если у меня есть такая запись в таблице: То я не смогу добавить строку со значением series_passport=7777 или number_passport=123454. Будет выдаваться ошибка. То есть проверка уникальности значений происходит по КАЖДОМУ столбцу, где установлен UNIQUE. Теперь рассмотрим второй случай. Я могу создавать строки с одинаковыми значениями series_passport или number_passport. Но пара этих значений должна быть уникальной. То есть во втором случае происходит проверка СОЧЕТАНИЯ значений всех столбцов. Один и только один. Иначе получаем такую ошибку: Сколько угодно. Ограничения на количество нет, но важно понимать целесообразность использования UNIQUE. Нет. Типы данных должны быть одинаковые, как и количество столбцов. В ином случае будет возникать ошибка. Рассмотрим связь, которую установили в примерах выше. У полей user_id и id, одинковый тип данных – int. Если бы тип отличался, или мы бы пытались связать поле user_id с двуми полями, а не одним (id), то установить связь не получилось бы. Да, могут. Рассмотрим такую задачу. У нас есть три таблицы: продукты, пользователи и отзывы. И есть условие: пользователь на один товар может оставить только один отзыв. Я выбрала вот такую реализацию. Создаем таблицы пользователи и продукты: Далее при создании таблицы Отзывы я установила первичный ключ на два столбца user_id,product_id (то есть сочетание их значений мне нужно проверять): И с этих же полей я установила связь с внешними таблицами user_new и product. И если я захочу добавить запись, где повторяется сочетание user_id + product_id, у меня возникнет ошибка: В таблице ниже я собрала разные вопросы, с которыми столкнулась. И на основании тех практических задач, что я разбирала, указала ответы. И получилось следующее: Вопрос Ответ 1. Можно ли создать таблицу без первичного ключа? Да, но согласно теории баз данных каждая таблица должна иметь первичный ключ 2. Можно ли использовать UNIQUE вместо PRIMARY KEY? В чем особенности? PostgreSQL позволяет это сделать (важно учитывать ограничение NOT NULL), но рекомендуют устанавливать первичный ключ 3. Можно ли использовать первичный ключ и ограничение уникальности вместе (то есть для одного столбца установить два ограничения)? Можно, но это не имеет смыла. В этом случае UNIQUE будет избыточным и не будет учитываться 4. Можно ли сделать связь с таблицей, в которой не установлено PRIMARY KEY и UNIQUE? Нет, это невозможно 5. Можно ли сделать связь с полем в таблице, где установлен UNIQUE, но не установлен PRIMARY KEY? Да, можно 6. Можно ли установить связь между таблицами без внешнего ключа? Нет, для установления связи необходимо использовать REFERENCES (на уровне
7. Можно ли в одной таблице использовать первичный ключ и ограничение уникальности? Да, но в разных столбцах. Если использовать для одного столбца UNIQUE и PRIMARY KEY, то UNIQUE будет считаться избыточным и не будет учитываться. 8. Может ли первичный ключ состоять из нескольких столбцов? Да, может 9. Может ли в одной таблице быть установлено несколько PRIMARY KEY? Нет 10. Может ли ограничение уникальности включать несколько столбцов? Да 11. Сколько ограничений уникальности может иметь таблица? Несколько 12. Может ли быть разное число столбцов и типы данных полей у внешнего ключа и первичного (или внешнего ключа и UNIQUE)? Нет, число столбцов и тип данных должен быть одинаковый 13. Может ли на одном поле быть уставлены и первичный и внешний ключи? Да
2. Можно ли использовать ограничение уникальности вместо первичного? В чём особенности?
CREATE TABLE public.user1 ( id int UNIQUE, "name" varchar, age int );CREATE TABLE public.user2 ( id int PRIMARY KEY, "name" varchar, age int );INSERT INTO public.user1 (id, "name", age) VALUES(null, 'Иван', 10); select * from public.user1
INSERT INTO public.user2 (id, "name", age) VALUES(null, 'Иван', 10); 
3. Можно ли использовать первичный ключ и ограничение уникальности вместе (т. е. для одного столбца установить два ограничения)?
CREATE TABLE public.user3 ( id int PRIMARY KEY UNIQUE, "name" varchar, age int );
4. Можно ли сделать связь с ограничением уникальности?
CREATE TABLE public.user1 ( id int UNIQUE, "name" varchar, age int );CREATE TABLE public.order ( id int, order_number varchar, user_id int references public.user1(id), sum float );

Технически можно условно связать таблицы, без references, на уровне кода. Т. е. не создавая в БД внешние ключи. Но тогда программист берет на себя заботу следить за связями и целостностью данных программно. Без создания внешних ключей в БД можно породить хаос в данных. В идеале за связями нужно следить с двух сторон: и в программе, и в БД. Но только БД позволит не довести до беды и вовремя сигнализировать о возможной ошибке. В данном вопросе мы рассматриваем связи именно на уровне БД.5. Можно ли в одной таблице (разных полях) использовать первичный ключ и ограничение уникальности? Может ли ограничение уникальности включать несколько столбцов?
CREATE TABLE public.user4 ( id int PRIMARY KEY, "name" varchar, series_passport varchar UNIQUE NOT NULL, number_passport varchar UNIQUE NOT NULL, age int );CREATE TABLE public.user5 ( id int PRIMARY KEY, "name" varchar, series_passport varchar, number_passport varchar, age int, UNIQUE (series_passport, number_passport) );

6. Сколько первичных ключей может иметь таблица?

7. Сколько ограничений уникальности может иметь таблица?
8. Может ли быть разное число столбцов и типы данных полей у внешнего ключа и первичного (или внешнего ключа и UNIQUE)?

9. Могут ли на одном столбце быть установлены и первичный и внешний ключи?
CREATE TABLE public.user_new ( id int PRIMARY KEY, "name" varchar, age int ); CREATE TABLE public.product ( id int PRIMARY KEY, "name" varchar, price float );CREATE TABLE public.review ( user_id int REFERENCES public.user_new(id), product_id int REFERENCES public.product(id) , "text" varchar, grade int, PRIMARY KEY (user_id,product_id) );
ссылка на оригинал статьи https://habr.com/ru/articles/787374/
Добавить комментарий