Типы данных в PostgreSQL: что выбрать до создания таблицы
В PostgreSQL тип столбца влияет на допустимые значения, точность вычислений и размер хранения. Разберёмся, как выбрать типы для текста, чисел, дат и идентификаторов и проверить схему на PostgreSQL 16.

Неверный тип столбца часто обнаруживается не при создании таблицы, а когда в неё пытаются записать дату вместо текста, дробную сумму в целое число или слишком длинную строку. Ниже — короткая подготовка к проектированию таблицы для PostgreSQL 16: вы выберете типы для обычных полей, создадите пример и проверите, что база принимает ожидаемые значения.
Что подготовить
Нужен доступ к базе PostgreSQL 16 и клиенту, в котором можно выполнять SQL-запросы: например, psql или графическому интерфейсу вашей СУБД. Права должны позволять создавать таблицу в выбранной схеме. Пример ниже создаёт таблицу с именем type_demo; если такое имя уже занято, замените его в запросах.
Сначала решите, какие значения хранит поле
Выбирайте тип по смыслу данных, а не по тому, как они выглядят на экране. Телефон может содержать только цифры, но это не число для арифметики: у него бывают ведущие нули и знак «+». Денежная сумма — не строка, а значение, для которого важны точность и правила округления.
| Что хранится | Тип для старта | Когда подходит |
|---|---|---|
| Идентификатор-счётчик | bigint GENERATED ALWAYS AS IDENTITY | Числовой ключ, который генерирует база |
| Целое число | integer или bigint | Счётчик, количество, целочисленный код без ведущих нулей |
| Дробное значение с заданной точностью | numeric(p, s) | Сумма или другой показатель, где важно контролировать число знаков |
| Короткий текст | text | Имена, описания, адреса, значения с переменной длиной |
| Дата и время | timestamp with time zone | Момент времени, который нужно сопоставлять между часовыми поясами |
| Логическое значение | boolean | Состояние из «да», «нет» и, если разрешено, неизвестного значения |
numeric(p, s) задаёт общую точность и число цифр после десятичного разделителя. Например, numeric(10, 2) допускает десять цифр всего, из них две — после запятой. Требования к точности суммы определите по предметной области, а не наугад.
Тип данных — это правило для будущих значений, а не просто подпись столбца. Если правило выбрано неверно, исправлять придётся и схему, и уже сохранённые данные.
Сноска. Точность — максимальное число значащих цифр, которое разрешает тип или его параметры. В numeric(p, s) параметр p задаёт общее число цифр, а s — число цифр после десятичного разделителя.
Создайте таблицу и проверьте значения
Для проверки используйте полный запрос. Он создаёт небольшую таблицу, добавляет одну строку и выводит сохранённые данные. Если пример не нужен, не выполняйте его на рабочей базе: создайте тестовую схему или базу.
Определите поля по их назначению. В примере число единиц товара — целое, цена — точная дробь, название — текст, а момент создания — дата и время с часовым поясом.
CREATE TABLE type_demo ( id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY, product_name text NOT NULL, quantity integer NOT NULL, unit_price numeric(10, 2) NOT NULL, created_at timestamp with time zone NOT NULL DEFAULT now(), is_available boolean NOT NULL DEFAULT true ); INSERT INTO type_demo (product_name, quantity, unit_price) VALUES ('Кабель', 2, 349.90); SELECT id, product_name, quantity, unit_price, created_at, is_available FROM type_demo;Проверка: запрос завершается без ошибки, а выборка показывает одну строку; идентификатор и время заполнены базой.
Проверьте ограничения типов, выполнив запрос на тестовой таблице. Он должен завершиться ошибкой, потому что в целочисленный столбец передана строка.
INSERT INTO type_demo (product_name, quantity, unit_price) VALUES ('Кабель', 'много', 349.90);Проверка: PostgreSQL отклоняет вставку с сообщением о неверном синтаксисе входного значения для типа integer. Это ожидаемое поведение, а не сбой таблицы.
Посмотрите фактические типы столбцов через метаданные PostgreSQL.
SELECT column_name, data_type, is_nullable FROM information_schema.columns WHERE table_name = 'type_demo' ORDER BY ordinal_position;Проверка: результат содержит столбцы таблицы; например, для
quantityуказан типinteger, а дляunit_price—numeric.
Где чаще ошибаются
Хранят деньги во
realилиdouble precision. Эти типы подходят для приблизительных вычислений с плавающей точкой, но могут давать неожиданные значения из-за двоичного представления дробей. Для точных сумм рассмотритеnumericи отдельно определите правила округления.Выбирают
varchar(255)«на всякий случай». Если в предметной области нет такого ограничения, оно не добавляет полезного смысла. Для текста переменной длины обычно достаточноtext; ограничения длины можно задавать отдельно, исходя из требований продукта.Сохраняют дату рождения как дату и время. Если время суток не имеет значения, используйте
date. И наоборот, для записи момента события важен часовой пояс: сравнитеtimestamp with time zoneиtimestamp without time zoneв официальной документации.Считают
NOT NULLзначением по умолчанию. Это лишь запрещает записатьNULL; оно не задаёт значение автоматически. Для автоматического значения нуженDEFAULT, если такое значение действительно уместно.Используют число для телефона или почтового индекса. Если значение не участвует в арифметике, храните его как текст. Так не потеряются ведущие нули и символы вроде «+».
Что выбрать для спорных полей
Для простого флага подойдёт boolean, но помните: без NOT NULL столбец может содержать и NULL — неизвестное или не заданное значение. Если в поле есть несколько устойчивых состояний, например «черновик», «опубликовано», «архив», решите, как система будет управлять их набором; способ хранения зависит от того, меняются ли состояния и нужны ли им дополнительные данные.
Для идентификатора обычно удобен целочисленный ключ с генерацией значения базой. Если идентификаторы приходят извне — например, из другой системы, — тип и правила уникальности нужно согласовать с источником. Не превращайте идентификатор в число, если его части имеют смысл только как символы.
Слова timestamp with time zone могут создать неверное ожидание, будто PostgreSQL хранит исходное название часового пояса. Тип представляет момент времени и приводит ввод с учётом зоны; формат отображения зависит от настроек сессии. Если нужно сохранить именно исходную зону пользователя, её следует хранить отдельно.
Что делать дальше
Перед созданием рабочей таблицы выпишите для каждого поля три вещи: какие значения допустимы, может ли поле быть пустым и нужны ли вычисления над ним. Затем проверьте типы на реальных крайних значениях: минимальной и максимальной сумме, самой длинной строке, дате с часовым поясом и пустом значении. После этого изучите ограничения CHECK, уникальность и внешние ключи — это следующий слой правил, который защищает данные от ошибок приложения.
В статье рассматриваются базовые типы и их выбор; миграции уже существующих таблиц и оценка объёма хранения — отдельные темы.
Логотип и фирменный стиль: Три концепции разного характера, палитра с обоснованием, проверка на читаемость в малом размере и в один цвет.
Спросить за 60 ₽Источники: PostgreSQL 16: типы данных, PostgreSQL 16: числовые типы
Частые вопросы
Для денег всегда нужно использовать numeric?
Чем text отличается от varchar в PostgreSQL?
Нужно ли хранить дату и время в UTC?
Что будет, если вставить значение неподходящего типа?
Можно ли изменить тип столбца после создания таблицы?
Какой тип выбрать для телефона и почтового индекса?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.