Типы данных в SQL — что нужно знать аналитику
Зачем аналитику знать типы данных
Тип данных определяет, что можно хранить в колонке и какие операции с ней допустимы. Складывать числа, сравнивать даты, фильтровать по строкам — всё это работает только если типы правильные. Неправильный тип — и вы получаете неожиданные результаты: целочисленное деление вместо дробного, строку вместо числа, ошибку при сравнении дат. На собеседовании по SQL вопросы про типы данных встречаются регулярно.
Числовые типы
| Тип | Размер | Диапазон / точность | Когда использовать |
|---|---|---|---|
| INTEGER (INT) | 4 байта | от −2,1 млрд до 2,1 млрд | id, количество, счётчики |
| BIGINT | 8 байт | до ±9,2 × 10¹⁸ | id в больших таблицах, Unix-таймстемпы |
| NUMERIC(p, s) / DECIMAL | переменный | точная арифметика | деньги, проценты, финансовые расчёты |
| FLOAT / REAL / DOUBLE PRECISION | 4–8 байт | приблизительная арифметика | научные расчёты, метрики, где мелкие погрешности допустимы |
Главное правило: для денег и финансовых данных — всегда NUMERIC. FLOAT хранит числа приблизительно: 0.1 + 0.2 может дать 0.30000000000000004. В аналитике это обычно некритично, но в отчёте по выручке — недопустимо.
Ловушка: целочисленное деление
Это самый частый сюрприз для начинающих:
SELECT 5 / 2; -- 2, а не 2.5!
SELECT 5 / 2.0; -- 2.5
SELECT 5::NUMERIC / 2; -- 2.5Если оба операнда — целые числа, PostgreSQL возвращает целое число. Дробная часть просто отбрасывается. Чтобы получить дробный результат, приведите хотя бы один операнд к NUMERIC или FLOAT.
Типичная ошибка в аналитике — считать конверсию без приведения типов:
-- Неправильно: 100 / 500 = 0
SELECT COUNT(*) FILTER (WHERE paid) / COUNT(*) AS conversion
FROM users;
-- Правильно: приводим к NUMERIC
SELECT COUNT(*) FILTER (WHERE paid)::NUMERIC / COUNT(*) AS conversion
FROM users;Строковые типы
| Тип | Особенность |
|---|---|
| VARCHAR(n) | Строка переменной длины, максимум n символов |
| TEXT | Строка без ограничения длины |
| CHAR(n) | Строка фиксированной длины, дополняется пробелами |
В PostgreSQL разницы в производительности между VARCHAR и TEXT нет. CHAR(n) на практике почти не используется — он дополняет значение пробелами до нужной длины, что создаёт путаницу при сравнениях. В аналитических таблицах чаще всего встретите TEXT или VARCHAR.
Дата и время
| Тип | Пример | Когда использовать |
|---|---|---|
| DATE | 2026-04-08 |
Дата рождения, отчётный период |
| TIMESTAMP | 2026-04-08 14:30:00 |
Время без привязки к часовому поясу |
| TIMESTAMPTZ | 2026-04-08 14:30:00+03 |
События, логи, created_at |
| INTERVAL | INTERVAL '3 days 2 hours' |
Разница между датами, арифметика |
Для событий — всегда TIMESTAMPTZ. Он хранит момент времени однозначно, независимо от часового пояса сервера. Если таблица событий использует TIMESTAMP без часового пояса — это потенциальная проблема: при переезде на другой сервер время «сдвинется». Подробнее о работе с датами — в отдельном гайде.
BOOLEAN
Принимает значения TRUE, FALSE и NULL. В PostgreSQL можно писать сокращённо: 't', 'f', 'yes', 'no', 1, 0 — все приведутся к boolean.
SELECT * FROM users WHERE is_active; -- TRUE
SELECT * FROM users WHERE NOT is_active; -- FALSE
SELECT * FROM users WHERE is_active IS NULL; -- NULLОбратите внимание: WHERE is_active = TRUE и WHERE is_active — одно и то же, но второй вариант короче и идиоматичнее.
NULL — не тип, но важно
NULL — это не ноль и не пустая строка. Это отсутствие значения. Любая операция с NULL возвращает NULL:
SELECT 5 + NULL; -- NULL
SELECT 'hello' || NULL; -- NULL
SELECT NULL = NULL; -- NULL (не TRUE!)Для проверки на NULL используйте IS NULL / IS NOT NULL, а не = NULL. Это одна из классических ошибок, которую спрашивают на собеседованиях.
Приведение типов (CAST)
Два способа привести тип в PostgreSQL:
-- Стандартный SQL
SELECT CAST('2026-04-08' AS DATE);
SELECT CAST(42 AS TEXT);
-- Сокращённый синтаксис PostgreSQL
SELECT '2026-04-08'::DATE;
SELECT 42::TEXT;Оператор :: — специфика PostgreSQL. На собеседованиях можно использовать оба варианта, но :: встречается чаще в реальных запросах.
Неявное и явное приведение
PostgreSQL умеет приводить типы автоматически (неявно):
SELECT '100' + 1; -- PostgreSQL: ошибка! Строку нельзя неявно привести к числу
SELECT 100 + 1.5; -- 101.5, INTEGER неявно приведётся к NUMERICЕсли PostgreSQL не может привести тип автоматически — будет ошибка. Правило простое: не надейтесь на неявное приведение, приводите явно через :: или CAST.
Вопросы с собеседований
— Чем NUMERIC отличается от FLOAT? — NUMERIC хранит числа точно, с заданным количеством знаков. FLOAT — приблизительно, с плавающей точкой. Для финансовых расчётов — NUMERIC, для метрик, где мелкая погрешность допустима — FLOAT.
— Что вернёт SELECT 5 / 2?
— Число 2. Оба операнда — INTEGER, результат тоже INTEGER, дробная часть отбрасывается. Чтобы получить 2.5, нужно привести один из операндов: 5::NUMERIC / 2 или 5 / 2.0.
— Как проверить значение на NULL?
— Только через IS NULL / IS NOT NULL. Оператор = с NULL всегда возвращает NULL, не TRUE. WHERE col = NULL не вернёт ни одной строки — это частая ошибка.
— Чем VARCHAR отличается от TEXT в PostgreSQL? — Функционально — почти ничем. VARCHAR(n) ограничивает длину строки до n символов, TEXT — нет. Производительность одинаковая. В аналитике обычно используют TEXT.
— Зачем нужен TIMESTAMPTZ вместо TIMESTAMP? — TIMESTAMPTZ хранит момент времени однозначно, с учётом часового пояса. TIMESTAMP без зоны зависит от настроек сервера — при смене сервера или зоны сессии значение интерпретируется иначе. Для событий (created_at, logged_at) — всегда TIMESTAMPTZ.
Потренируйтесь
Типы данных лучше всего запоминаются на практике — когда пишешь запросы и разбираешься, почему конверсия вышла 0 вместо 0.15. Откройте тренажёр с 1500+ вопросами по SQL и другим темам для аналитика.
FAQ
Какой тип выбрать для id — INTEGER или BIGINT?
Для небольших таблиц (до 2 млрд строк) хватит INTEGER. Для таблиц событий, логов и всего, что быстро растёт — BIGINT. В современных системах часто сразу используют BIGINT для id: разница в размере минимальна, а проблемы с переполнением исключены.
Можно ли хранить числа в VARCHAR?
Технически — да. Практически — не стоит. Вы не сможете нормально сортировать ('9' > '10' потому что строковое сравнение), не сможете складывать без приведения, займёте больше места. Числа — в числовые типы.
Что будет, если вставить строку длиннее VARCHAR(n)?
PostgreSQL вернёт ошибку. MySQL в старых версиях молча обрезал строку. В аналитике это редко проблема, но на собеседовании полезно знать разницу.
Больше теории и практики по SQL — в тренажёре Карьерника. 1500+ вопросов с объяснениями — на странице примеров.