Числовые типы: integer, bigint, numeric
Разбираемся, какой числовой тип выбрать, чтобы не потерять точность и не переполнить столбец.
Числовой тип определяет диапазон значений и точность хранения числа; правильный выбор экономит память и защищает от ошибок округления.
Целые числа
PostgreSQL предлагает три целочисленных типа, отличающихся диапазоном и размером.
| Тип | Размер | Диапазон (примерно) |
smallint | 2 байта | ±32 тысячи |
integer (int) | 4 байта | ±2 миллиарда |
bigint | 8 байт | ±9 квинтиллионов |
В большинстве случаев берут integer — его хватает для счётчиков, количеств и большинства id. bigint нужен там, где значения реально большие: идентификаторы в крупных системах, количество байт, временные метки в миллисекундах.
Точные дробные: numeric
Для денег и любых величин, где нельзя терять копейки, существует numeric(precision, scale) (синоним — decimal). Это число с фиксированной точностью без ошибок округления.
-- numeric(10, 2): всего 10 значащих цифр, 2 после запятой
price NUMERIC(10, 2) -- хранит, например, 18000.00 точно
-- Деньги ВСЕГДА храните в numeric, а не во float!
Запись numeric(10, 2) означает: до 10 цифр всего, из них 2 после десятичной точки, то есть до 99 999 999.99.
Приближённые дробные: real и double precision
Типы real (4 байта) и double precision (8 байт) — это числа с плавающей точкой. Они быстрые и компактные, но хранят значения приближённо. Для научных расчётов это нормально, для денег — недопустимо.
SELECT 0.1 + 0.2 = 0.3 AS float_equal;
Вывод:
float_equal 0
Результат 0 (ложь!) — классическая ловушка плавающей точки: 0.1 + 0.2 не равно ровно 0.3. Именно поэтому деньги хранят в numeric, где такой проблемы нет.
Практика: считаем суммы в песочнице
Создадим таблицу заказов с целыми ценами и посчитаем итог. Пример переносимый — запустите и поменяйте числа.
CREATE TABLE orders (
id INTEGER PRIMARY KEY,
item TEXT,
qty INTEGER,
price INTEGER
);
INSERT INTO orders (id, item, qty, price) VALUES
(1, 'Кофе', 3, 250),
(2, 'Чай', 2, 180),
(3, 'Печенье', 5, 90);
SELECT item, qty * price AS total
FROM orders
ORDER BY total DESC;
Вывод:
Кофе|750 Печенье|450 Чай|360
Здесь total вычисляется на лету как qty * price и сортируется по убыванию. Поскольку цены целые, всё точно и без округлений.
Итог
integer— рабочая лошадка для счётчиков и id;bigint— для очень больших значений.numeric(p, s)— точные дроби; деньги храните только в нём.real/double precisionбыстрые, но приближённые — не для финансов.