В этой статье разберём основы SQL на примере PostgreSQL 16 версии. А именно как создаются или удаляются базы данных и таблицы в них. Также изучим типы данных в PostgreSQL, первичный и внешний ключ, и другие ограничения целостности.
Создание базы данных
В этой статье я использую PostgreSQL 16 установленный на Debian 12. Для начала необходимо подключиться к консоли СУБД. Я это делаю с помощью утилиты psql, о которой я писал в статье Утилита psql для работы с PostgreSQL.
sudo -u postgres psql
Чтобы создать базу данных используется команда CREATE DATABASE. Создадим базу данных it_outsourcing:
CREATE DATABASE it_outsourcing;
Переключимся на эту базу данных. Для этого используем не SQL команду а встроенную команду утилиты psql \c (все такие команды начинаются на обратный слеш и после команды не нужно использовать точку с запятой):
\c it_outsourcing
Работа с таблицами
Создание таблицы
Основной элемент из которых состоит реляционная база данных — это таблицы. Для создания таблицы используется команда CREATE TABLE. Например создадим таблицу users для хранения списка пользователей, которых мы обслуживаем. В эту таблицу будем заносить ФИО пользователя, название его компании, его номер телефона и электронную почту. Вот как это делается:
CREATE TABLE users (fio text, company text, phone varchar(11), email text );
Из примера видно что мы указываем имя поля (fio, company, phone, email), а затем тип данных для этого поля. Типы данных, которые можно использовать, мы рассмотрим ниже в этой статье.
Наполнение таблицы строками
Строки вставляются в таблицу с помощью команды INSERT INTO. Можно вставлять по одной строке или по несколько. Вставим три строки в нашу таблицу users (все телефоны и email из примера вымышленные.):
INSERT INTO users (fio, company, phone, email)
VALUES ('Иванов Иван Алексеевич', 'ООО "Ромашка"', '89057362761', 'ivanov@mail.ru'),
('Донченко Иван Андреевич', 'ООО "Ромашка"', '89038276494', 'dota@yandex.ru'),
('Девин Алексей Владимирович', 'ООО "Начало"', '89069384782', 'test@yandex.ru');
Как видно из примера выше, мы вначале определяем порядок колонок (fio, company, phone, email), а затем в этом порядке вставляем значения. При вставке строковых значений, строка всегда берётся в одинарные кавычки.
Просмотр таблицы
Посмотреть на созданную таблицу можно с помощью команды SELECT. Например выведем все поля и строки в таблице с помощью звёздочки (*):
SELECT * FROM users;
Вывод:
fio | company | phone | email ----------------------------+---------------+-------------+---------------- Иванов Иван Алексеевич | ООО "Ромашка" | 89057362761 | ivanov@mail.ru Донченко Иван Андреевич | ООО "Ромашка" | 89038276494 | dota@yandex.ru Девин Алексей Владимирович | ООО "Начало" | 89069384782 | test@yandex.ru (3 строки)
Можно вывести определённые колонки указав их вместо звездочки:
SELECT fio, phone FROM users;
Вывод:
fio | phone ----------------------------+------------- Иванов Иван Алексеевич | 89057362761 Донченко Иван Андреевич | 89038276494 Девин Алексей Владимирович | 89069384782 (3 строки)
Можно вывести определённые строки с помощью WHERE <условие>. Например выведем всех сотрудников у которых в поле company указано ООО «Ромашка»:
SELECT * FROM users WHERE company = 'ООО "Ромашка"';
Вывод:
fio | company | phone | email -------------------------+---------------+-------------+---------------- Иванов Иван Алексеевич | ООО "Ромашка" | 89057362761 | ivanov@mail.ru Донченко Иван Андреевич | ООО "Ромашка" | 89038276494 | dota@yandex.ru (2 строки)
В качестве условия можем указать, что значение в определённой колонке должно:
- чему-то равняется —
column = 'строка'; - быть больше или меньше определённого значения —
column > 60000; - содержать что-то —
column LIKE '%word%'.%– означает любую последовательность символов до и после искомого слова.
Можем комбинировать какие колонки и строки выводить, например:
SELECT fio, phone FROM users WHERE company = 'ООО "Ромашка"';
Вывод:
fio | phone -------------------------+------------- Иванов Иван Алексеевич | 89057362761 Донченко Иван Андреевич | 89038276494 (2 строки)
А ещё можем отсортировать таблицу по какой-нибудь строке:
SELECT fio, phone FROM users ORDER BY fio;
Вывод:
fio | phone ----------------------------+------------- Девин Алексей Владимирович | 89069384782 Донченко Иван Андреевич | 89038276494 Иванов Иван Алексеевич | 89057362761 (3 строки)
Условий может быть несколько, например ФИО должно содержать Иван (%Иван%), а телефон должен заканчиваться на 94 (%94), для этого используется оператор AND или OR:
SELECT * FROM users WHERE fio LIKE '%Иван%'AND phone LIKE '%94';
Вывод:
fio | company | phone | email -------------------------+---------------+-------------+---------------- Донченко Иван Андреевич | ООО "Ромашка" | 89038276494 | dota@yandex.ru (1 строка)
Изменение строк
Строки в таблице можно обновить, или другими словами изменить. Изменяют строки с помощью команды UPDATE. Например изменим номер телефона Иванову Ивану Алексеевичу:
UPDATE users SET phone = '89057362744' WHERE fio = 'Иванов Иван Алексеевич';
Если не указать условие, то обновятся все строки (всех сотрудников).
Удаление строк
Для удаления строк используют команду DELETE FROM. Например:
DELETE FROM users WHERE fio = 'Донченко Иван Андреевич';
Если не указать блок WHERE, то удалятся все строки! Но очищать таблицу лучше другой командой.
Очистка таблицы
Очистка таблицы осуществляется с помощью команды TRUNCATE. Например:
TRUNCATE users;
Посмотрим что у нас получилось:
SELECT * FROM users;
Вывод:
fio | company | phone | email -----+---------+-------+------- (0 строк)
Удаление таблицы
Для удаления таблицы используем команду DROP TABLE.
DROP TABLE users;
Удаление базы данных
А чтобы удалить базу данных выполняем DROP DATABASE. Но предварительно нужно отключиться от удаляемой базы:
\c postgres DROP DATABASE it_outsourcing;
Типы данных в PostgreSQL
Каждая колонка в таблице имеет свой тип и может хранить только определённые данные. В PostgreSQL все типы данных можете посмотреть здесь. Я рассмотрю лишь некоторые.
Числовые типы:
- integer — целое число.
- numeric(m, n) — вещественное число, где m общее количество цифр, n количество цифр после запятой.
- real — число с плавающей точкой (6 цифр после точки). Точность меньше, но вычисления быстрее чем у numeric.
- serial — целое число которое автоматически увеличивается для каждой новой строки.
- money — тип данных для хранения денежной суммы. Две цифры после запятой. После числа добавляется знак денежной единицы.
Строки:
- varchar(n) — строка переменной длины, но не длиннее «n».
- char(n) — строка фиксированной длины, длинной «n».
- text — строка неограниченной и переменной длины.
Дата и время:
- timestamp — дата и время, пример
2025-07-13 14:21:41. - timestamptz — дата и время с часовым поясом, пример
2025-07-13 14:21:41+03. - date — дата, пример
2025-07-13. - time — время, пример
14:21:41.
Логический тип:
- boolean — true или false.
Сетевые адреса:
- inet — Узлы и сети IPv4 и IPv6, пример
192.168.0.1/24. - cidr — Сети IPv4 и IPv6, пример
192.168.0.0/24. - macaddr — MAC-адреса, пример
'08:00:2b:01:02:03'. - macaddr8 — MAC-адреса (в формате EUI-64), пример
'08:00:2b:01:02:03:04:05'.
Уникальный идентификатор:
- uuid — 128-битное значение, генерируемое специальной функцией (
gen_random_uuid ()), примерa0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11.
Существуют и другие типы, например для хранения двоичных данных, json, массивов, xml и другой информации.
Первичный и внешний ключ SQL
Первичный ключ — это одно или несколько полей в таблице, которые необходимы для уникальной идентификации любой строки. Он накладывает ограничения:
- Все записи относящиеся к первичному ключу должны быть уникальны.
- Если первичный ключ состоит из одного поля, то все записи в нём должны быть уникальными.
- Если он состоит из нескольких полей, то комбинация этих записей должна быть уникальна.
- Записи в полях первичного ключа не могут быть пустыми (not null).
- В каждой таблице может присутствовать только один первичный ключ.
Первичный ключ может быть:
- естественным — существует в реальном мире, например ФИО;
- суррогатным — не существует в реальном мире, например порядковый номер.
Специалисты по базам данных говорят что лучше использовать естественный первичный ключ.
Основная задача первичного ключа — это уникальная идентификация каждой строки. Вторичная задача — связь нескольких таблиц. В одной из таблиц создают внешний ключ, который ссылается на первичный ключ другой таблицы.
Таблица Ученики (pupils):
| ФИО full_name | Возраст age | Класс class |
| Иванов Иван Иванович | 15 | 9А |
| Сумкин Фёдор Андреевич | 15 | 9А |
| Петров Алексей Николаевич | 14 | 8Б |
| Булгаков Александр Геннадьевич | 14 | 8Б |
Таблица Успеваемость (evaluations):
| Предмет item | ФИО full_name | Оценка evaluation |
| Русский язык | Иванов Иван Иванович | 4 |
| Русский язык | Петров Алексей Николаевич | 5 |
| Математика | Булгаков Александр Геннадьевич | 3 |
| Литература | Сумкин Фёдор Андреевич | 5 |
В обоих таблицах есть поле: ФИО. При этом в таблице Успеваемость не может содержаться ФИО, которого нет в таблице Ученики. Нельзя поставить ученику оценку, которого не существует.
Первичным ключом в этом случае может выступать поле ФИО в таблице Ученики. А внешним ключом будет ФИО в таблице Успеваемость. А если мы удаляем запись о каком-то ученике из таблицы Ученики, то все его оценки тоже должны удалиться из таблицы Успеваемость.
Стоит заметить что первичный ключ в PostgreSQL автоматически создает индекс. Который ускоряет доступ к строкам таблицы и накладывает ограничение на уникальность. То есть двух Ивановых Иванов Ивановичей у нас не может существовать. Чтобы это обойти можно использовать:
- Составной первичный ключ — в качестве первичного ключа взять поля: ФИО и Класс.
- Суррогатный первичный ключ — в таблице Ученики добавить поле № Ученика и сделать это поле первичным ключом.
- Добавить более уникальное поле — можно использовать номер зачетной книжки как первичный ключ.
Практика работы с первичным и внешним ключом
Создадим эти две таблицы и поработаем с ними. Для начала создадим базу данных school и подключимся к ней, затем создадим таблицу pupils:
CREATE DATABASE school; \c school CREATE TABLE pupils (full_name text, age integer, class varchar(3), PRIMARY KEY (full_name) );
Как вы могли заметить, первичный ключ создаётся с помощью конструкции PRIMARY KEY (имя_поля) в момент создания таблицы.
Затем посмотрим на табличку с помощью команды psql \d:
\d pupils
Вывод:
Таблица "public.pupils"
Столбец | Тип | Правило сортировки | Допустимость NULL | По умолчанию
-----------+----------------------+--------------------+-------------------+--------------
full_name | text | | not null |
age | integer | | |
class | character varying(3) | | |
Индексы:
"pupils_pkey" PRIMARY KEY, btree (full_name)
Вывод показал, что у нас в таблице есть первичный ключ, который сделал два ограничения:
- поле full_name не может быть пустым (not null);
- для поля full_name был создан индекс pupils_pkey с типом btree. А индекс наложил ещё одно ограничение — записи в поле full_name должны быть уникальны.
Дальше создадим таблицу evaluations:
CREATE TABLE evaluations (item text, full_name text, evaluation integer, FOREIGN KEY (full_name) REFERENCES pupils ON DELETE CASCADE );
Внешний ключ создается с помощью конструкции FOREIGN KEY (имя_поля) REFERENCES таблица_на_которую_ссылаются. Создавая внешний ключ мы дополнительно указали опцию ON DELETE CASCADE. Это означает, что при удалении строки с определённым учеником в таблице pupils, все строки связанные с этим учеником удалятся и в таблице evaluations автоматически.
И посмотри на структуру этой таблицы:
\d evaluations
Вывод:
Таблица "public.evaluations"
Столбец | Тип | Правило сортировки | Допустимость NULL | По умолчанию
------------+---------+--------------------+-------------------+--------------
item | text | | |
full_name | text | | |
evaluation | integer | | |
Ограничения внешнего ключа:
"evaluations_full_name_fkey" FOREIGN KEY (full_name) REFERENCES pupils(full_name) ON DELETE CASCADE
Здесь видно, что создался внешний ключ (Foreign-key), который относится к полю full_name и ссылается на таблицу pupils.
Заполним таблицы строками:
INSERT into pupils (full_name, age, class)
VALUES ('Иванов Иван Иванович', 15, '9A'),
('Сумкин Фёдор Андреевич', 15, '9A'),
('Петров Алексей Николаевич', 14, '8B'),
('Булгаков Александр Геннадьевич', 14, '8B');
INSERT into evaluations (item, full_name, evaluation)
VALUES ('Русский язык', 'Иванов Иван Иванович', 4),
('Русский язык', 'Петров Алексей Николаевич', 5),
('Математика', 'Булгаков Александр Геннадьевич', 3),
('Литература', 'Сумкин Фёдор Андреевич', 5);
Попробуем поставить оценку не существующему ученику:
INSERT into evaluations (item, full_name, evaluation)
VALUES ('Русский язык', 'Угаров Виктор Михайлович', 3);
Вывод:
ОШИБКА: INSERT или UPDATE в таблице "evaluations" нарушает ограничение внешнего ключа "evaluations_full_name_fkey" ПОДРОБНОСТИ: Ключ (full_name)=(Угаров Виктор Михайлович) отсутствует в таблице "pupils".
Как видите, мы получили ошибку. Вставлять (insert) или изменять (update) в таблице evaluations, в поле full_name можно только те значения, которые есть в этом же поле в таблице pupils.
Теперь удалим какого-нибудь ученика из таблицы pupils:
delete from pupils WHERE full_name = 'Иванов Иван Иванович';
И посмотрим на строки в таблице evaluations:
SELECT * FROM evaluations;
Вывод:
item | full_name | evaluation --------------+--------------------------------+------------ Русский язык | Петров Алексей Николаевич | 5 Математика | Булгаков Александр Геннадьевич | 3 Литература | Сумкин Фёдор Андреевич | 5 (3 строки)
Строка с full_name равная ‘Иванов Иван Иванович’ тоже удалилась. Если бы у Иванова было бы больше оценок, они все бы удалились. За это отвечает опция ON DELETE CASCADE.
Попробуем теперь создать ученика с точно таким-же ФИО, как у одного из существующих:
INSERT into pupils (full_name, age, class)
VALUES ('Петров Алексей Николаевич',15, '5B');
Вывод:
ОШИБКА: повторяющееся значение ключа нарушает ограничение уникальности "pupils_pkey" ПОДРОБНОСТИ: Ключ "(full_name)=(Петров Алексей Николаевич)" уже существует.
Ничего не вышло, так как такая запись уже существует в поле full_name, а это поле у нас имеет индекс. Значит значения в нём должны быть уникальными.
Составной первичный ключ
Есть большая вероятность, что в одной школе будут учиться два ученика с одинаковым ФИО. Но меньше вероятности что эти два ученика будут учиться в одном классе. Поэтому в качестве первичного ключа мы можем взять два поля, например full_name и class.
Давайте удалим наши таблички и создадим их заново, но теперь создадим их используя составной первичный ключ:
DROP table evaluations; DROP table pupils; CREATE TABLE pupils (full_name text, age integer, class varchar(3), PRIMARY KEY (full_name, class) ); CREATE TABLE evaluations (item text, full_name text, class varchar(3), evaluation integer, FOREIGN KEY (full_name, class) REFERENCES pupils ON DELETE CASCADE );
Как вы могли заметить, разница не большая. Мы должны в PRIMARY KEY указать два поля вместо одного. И в FOREIGN KEY точно также указать два поля вместо одного. Ну и не забудьте в таблице evaluations при создании добавить поле class, так как его там в предыдущем варианте не было.
Теперь посмотрим на структуры этих таблиц:
\d pupils
Вывод:
Таблица "public.pupils"
Столбец | Тип | Правило сортировки | Допустимость NULL | По умолчанию
-----------+----------------------+--------------------+-------------------+--------------
full_name | text | | not null |
age | integer | | |
class | character varying(3) | | not null |
Индексы:
"pupils_pkey" PRIMARY KEY, btree (full_name, class)
Ссылки извне:
TABLE "evaluations" CONSTRAINT "evaluations_full_name_class_fkey" FOREIGN KEY (full_name, class) REFERENCES pupils(full_name, class) ON DELETE CASCADE
\d evaluations
Вывод:
Таблица "public.evaluations"
Столбец | Тип | Правило сортировки | Допустимость NULL | По умолчанию
------------+----------------------+--------------------+-------------------+--------------
item | text | | |
full_name | text | | |
class | character varying(3) | | |
evaluation | integer | | |
Ограничения внешнего ключа:
"evaluations_full_name_class_fkey" FOREIGN KEY (full_name, class) REFERENCES pupils(full_name, class) ON DELETE CASCADE
Первичный ключ в таблице pupils уже состоит из двух полей, поэтому внешний ключ ссылается на эти два поля.
Теперь мы можем учеников с одинаковым ФИО вбить в нашу базу данных, но при условии что они будут учиться в разных классах:
INSERT INTO pupils (full_name, age, class)
VALUES ('Гришина Ольга Константиновна', 12, '5A'),
('Гришина Ольга Константиновна', 14, '7B');
SELECT * FROM pupils;
Вывод:
full_name | age | class ------------------------------+-----+------- Гришина Ольга Константиновна | 12 | 5A Гришина Ольга Константиновна | 14 | 7B (2 строки)
И также по второй таблице:
INSERT INTO evaluations (item, full_name, class, evaluation)
VALUES ('Русский язык', 'Гришина Ольга Константиновна', '5A', 5),
('Русский язык', 'Гришина Ольга Константиновна', '7B', 3);
SELECT * FROM evaluations;
Вывод:
item | full_name | class | evaluation --------------+------------------------------+-------+------------ Русский язык | Гришина Ольга Константиновна | 5A | 5 Русский язык | Гришина Ольга Константиновна | 7B | 3 (2 строки)
Удаление связанных таблиц
Кстати, удалить таблицу, на которую ссылается другая таблица вы не сможете:
DROP table pupils;
ОШИБКА: удалить объект таблица pupils нельзя, так как от него зависят другие объекты ПОДРОБНОСТИ: ограничение evaluations_full_name_class_fkey в отношении таблица evaluations зависит от объекта таблица pupils ПОДСКАЗКА: Для удаления зависимых объектов используйте DROP ... CASCADE.
Удалить таблицы можно в следующем порядке (если повторяете за мной, пока не удаляйте, я покажу каскадное удаление ниже):
DROP table evaluations; DROP table pupils;
Либо мы могли удалить каскадно таблицу pupils вместе с внешним ключом у таблицы evaluations:
DROP TABLE pupils CASCADE;
После каскадного удаления у нас вместе с таблицей pupils удаляется внешний ключ в таблице evaluations.
\d evaluations
Вывод:
Таблица "public.evaluations" Столбец | Тип | Правило сортировки | Допустимость NULL | По умолчанию ------------+----------------------+--------------------+-------------------+-------------- item | text | | | full_name | text | | | class | character varying(3) | | | evaluation | integer | | |
То есть таблица evaluations больше не ссылается на таблицу pupils.
Создание связи в уже существующих таблицах
Выше я создавал первичный и внешний ключи при создании таблицы, но их можно создавать и для существующих таблиц.
Вначале удалим оставшуюся таблицу:
DROP table evaluations;
И сделаем таблицы без ключей:
CREATE TABLE pupils (full_name text, age integer, class varchar(3) ); CREATE TABLE evaluations (item text, full_name text, class varchar(3), evaluation integer );
Создать первичный и внешний ключи можно с помощью команды ALTER. Создадим первичный ключ в таблице pupils:
ALTER TABLE pupils ADD PRIMARY KEY (full_name, class);
И создадим внешний ключ в таблице evaluations:
ALTER TABLE evaluations ADD FOREIGN KEY (full_name, class) REFERENCES pupils ON DELETE CASCADE;
Посмотрим что у нас получилось:
\d pupils
Вывод:
Таблица "public.pupils"
Столбец | Тип | Правило сортировки | Допустимость NULL | По умолчанию
-----------+----------------------+--------------------+-------------------+--------------
full_name | text | | not null |
age | integer | | |
class | character varying(3) | | not null |
Индексы:
"pupils_pkey" PRIMARY KEY, btree (full_name, class)
Ссылки извне:
TABLE "evaluations" CONSTRAINT "evaluations_full_name_class_fkey" FOREIGN KEY (full_name, class) REFERENCES pupils(full_name, class) ON DELETE CASCADE
\d evaluations
Вывод:
Таблица "public.evaluations"
Столбец | Тип | Правило сортировки | Допустимость NULL | По умолчанию
------------+----------------------+--------------------+-------------------+--------------
item | text | | |
full_name | text | | |
class | character varying(3) | | |
evaluation | integer | | |
Ограничения внешнего ключа:
"evaluations_full_name_class_fkey" FOREIGN KEY (full_name, class) REFERENCES pupils(full_name, class) ON DELETE CASCADE
Ограничения целостности в SQL
Ограничение целостности SQL, это определённое требование для полей в таблице SQL. За соблюдение этих требований отвечает сама СУБД.
Например:
- Тип данных накладывает некоторое ограничение. Нельзя в поле с типом integer вставить текстовую строку. Но для некоторых типов можно ещё ужесточить правила:
- для типа char и varchar можно указать максимальную длину строки. Например, в поле vaechar(4) нельзя будет вставить строку из пяти символов.
- Первичный ключ сразу накладывает несколько ограничений, хотя их можно наложить и по-отдельности:
- записи должны быть уникальны (unique);
- записи не могут быть пустыми (not null).
- Есть определённые проверки (check). С их помощью можно наложить дополнительные ограничения. Например, для цифрового значения можно указать что число должно быть больше 50, но меньше 200. Или поле, которое хранит пол человека, может принимать только два значения: М или Ж.
В документации об ограничениях можете почитать здесь.
Про типы данных и о первичном ключе я писал выше. Пришло время познакомиться с check проверками. А также я покажу как создаются ограничения unique и not null.
Создание таблицы с ограничениями целостности
Для теста создадим новую базу данных и подключимся к ней:
CREATE DATABASE check_constraint; \c check_constraint
Создадим таблицу staff (сотрудники):
| Название | Описание | Тип данных | Ограничения ( NOT NULL, UNIQUE ) | Ограничения (CHECK) |
| number | номер | serial | NOT NULL, UNIQUE | |
| fullname | фио | varchar (50) | NOT NULL | |
| sex | пол | char (1) | NOT NULL | Может быть только «М» или «Ж» |
| age | возраст | integer | NOT NULL | От 18 до 100 (я думаю больше 100 лет сотруднику не может быть) |
| experience | стаж | integer | NOT NULL | Стаж должен быть меньше возраста |
Создаём таблицу:
CREATE TABLE staff
(number serial NOT NULL UNIQUE,
fullname varchar(50) NOT NULL,
sex char(1) NOT NULL, CHECK ( sex IN ('М', 'Ж')),
age integer NOT NULL, CHECK ( age > 18 AND age < 100),
experience integer NOT NULL, CHECK ( experience < age)
);
И посмотрим на то, что у нас получилось:
\d staff
Вывод:
Таблица "public.staff"
Столбец | Тип | Правило сортировки | Допустимость NULL | По умолчанию
------------+-----------------------+--------------------+-------------------+---------------------------------------
number | integer | | not null | nextval('staff_number_seq'::regclass)
fullname | character varying(50) | | not null |
sex | character(1) | | not null |
age | integer | | not null |
experience | integer | | not null |
Индексы:
"staff_number_key" UNIQUE CONSTRAINT, btree (number)
Ограничения-проверки:
"staff_age_check" CHECK (age > 18 AND age < 100)
"staff_check" CHECK (experience < age)
"staff_sex_check" CHECK (sex = ANY (ARRAY['М'::bpchar, 'Ж'::bpchar]))
Попробуем создать 15 летнего сотрудника:
INSERT INTO staff (fullname, sex, age, experience)
VALUES ('Иванов Иван Алексеевич', 'М', 15, 10);
Вывод:
ОШИБКА: новая строка в отношении "staff" нарушает ограничение-проверку "staff_age_check" ПОДРОБНОСТИ: Ошибочная строка содержит (1, Иванов Иван Алексеевич, М, 15, 10).
Как видно из ошибки, сработало ограничение staff_age_check.
А 20 летний создастся нормально:
INSERT INTO staff (fullname, sex, age, experience)
VALUES ('Иванов Иван Алексеевич', 'М', 20, 10);
А что будет, если ошибёмся с полом:
INSERT INTO staff (fullname, sex, age, experience)
VALUES ('Донченко Иван Андреевич', 'К', 25, 8);
Вывод:
ОШИБКА: новая строка в отношении "staff" нарушает ограничение-проверку "staff_sex_check" ПОДРОБНОСТИ: Ошибочная строка содержит (2, Донченко Иван Андреевич, К, 25, 8).
Здесь уже сработало ограничение staff_sex_check.
Если мы что-то забудем указать, то сработает ограничение NOT NULL:
INSERT INTO staff (fullname, sex, age)
VALUES ('Донченко Иван Андреевич', 'Ж', 25);
Вывод:
ОШИБКА: значение NULL в столбце "experience" отношения "staff" нарушает ограничение NOT NULL ПОДРОБНОСТИ: Ошибочная строка содержит (3, Донченко Иван Андреевич, Ж, 25, null).
И наконец введем второго пользователя в базу:
INSERT INTO staff (fullname, sex, age, experience)
VALUES ('Донченко Иван Андреевич', 'М', 25, 8);
А теперь посмотрим на табличку:
SELECT * FROM staff;
Вывод:
number | fullname | sex | age | experience
--------+-------------------------+-----+-----+------------
2 | Иванов Иван Алексеевич | М | 20 | 10
5 | Донченко Иван Андреевич | М | 25 | 8
(2 строки)
Как вы могли заметить последовательность постоянно растёт, даже если мы ошибаемся при вставке. Поэтому у нас в поле number вначале 2, а затем 5.
Создание ограничения для существующей таблицы
Выше я показал как добавлять ограничения для полей при создании таблицы. Но добавлять или удалять ограничения можно с помощью команды ALTER уже на существующих таблица.
Добавить или удалить ограничение целостности NOT NULL:
ALTER TABLE staff ALTER COLUMN number SET NOT NULL; ALTER TABLE staff ALTER COLUMN number DROP NOT NULL;
Ограничения целостности UNIQUE удаляются с помощью DROP CONSTRAINT, а добавляется с помощью ADD CONSTRAINT:
ALTER TABLE staff DROP CONSTRAINT staff_number_key; ALTER TABLE staff ADD CONSTRAINT staff_number_key UNIQUE (number);
Кстати, при удалении ограничения целостности UNIQUE удаляется и индекс.
Ограничения целостности CHECK создаются и удаляются подобным способом:
ALTER TABLE staff DROP CONSTRAINT staff_age_check; ALTER TABLE staff ADD CONSTRAINT staff_age_check CHECK (age > 18 AND age < 100);
При этом названия ограничения (staff_number_key, staff_age_check) вы придумываете сами.
Если понравилась статья, подпишись на мой канал в VK или Telegram.