Типы Данных и Ограничения

С возвращением.
В предыдущем уроке ты изучил базовые SQL-действия:
SELECT;INSERT;UPDATE;DELETE.
Ты научился читать данные.
Добавлять данные.
Изменять данные.
Удалять данные.
Очень мощно.
И немного опасно.
Сегодня мы научимся делать таблицы безопаснее.
Потому что база данных не должна принимать всё подряд.
Если колонка предназначена для возраста, она не должна принимать:
banana
Если email должен быть уникальным, PostgreSQL должен остановить двух пользователей от использования одного и того же email.
Если имя обязательно, PostgreSQL не должен позволять загадочным пустым людям заходить в таблицу.
Именно здесь помогают типы данных и ограничения.
Типы данных определяют, какой тип данных может хранить колонка.
Ограничения определяют правила, которым данные должны следовать.
Вместе они делают базу данных сильнее.
Как серьёзный охранник.
Но с точками с запятой.
Что Ты Изучишь
В этом уроке ты изучишь:
- что такое типы данных;
- почему типы данных важны;
- как использовать
INTEGER; - как использовать
VARCHAR; - как использовать
TEXT; - как использовать
BOOLEAN; - как использовать
DATE; - как использовать
NUMERIC; - что такое ограничения;
- как использовать
NOT NULL; - как использовать
UNIQUE; - как использовать
DEFAULT; - как использовать
CHECK; - как создавать более безопасные таблицы;
- как PostgreSQL защищает твои данные от хаоса.
В конце этого урока ты будешь понимать, как проектировать таблицы, которые не принимают ерунду.
Это важно.
Потому что плохие данные — как блёстки.
Если они один раз попали в систему, они появляются везде.
Навсегда.
Что Такое Типы Данных?
Тип данных говорит PostgreSQL, какой тип значения может хранить колонка.
Пример:
CREATE TABLE students (
id SERIAL PRIMARY KEY,
name VARCHAR(100),
age INTEGER
);
Здесь:
name VARCHAR(100)
означает, что колонка name хранит текст.
А:
age INTEGER
означает, что колонка age хранит целые числа.
То есть PostgreSQL понимает:
name = текст
age = число
Это полезно, потому что PostgreSQL может отклонить неправильные данные.
Если ты попробуешь вставить текст в колонку INTEGER, PostgreSQL будет протестовать.
И правильно.
Базы данных должны протестовать, когда приходит ерунда.
Тишина опасна.
Особенно в базах данных.
И на кухнях.
Почему Типы Данных Важны
Представь такую таблицу:
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name TEXT,
age TEXT
);
Технически age здесь текст.
Поэтому PostgreSQL может разрешить такое:
INSERT INTO users (name, age)
VALUES ('Anna', 'twenty two');
Или даже такое:
INSERT INTO users (name, age)
VALUES ('Marco', 'banana');
Это плохо.
Возраст должен быть числом.
Лучше:
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name TEXT,
age INTEGER
);
Теперь PostgreSQL ожидает число для age.
Это защищает твои данные.
Хорошая структура блокирует глупые данные ещё до входа в таблицу.
PostgreSQL фактически говорит:
Сегодня без банановых возрастов.
Прекрасно.
Популярные Типы Данных в PostgreSQL
PostgreSQL имеет много типов данных.
Сегодня мы изучим самые полезные для начинающих:
INTEGER;VARCHAR;TEXT;BOOLEAN;DATE;NUMERIC;SERIAL.
Этого достаточно для многих beginner-проектов.
Позже ты можешь изучить более advanced типы.
У PostgreSQL их много.
Потому что PostgreSQL посмотрел на данные и сказал:
Да, я могу всё это организовать.
Очень амбициозно.
Очень полезно.
INTEGER
INTEGER хранит целые числа.
Пример:
age INTEGER
Хорошие значения:
18
25
100
Плохие значения:
hello
25.5
banana
Пример таблицы:
CREATE TABLE players (
id SERIAL PRIMARY KEY,
name VARCHAR(100),
score INTEGER
);
Вставь данные:
INSERT INTO players (name, score)
VALUES ('Anna', 100);
Это работает.
А это нет:
INSERT INTO players (name, score)
VALUES ('Marco', 'very good');
Потому что score ожидает число.
PostgreSQL отказывает.
И правильно делает.
База данных без стандартов — это просто электронная таблица с амбициями.
VARCHAR
VARCHAR хранит текст с максимальной длиной.
Пример:
name VARCHAR(100)
Это означает:
Имя может содержать максимум 100 символов.
Пример:
CREATE TABLE products (
id SERIAL PRIMARY KEY,
name VARCHAR(100),
category VARCHAR(50)
);
Это хорошо для текстовых полей, где нужен разумный лимит.
Например:
- имена;
- названия;
- email;
- категории;
- короткие метки.
Если ты попробуешь вставить текст длиннее лимита, PostgreSQL его отклонит.
Хорошо.
Иногда лимиты полезны.
Особенно для колонок базы данных.
И, возможно, для порций пиццы.
TEXT
TEXT хранит длинный текст.
Пример:
description TEXT
Используй TEXT, когда тебе не нужен строгий лимит символов.
Хорошо подходит для:
- описаний;
- содержания статей;
- комментариев;
- заметок;
- длинных сообщений.
Пример:
CREATE TABLE articles (
id SERIAL PRIMARY KEY,
title VARCHAR(150),
content TEXT
);
Здесь:
title VARCHAR(150)
имеет лимит.
А:
content TEXT
может быть длинным.
Это логично.
Название не должно быть романом.
А поле content может им быть.
PostgreSQL практичен.
В основном.
BOOLEAN
BOOLEAN хранит значения true или false.
Пример:
available BOOLEAN
Хорошие значения:
true
false
Пример таблицы:
CREATE TABLE tasks (
id SERIAL PRIMARY KEY,
title VARCHAR(150),
completed BOOLEAN
);
Вставь данные:
INSERT INTO tasks (title, completed)
VALUES ('Learn PostgreSQL', false);
Позже можно обновить:
UPDATE tasks
SET completed = true
WHERE title = 'Learn PostgreSQL';
BOOLEAN идеально подходит для значений да/нет:
- active;
- completed;
- available;
- published;
- verified.
Не храни это как текст:
yes
no
maybe
sort of
Там начинается хаос.
Используй BOOLEAN.
Позволь базе данных помочь тебе.
DATE
DATE хранит календарные даты.
Пример:
birth_date DATE
Вставь дату так:
'1992-10-23'
PostgreSQL любит формат:
YYYY-MM-DD
Пример таблицы:
CREATE TABLE events (
id SERIAL PRIMARY KEY,
title VARCHAR(150),
event_date DATE
);
Вставь данные:
INSERT INTO events (title, event_date)
VALUES ('PostgreSQL Practice', '2026-05-03');
Даты должны быть датами.
Не текстом.
Не случайными строками.
Не “следующая пятница, наверное”.
PostgreSQL может нормально работать с датами только тогда, когда ты хранишь их как даты.
Шок.
Но правда.
NUMERIC
NUMERIC хранит точные десятичные числа.
Это полезно для денег.
Пример:
price NUMERIC(10, 2)
Это означает:
До 10 цифр всего, с 2 цифрами после десятичной точки.
Примеры значений:
49.99
100.00
1250.50
Пример таблицы:
CREATE TABLE courses (
id SERIAL PRIMARY KEY,
title VARCHAR(150),
price NUMERIC(10, 2)
);
Вставь данные:
INSERT INTO courses (title, price)
VALUES ('PostgreSQL Basics', 49.99);
Для цен NUMERIC обычно лучше, чем INTEGER.
Разве что ты хранишь центы как целые числа.
Это тоже нормальный подход.
Но для начинающих NUMERIC(10, 2) легко понять.
Деньги заслуживают точности.
Особенно когда они уходят с твоего счёта.
SERIAL
SERIAL создаёт автоматически растущее целое число.
Пример:
id SERIAL PRIMARY KEY
Это означает, что PostgreSQL автоматически генерирует ID.
Пример:
CREATE TABLE students (
id SERIAL PRIMARY KEY,
name VARCHAR(100)
);
Вставь данные без id:
INSERT INTO students (name)
VALUES ('Anna');
PostgreSQL автоматически даст Anna ID.
Потом следующая строка получит следующий ID.
И так далее.
Очень полезно.
Не управляй ID вручную, если PostgreSQL может сделать это за тебя.
Жизнь и так сложная.
Пусть база данных считает.
Что Такое Ограничения?
Ограничения — это правила для данных в таблице.
Они говорят PostgreSQL:
Это значение обязательно.
Это значение должно быть уникальным.
Это значение должно соответствовать условию.
Это значение имеет default.
Популярные ограничения:
PRIMARY KEY;NOT NULL;UNIQUE;DEFAULT;CHECK.
Ограничения делают таблицы безопаснее.
Они останавливают плохие данные до того, как те попадут в таблицу.
Думай об ограничениях как о правилах таблицы.
Например:
Без пустых имён.
Без дублированных email.
Без отрицательных цен.
Без невозможного возраста.
Очень разумно.
PostgreSQL строгий.
Но здесь строгость — это хорошо.
NOT NULL
NOT NULL означает, что колонка обязательная.
Пример:
name VARCHAR(100) NOT NULL
Это означает, что каждая строка должна иметь имя.
Пример таблицы:
CREATE TABLE customers (
id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
email VARCHAR(150)
);
Это работает:
INSERT INTO customers (name, email)
VALUES ('Anna', 'anna@example.com');
Это не работает:
INSERT INTO customers (email)
VALUES ('no-name@example.com');
Потому что name обязательно.
Хорошо.
Никаких загадочных customers без имён.
Это не база данных шпионов.
Наверное.
UNIQUE
UNIQUE означает, что значения в колонке не могут повторяться.
Очень полезно для email.
Пример:
email VARCHAR(150) UNIQUE
Таблица:
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
email VARCHAR(150) UNIQUE
);
Вставь первого пользователя:
INSERT INTO users (name, email)
VALUES ('Anna', 'anna@example.com');
Это работает.
Попробуй вставить другого пользователя с тем же email:
INSERT INTO users (name, email)
VALUES ('Another Anna', 'anna@example.com');
PostgreSQL это отклонит.
Потому что email должен быть уникальным.
Это защищает твои данные.
Без UNIQUE дубли email могут создать проблемы с login, account и головной болью.
Головная боль от базы данных не весёлая.
Она носит тяжёлые ботинки.
DEFAULT
DEFAULT даёт колонке значение, если ты ничего не передал.
Пример:
active BOOLEAN DEFAULT true
Таблица:
CREATE TABLE subscribers (
id SERIAL PRIMARY KEY,
email VARCHAR(150) UNIQUE NOT NULL,
active BOOLEAN DEFAULT true
);
Вставь без active:
INSERT INTO subscribers (email)
VALUES ('reader@example.com');
Теперь проверь:
SELECT * FROM subscribers;
Колонка active должна быть true.
PostgreSQL использовал значение по умолчанию.
Default-ы полезны, когда большинство строк должны начинаться с одного и того же значения.
Например:
active DEFAULT true;completed DEFAULT false;published DEFAULT false;created_at DEFAULT CURRENT_DATE.
Хорошие default-ы уменьшают повторение кода.
А повторение кода — это место, где маленькие bugs строят гнёзда.
CHECK
CHECK создаёт правило, которому значения должны соответствовать.
Пример:
price NUMERIC(10, 2) CHECK (price >= 0)
Это означает, что цена не может быть отрицательной.
Таблица:
CREATE TABLE store_products (
id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
price NUMERIC(10, 2) CHECK (price >= 0)
);
Это работает:
INSERT INTO store_products (name, price)
VALUES ('Mouse', 25.00);
Это не работает:
INSERT INTO store_products (name, price)
VALUES ('Magic Refund Product', -10.00);
PostgreSQL это отклонит.
Хорошо.
Отрицательные цены могут существовать в бухгалтерии.
Но не в этой таблице.
База данных защищает правило.
Очень серьёзно.
Очень полезно.
CHECK с Возрастом
Другой пример:
age INTEGER CHECK (age >= 0)
Это означает, что возраст не может быть отрицательным.
Таблица:
CREATE TABLE people (
id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
age INTEGER CHECK (age >= 0)
);
Это работает:
INSERT INTO people (name, age)
VALUES ('Anna', 22);
Это не работает:
INSERT INTO people (name, age)
VALUES ('Time Traveler', -5);
PostgreSQL отказывает.
Хорошо.
Если тебе нужны путешественники во времени, создай отдельную таблицу.
Возможно.
Сочетание Ограничений
Можно сочетать несколько ограничений в одной таблице.
Пример:
CREATE TABLE app_users (
id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
email VARCHAR(150) UNIQUE NOT NULL,
active BOOLEAN DEFAULT true,
age INTEGER CHECK (age >= 0)
);
Эта таблица имеет много правил:
id— primary key;nameобязательно;emailобязателен;emailдолжен быть уникальным;activeпо умолчаниюtrue;ageне может быть отрицательным.
Это намного безопаснее, чем таблица без правил.
Таблица без ограничений принимает слишком много.
Она слишком вежливая.
Базы данных не должны быть слишком вежливыми.
Они должны защищать данные.
Как серьёзный фейс-контроль в клубе информации.
Создай Более Безопасную Таблицу Products
Создадим лучшую таблицу products.
Сначала удали старую, если нужно:
DROP TABLE IF EXISTS safe_products;
Теперь создай:
CREATE TABLE safe_products (
id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
category VARCHAR(100) DEFAULT 'General',
price NUMERIC(10, 2) CHECK (price >= 0),
available BOOLEAN DEFAULT true
);
Эта таблица имеет лучшие правила:
nameобязательно;categoryимеет default;priceне может быть отрицательным;availableпо умолчаниюtrue.
Вставь данные:
INSERT INTO safe_products (name, price)
VALUES ('Laptop', 900.00);
Проверь:
SELECT * FROM safe_products;
Ты должен увидеть:
category = General
available = true
PostgreSQL заполнил default-ы.
Приятно.
База данных помогает.
Наконец-то.
Протестируй Правила
Попробуй вставить товар без названия:
INSERT INTO safe_products (price)
VALUES (10.00);
PostgreSQL должен отклонить это, потому что name является NOT NULL.
Попробуй вставить отрицательную цену:
INSERT INTO safe_products (name, price)
VALUES ('Broken Product', -5.00);
PostgreSQL должен отклонить это из-за CHECK.
Это хорошо.
Таблица защищает себя сама.
Таблица, которая защищает себя сама, намного безопаснее таблицы, которая принимает всё.
Как дверь с замком.
Не идеально.
Но лучше, чем штора.
Проверь Таблицу
Выполни:
\d safe_products
Ты должен увидеть колонки, типы, default-ы и constraints.
Это полезная команда.
Используй её часто.
Когда забудешь, как выглядит таблица, спроси PostgreSQL.
Он помнит.
Он всегда помнит.
Очень базоданно.
Немного страшно.
Типичные Ошибки
Использовать TEXT для Всего
Плохо:
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name TEXT,
age TEXT,
active TEXT
);
Лучше:
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name VARCHAR(100),
age INTEGER,
active BOOLEAN
);
Используй правильный тип.
Text — это не универсальное решение.
Это полезный инструмент.
Не мусорный пакет для storage.
Забыть NOT NULL
Плохо:
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name VARCHAR(100),
email VARCHAR(150)
);
Это позволяет создавать пользователей без имён или email.
Возможно, это не то, что ты хочешь.
Лучше:
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
email VARCHAR(150) NOT NULL
);
Если значение обязательно, скажи это.
PostgreSQL будет это контролировать.
Забыть UNIQUE для Email
Плохо:
email VARCHAR(150)
Лучше:
email VARCHAR(150) UNIQUE
Если email идентифицирует пользователей, обычно он должен быть уникальным.
Дубли email — это как два человека с одним паспортом.
Возможно в плохой системе.
Ужасная идея.
Разрешать Отрицательные Цены
Плохо:
price NUMERIC(10, 2)
Лучше:
price NUMERIC(10, 2) CHECK (price >= 0)
Если отрицательные цены не имеют смысла, заблокируй их.
Не доверяй будущему коду, что он всегда будет вести себя хорошо.
Будущий код пишут будущие люди.
Опасно.
Практика
Создай таблицу с названием employees.
Она должна иметь:
id;name;email;salary;active;hired_at.
Используй эти правила:
nameобязательно;emailобязателен и уникален;salaryне может быть отрицательной;activeпо умолчаниюtrue;hired_at— дата.
Пример:
CREATE TABLE employees (
id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
email VARCHAR(150) UNIQUE NOT NULL,
salary NUMERIC(10, 2) CHECK (salary >= 0),
active BOOLEAN DEFAULT true,
hired_at DATE
);
Вставь employees:
INSERT INTO employees (name, email, salary, hired_at)
VALUES ('Anna', 'anna@example.com', 2500.00, '2026-05-03');
INSERT INTO employees (name, email, salary, active, hired_at)
VALUES ('Marco', 'marco@example.com', 3000.00, false, '2026-05-04');
Прочитай данные:
SELECT * FROM employees;
Потом протестируй constraints.
Попробуй дублированный email.
Попробуй отрицательную salary.
Попробуй отсутствующее name.
Позволь PostgreSQL тебя остановить.
В этом и смысл.
Мини-Челлендж
Создай таблицу с названием courses.
Она должна иметь:
id;title;description;price;published;created_at.
Правила:
titleобязателен;priceне может быть отрицательным;publishedпо умолчаниюfalse;created_atпо умолчанию текущая дата.
Подсказка:
created_at DATE DEFAULT CURRENT_DATE
Вставь минимум три курса.
Потом выполни:
SELECT * FROM courses;
Попробуй вставить курс без title.
Попробуй вставить курс с отрицательной price.
PostgreSQL должен отклонить плохие данные.
Это не PostgreSQL раздражает тебя.
Это PostgreSQL полезен.
Есть разница.
Иногда.
Итог
Сегодня ты изучил:
- типы данных определяют, какой тип данных хранит колонка;
INTEGERхранит целые числа;VARCHARхранит ограниченный текст;TEXTхранит длинный текст;BOOLEANхранитtrueилиfalse;DATEхранит даты;NUMERICхранит точные десятичные значения;SERIALсоздаёт автоматически растущие ID;- ограничения создают правила для данных;
NOT NULLделает колонку обязательной;UNIQUEблокирует дубли;DEFAULTавтоматически даёт значение;CHECKпроверяет значение через условие;- хороший дизайн таблиц защищает базу данных.
Это большой шаг.
Ты уже не просто создаёшь таблицы.
Ты создаёшь более безопасные таблицы.
База данных не должна принимать ерунду.
Она должна защищать структуру.
Она должна отклонять плохие данные.
Она должна останавливать банановые возрасты, дублированные email, отрицательные цены и загадочных пустых пользователей.
PostgreSQL может это делать.
Если ты дашь ему правила.
Следующий Урок
В следующем уроке мы научимся фильтровать и сортировать данные.
Мы глубже разберём:
WHERE;- операторы сравнения;
AND;OR;LIKE;ORDER BY;LIMIT.
Потому что когда у тебя есть данные, нужно найти правильные данные.
Не все данные.
Правильные данные.
Именно здесь запросы становятся интересными.
И немного опасными.