Тип данных определяет, какие значения можно хранить в столбце и какие операции с ними доступны. Ниже собраны основные типы PostgreSQL, примеры их применения и особенности, которые стоит учитывать при создании таблиц.
Числовые типы
Целые числа
Используются для счётчиков, количества, порядковых номеров и целочисленных идентификаторов.
| Тип | Другие названия | Размер | Диапазон |
smallint |
int2 |
2 байта | от −32 768 до 32 767 |
integer |
int, int4 |
4 байта | от −2 147 483 648 до 2 147 483 647 |
bigint |
int8 |
8 байт | от −9 223 372 036 854 775 808 до 9 223 372 036 854 775 807 |
Обычно достаточно integer. Если значения могут выйти за его диапазон, выбирайте bigint.
Числа с дробной частью
| Тип | Особенности | Применение |
numeric(p, s), decimal(p, s) |
Точное десятичное хранение с заданной точностью | Цены, суммы, расчёты с контролируемым округлением |
real, float4 |
Приближённое хранение; 4 байта, не менее 6 значащих десятичных цифр | Измерения, для которых допустима погрешность |
double precision, float8 |
Приближённое хранение; 8 байт, не менее 15 значащих десятичных цифр | Вычисления с большей точностью |
В обычной записи numeric(p, s) параметр p задаёт общее количество цифр, а s — количество цифр после точки. Например, numeric(10, 2) допускает восемь цифр до точки и две после неё. Лишние дробные цифры округляются; превышение допустимой целой части вызывает ошибку.
numeric без параметров не задаёт фиксированную точность и масштаб.
Для денежных сумм обычно выбирают numeric: real и double precision могут давать погрешность при хранении и вычислениях.
Автоматическая нумерация: IDENTITY и SERIAL
Для автоматически создаваемого числового идентификатора можно использовать столбец IDENTITY:
sqlid bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY
PostgreSQL получает значения из последовательности. ALWAYS ограничивает обычную вставку явно заданного идентификатора; вариант BY DEFAULT позволяет указать его вручную.
В существующих схемах часто встречаются smallserial, serial и bigserial. Это сокращения для создания столбца соответствующего целого типа с последовательностью, а не самостоятельные типы данных.
Ни SERIAL, ни IDENTITY сами по себе не гарантируют уникальность. Для неё нужны PRIMARY KEY или UNIQUE. В нумерации возможны пропуски, например после отмены транзакции.
Строковые типы
| Тип | Что хранит | Когда использовать |
text |
Строку без заданного ограничения длины | Описания, статьи, комментарии |
varchar(n) |
Строку длиной до n символов | Названия и коды с обоснованным пределом длины |
char(n) |
Строку фиксированной длины с дополнением пробелами справа | Когда требуется именно такое поведение |
varchar без параметра длины, как и text, не задаёт ограничения на число символов. При этом технический предел отдельного строкового значения составляет около 1 ГБ.
Параметр n измеряется в символах, а не в байтах. Обычно для текста выбирают text, а varchar(n) используют, если ограничение длины связано с требованиями к данным. char(n) не даёт преимущества в скорости.
Телефонные номера, почтовые индексы и номера документов обычно хранят как строки: в них могут быть ведущие нули, знак + и другие значимые символы.
Логический тип
boolean, или bool, хранит TRUE и FALSE. Если столбец допускает отсутствие значения, в нём также может находиться NULL.
| Значение | Смысл |
TRUE |
Да, условие выполнено |
FALSE |
Нет, условие не выполнено |
NULL |
Значение отсутствует или неизвестно |
Пример определения столбца:
sqlis_active boolean NOT NULL DEFAULT TRUE
В SQL удобнее писать TRUE и FALSE без кавычек. PostgreSQL также распознаёт строковые формы, например 'yes', 'no', '1' и '0', когда ожидается логическое значение.
NULL не равен FALSE. Клиентская программа может показывать его как пустую ячейку, но это не пробел и не пустая строка.
Дата и время
| Тип | Что хранит | Пример значения |
date |
Дату без времени | '2026-10-10' |
time |
Время суток без часового пояса | '14:30:00' |
timestamp |
Дату и время без часового пояса | '2026-10-10 14:30:00' |
timestamptz |
Конкретный момент времени с учётом часового пояса | '2026-10-10 14:30:00+03:00' |
interval |
Интервал времени | '2 days 3 hours' |
timestamp — сокращение для timestamp without time zone, а timestamptz — для timestamp with time zone.
TIMESTAMPTZ не сохраняет исходное название часового пояса. Значение хранится как момент времени в UTC, а при выводе отображается в часовом поясе текущей сессии. Если нужно сохранить именно Europe/Moscow, для него потребуется отдельный столбец.
Для времени создания записи или оплаты обычно подходит timestamptz. Для даты рождения — date, для времени открытия магазина — time.
Существует и time with time zone (timetz), но для большинства новых схем он не нужен.
UUID
uuid хранит 128-битный идентификатор. Его обычная текстовая запись выглядит так:
texta57eec41-1923-4ad8-9ed6-728ed83194af
UUID удобен, когда идентификаторы создаются независимо в разных системах. Сам тип хранит значение; способ его генерации задаётся отдельно.
Для идентификатора строки по-прежнему нужны PRIMARY KEY или UNIQUE. UUID также не заменяет проверку прав доступа: по форме идентификатора нельзя судить, защищены ли данные.
JSON и JSONB
Эти типы хранят JSON-данные: объекты, массивы и отдельные значения. Например:
json{"color": "blue", "size": 42, "available": true}
| Тип | Особенности |
json |
Сохраняет исходный текст, включая пробелы, порядок ключей и повторяющиеся ключи |
jsonb |
Хранит разобранную структуру; не сохраняет форматирование и порядок ключей объекта, при повторении ключа оставляет последнее значение |
Оба типа проверяют корректность JSON. Для поиска и обработки содержимого обычно выбирают jsonb: он поддерживает индексацию и не требует повторного разбора текста.
json полезен, если важно сохранить исходное представление документа. Порядок элементов массива сохраняется в обоих типах.
JSONB подходит для дополнительных свойств с меняющимся набором полей. Данные с устойчивой структурой, например цену и дату создания, обычно удобнее хранить в отдельных столбцах.
Массивы
Массив хранит несколько элементов одного типа в одном значении. Для объявления к названию типа добавляют []:
| Тип | Пример значения |
integer[] |
ARRAY[10, 20, 30] |
text[] |
ARRAY['sql', 'postgresql'] |
Поддерживаются и многомерные массивы. По умолчанию индексация начинается с 1.
Массивы удобны для небольших списков внутри записи. Если элементы имеют собственные свойства или связывают разные сущности, обычно лучше использовать отдельную таблицу.
Запись integer[3] сама по себе не ограничивает длину массива тремя элементами. Для такого правила нужно дополнительное ограничение CHECK.
Другие полезные типы
| Тип или группа | Назначение |
bytea |
Двоичные данные: последовательности байтов |
inet |
Адрес IPv4 или IPv6, при необходимости с маской сети |
cidr |
Сеть IPv4 или IPv6 |
macaddr, macaddr8 |
MAC-адреса |
point, line, lseg, box, path, polygon, circle |
Геометрические объекты на плоскости |
bit(n), bit varying(n) |
Битовые строки фиксированной или переменной длины |
tsvector, tsquery |
Представление документа и запроса для полнотекстового поиска |
xml |
XML-данные |
Есть также тип money, но для универсального хранения денежных сумм обычно удобнее numeric: формат money зависит от региональных настроек.
Отдельного упоминания заслуживают:
- Перечисления (ENUM) — пользовательские типы с заранее заданным набором значений, например статусами заказа.
- Диапазоны — типы вроде daterange, int4range и tstzrange, которые хранят диапазон с границами. Мультидиапазоны объединяют несколько таких диапазонов.
- HSTORE — тип из расширения hstore для пар «ключ — значение». Ключи и значения текстовые; значение также может быть NULL. Для вложенных структур обычно подходит jsonb.
Пример таблицы
sqlCREATE TABLE products ( id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY, name text NOT NULL, price numeric(10, 2) NOT NULL CHECK (price >= 0), quantity integer NOT NULL DEFAULT 0 CHECK (quantity >= 0), is_available boolean NOT NULL DEFAULT TRUE, created_at timestamptz NOT NULL DEFAULT CURRENT_TIMESTAMP, properties jsonb NOT NULL DEFAULT '{}'::jsonb);
Тип задаёт допустимый формат значения. Ограничения дополняют его: NOT NULL запрещает отсутствие значения, CHECK проверяет условие, а PRIMARY KEY обеспечивает уникальность идентификатора и запрещает NULL.
Функция CAST — изменить тип данных
Иногда возникает необходимость изменить тип данных в какой-нибудь колонке результирующей таблицы, не меняя при этом свойства исходной таблицы — например, преобразовать число в текст (тип данных VARCHAR). Для этого существует функция CAST. На вход ей необходимо подать имя колонки, указав через AS тип данных, к которому нужно привести все значения:
SELECT CAST(column AS VARCHAR)FROM table
Также изменить тип данных можно с помощью специального синтаксиса с двумя двоеточиями («::»):
SELECT column::VARCHARFROM table
Обратите внимание, что для успешной конвертации значения должны быть конвертируемыми в указываемый тип. Например, текст, который не выглядит как число, перевести в числовой тип данных не получится. А вот преобразовать текст в дату, если он выглядит как дата, вполне получится:
SELECT '2022-12-31'::DATE
Результат:
31/12/22