Типы данных SQL и PostgreSQL: таблица с примерами
Таблица типов данных PostgreSQL с примерами: integer и bigint, NUMERIC и DOUBLE, VARCHAR и TEXT, дата и время, UUID, JSONB. Как выбрать тип и чем отличаются MySQL и ClickHouse.
Содержание статьи
Тип данных — это обещание столбца: здесь лежат целые числа, здесь деньги с копейками, здесь момент во времени. От типа зависит, что база разрешит записать, как она сравнит значения, отсортирует и посчитает сумму. Ниже — сводная таблица типов PostgreSQL с примерами, разбор групп, которые чаще всего путают (NUMERIC и DOUBLE, VARCHAR и TEXT, SERIAL и IDENTITY), как посмотреть типы столбцов в своей базе и чем названия отличаются в MySQL, SQL Server и ClickHouse.
Коротко
- Целые числа и идентификаторы —
integerилиbigint, если строк может стать больше двух миллиардов. - Деньги —
numeric(12, 2): точные десятичные дроби.double precision— для измерений, где важна скорость, а не копейка. - Строки —
textилиvarchar(n). В PostgreSQL они одинаково быстрые,nнужен только как ограничение длины. - Моменты времени —
timestamptz, календарные дни —date. - Новый ключ-счётчик —
bigint generated always as identityвместо устаревшегоserial.
Сводная таблица типов PostgreSQL
В таблице — типы, которые встречаются в рабочих базах продукта. PostgreSQL знает больше (геометрию, сетевые адреса, диапазоны), но аналитик сталкивается с ними редко.
| Группа | Тип | Размер | Диапазон или смысл | Пример |
|---|---|---|---|---|
| Целые | smallint | 2 байта | −32 768 … 32 767 | возраст, номер месяца |
| Целые | integer, int | 4 байта | ≈ ±2,1 млрд | количество, id небольшой таблицы |
| Целые | bigint | 8 байт | ≈ ±9,2 × 10¹⁸ | id событий и заказов |
| Точные дробные | numeric(p, s), decimal | переменный | до 131 072 цифр до запятой | суммы денег: numeric(12, 2) |
| Приближённые | real | 4 байта | ≈ 6 значащих цифр | показания датчиков |
| Приближённые | double precision | 8 байт | ≈ 15 значащих цифр | координаты, оценки модели |
| Счётчики | serial, bigserial | 4 и 8 байт | integer или bigint с последовательностью | старый способ задать id |
| Строки | text | переменный | без ограничения длины | комментарий, название |
| Строки | varchar(n) | переменный | не длиннее n символов | код страны varchar(2) |
| Строки | char(n) | n символов | дополняется пробелами до n | почти не нужен |
| Логический | boolean | 1 байт | true, false, null | флаг is_paid |
| Дата и время | date | 4 байта | день без времени | дата регистрации |
| Дата и время | timestamp | 8 байт | дата и время без пояса | время по договорённому поясу |
| Дата и время | timestamptz | 8 байт | момент во времени (UTC) | время события |
| Дата и время | interval | 16 байт | длительность | 3 days 04:00:00 |
| Идентификаторы | uuid | 16 байт | 128-битный идентификатор | id из внешней системы |
| Документы | jsonb | переменный | JSON в разобранном виде | свойства события |
| Массивы | integer[], text[] | переменный | список значений одного типа | теги товара |
Целые числа: integer или bigint
Для подсчётов и небольших справочников хватает integer. Для идентификаторов событий, заказов и всего, что растёт каждый день, берите bigint сразу. Переполнение integer — не теория: на 2 147 483 648-й строке вставка падает с ошибкой «integer out of range», а поменять тип у таблицы в миллиарды строк — это часы блокировки.
Аналитику переполнение встречается и в расчётах: сумма большого числа значений integer в PostgreSQL возвращается как bigint, но умножение двух integer остаётся integer и может не поместиться. Если перемножаете большие счётчики, приведите один множитель к bigint или numeric.
NUMERIC против DOUBLE PRECISION
double precision хранит число в двоичной дроби, и большинство десятичных дробей в ней представимы только приблизительно. Поэтому 0,1 + 0,2 в double не равно 0,3 — разница в шестнадцатом знаке. На одной операции это незаметно, на сумме миллиона платежей копейки расходятся с бухгалтерией.
numeric хранит десятичные цифры точно. Он медленнее на тяжёлых вычислениях, но для денег, процентов комиссии и всего, что сверяют с внешним отчётом, выбора нет. Запись numeric(12, 2) значит: всего до 12 цифр, из них 2 после запятой.
| double_equal | numeric_equal |
|---|---|
| false | true |
select
0.1::double precision + 0.2::double precision = 0.3 as double_equal,
0.1::numeric(10, 2) + 0.2::numeric(10, 2) = 0.3 as numeric_equal;В PostgreSQL есть тип money, но знак валюты и формат он берёт из локали сервера: на одном сервере сумма выйдет с долларом, на другом — с рублём. Для денег надёжнее numeric и отдельный столбец с кодом валюты.
VARCHAR, TEXT и CHAR
В PostgreSQL text и varchar(n) хранятся одинаково и работают с одной скоростью. Документация прямо говорит, что разницы в производительности между ними нет. varchar(n) нужен, когда ограничение длины — часть правил данных: код страны из двух букв, номер телефона. varchar без числа — то же самое, что text.
У ограничения есть ловушка. Вставка слишком длинной строки в varchar(3) падает с ошибкой, а явное приведение 'abcd'::varchar(3) молча обрезает строку до abc. Если очищаете данные через CAST, длинные значения потеряют хвост без предупреждения.
char(n) дополняет строку пробелами до длины n. При сравнении и склейке PostgreSQL эти пробелы игнорирует, а в выгрузке и при подсчёте байт они есть. Новых причин выбирать char почти нет: ограничение длины даёт varchar(n) без сюрпризов с пробелами.
select
'abcd'::varchar(3) as cast_truncates, -- abc
'ab'::char(5) = 'ab' as char_equal, -- true
length('ab'::char(5)) as char_length, -- 2
octet_length('ab'::char(5)) as char_bytes; -- 5
-- А вставка не обрезает, а падает:
-- insert into t (code) values ('abcd');
-- ERROR: value too long for type character varying(3)SERIAL и IDENTITY: автоинкремент
serial — не настоящий тип, а сокращение: столбец integer, последовательность и значение по умолчанию nextval(…). Так id задавали годами, и вы увидите serial во многих старых схемах.
С PostgreSQL 10 стандартный способ — generated always as identity. Он описан в стандарте SQL, последовательность принадлежит столбцу, и случайно записать в id своё значение не выйдет. Для новой таблицы пишите id bigint generated always as identity primary key. Подробнее — в статье про CREATE TABLE.
Дата и время
Главное различие — timestamp и timestamptz. Первый хранит показания часов без пояса, второй — момент во времени, который показывается в поясе сессии. Для событий почти всегда нужен timestamptz, для дат договоров и рождений — date. Разница и перевод между поясами подробно разобраны в статье про TIMESTAMP в PostgreSQL, а группировка по неделям и месяцам — в статье про DATE_TRUNC.
BOOLEAN, UUID, JSONB и массивы
boolean хранит true, false или null. Считать долю удобно через avg(flag::int) или count(*) filter (where flag): сложение булевых значений напрямую в PostgreSQL не работает.
uuid — 128-битный идентификатор, его удобно генерировать вне базы. С PostgreSQL 13 функция gen_random_uuid() встроена. Хранить uuid в text можно, но столбец будет вдвое больше и сравнения медленнее.
jsonb хранит JSON в разобранном виде: поиск по ключам быстрый, по нему строят индексы. Старый json хранит текст как есть и подходит только для логов, которые никто не разбирает. Массивы (text[]) хороши для коротких списков вроде тегов. Если элементы массива нужно соединять с другими таблицами, лучше отдельная таблица.
Как посмотреть типы столбцов
В psql: команда \d payments выводит столбцы таблицы, их типы, ограничения и индексы. В любом клиенте — запрос к стандартному представлению information_schema.columns. Он работает и в PostgreSQL, и в DuckDB, на котором устроена песочница, но названия типов движки пишут по-своему.
Тип любого выражения покажет функция pg_typeof(…): например, pg_typeof(sum(amount)). Удобно, когда непонятно, почему деление вернуло целое число.
| Столбец | DuckDB (песочница) | PostgreSQL |
|---|---|---|
| payments.payment_id | INTEGER | integer |
| payments.paid_at | DATE | date |
| payments.amount | DECIMAL(10,2) | numeric |
| payments.plan | VARCHAR | character varying или text |
select table_name, column_name, data_type
from information_schema.columns
where table_name in ('users', 'payments')
order by table_name, ordinal_position;Типы в других СУБД
Стандарт SQL задаёт общие названия, но каждая СУБД добавляет свои. Если запрос или схема переезжает, проверьте прежде всего деньги, строки и время.
| Смысл | PostgreSQL | MySQL | SQL Server | ClickHouse |
|---|---|---|---|---|
| Целое 4 байта | integer | int | int | Int32 |
| Целое 8 байт | bigint | bigint | bigint | Int64 |
| Деньги | numeric(12,2) | decimal(12,2) | decimal(12,2) | Decimal(12,2) |
| Строка | text, varchar(n) | varchar(n), text | nvarchar(n) | String |
| Логический | boolean | tinyint(1) | bit | Bool |
| Дата | date | date | date | Date |
| Момент времени | timestamptz | timestamp | datetimeoffset | DateTime('пояс') |
| JSON | jsonb | json | nvarchar(max) | JSON, String |
Как выбрать тип: чеклист
- Будет ли значение участвовать в арифметике? Если да — число, а не текст с цифрами. Номер телефона и почтовый индекс — текст: с ними не считают, и у них бывают ведущие нули.
- Нужна ли точность до копейки? Да —
numeric. Нет, и важна скорость на миллионах строк —double precision. - Может ли таблица вырасти больше двух миллиардов строк? Да —
bigintдля ключей. - Есть ли у значения правило длины? Да —
varchar(n)или ограничениеcheck. Нет —text. - Это момент или календарный день? Момент —
timestamptz, день —date.
Частые вопросы
Чем varchar отличается от text в PostgreSQL?
Только тем, что у varchar(n) есть предел длины. Хранение и скорость одинаковые.
Какой тип выбрать для денег?
numeric с двумя знаками после запятой, например numeric(12, 2). Не double precision и не money.
Сколько символов можно записать в text?
Ограничения длины нет, предел — около 1 ГБ на значение.
Что такое serial в PostgreSQL?
Столбец integer с собственной последовательностью и значением по умолчанию. В новых таблицах вместо него используют generated always as identity.
Как изменить тип столбца?
alter table … alter column … type новый_тип using выражение;. На большой таблице команда переписывает её целиком, поэтому её планируют заранее.
Почему 7 / 2 в PostgreSQL даёт 3?
Деление двух целых — целочисленное. Приведите одно из чисел к numeric. Разбор этой и других ловушек приведения — в статье про CAST.
Типы на практике удобнее всего проверить на учебной базе в песочнице. Курс «SQL с нуля» начинается с модуля о том, как устроены таблицы и их столбцы.
Материалы по теме

DATE_TRUNC в SQL: группировка по неделям, месяцам и кварталам
Как работает date_trunc в PostgreSQL: выручка по месяцам, недели с понедельника и с воскресенья, неполный период, часовой пояс и аналоги в MySQL, ClickHouse и SQL Server.

Как посмотреть таблицы и столбцы в PostgreSQL
Как посмотреть список таблиц, баз и схем в PostgreSQL, столбцы и типы таблицы, найти столбец по имени, узнать число строк и размер таблицы: psql, information_schema и pg_catalog.

ROUND в SQL: округление до 2 знаков, CEIL, FLOOR и деление целых
Как округлять в SQL: ROUND до двух знаков и до сотен, CEIL, FLOOR и TRUNC, половинки в PostgreSQL и DuckDB, целочисленное деление и доли, которые в сумме дают 101%.