В прошлом уроке мы создали первую таблицу и выбрали типы колонок наугад. Пора разобраться. Начнём с чисел: в книжном магазине они повсюду, от количества страниц до цены. И у каждого числа своя правильная «коробка».
Коробки разного размера
Представь склад, где для каждой вещи есть коробка. Пуговицу можно положить и в коробку от холодильника, но склад быстро закончится. А холодильник в коробку для пуговиц не влезет никак. Хороший кладовщик берёт коробку чуть больше вещи.
Тип данных колонки работает так же: он задаёт, какие значения в неё помещаются и сколько байт займёт каждое. Ошибёшься в меньшую сторону, и база откажется принять значение. В большую, и потратишь лишнее место на каждой строке.
В PostgreSQL числовые типы делятся на три семьи:
- целые для того, что считают штуками: страницы, остатки на складе, идентификаторы;
- точные дробные для денег и всего, где копейка важна;
- приблизительные дробные для измерений, где важна скорость, а не последний знак.
Целые: smallint, integer, bigint
| Тип | Байт | Диапазон |
|---|---|---|
smallint | 2 | от −32 768 до 32 767 |
integer | 4 | примерно ± 2,1 миллиарда |
bigint | 8 | примерно ± 9,2 квинтиллиона |
integer (его же пишут int или int4) это выбор по умолчанию. bigint (int8) берут, когда счёт может уйти за два миллиарда: идентификаторы больших таблиц, просмотры, суммы в копейках. smallint (int2) экономит два байта, но на практике его выбирают редко: выигрыш копеечный, а риск упереться в потолок реальный.
Что будет, если число не влезло? PostgreSQL не обрезает его молча, а останавливает запрос с ошибкой:
SELECT 2147483647 + 1;
ERROR: integer out of range
Это называется переполнением. Java и Go при переполнении молча «перескакивают» на отрицательные числа, и ошибка всплывает через месяц в отчёте. Postgres честно падает сразу. Если же один из операндов bigint, сложение пройдёт:
SELECT 2147483647::bigint + 1;
?column?
------------
2147483648
Запись ::bigint это приведение типа, ему посвящён урок 8. Пока читай её как «считай это число bigint’ом».
Есть и ловушка: деление целого на целое даёт целое, дробная часть отбрасывается.
SELECT 10 / 3, 10 / 3.0;
?column? | ?column?
----------+--------------------
3 | 3.3333333333333333
Стоит одному из чисел стать дробным, и результат тоже дробный.
Точные дробные: numeric
Цена книги 990 рублей 50 копеек. Для денег в Postgres есть numeric: он хранит число цифра в цифру, как ты пишешь его на бумаге.
У numeric два необязательных параметра: numeric(точность, масштаб).
- Точность это сколько цифр всего.
- Масштаб это сколько из них после запятой.
numeric(10, 2) вмещает до 99 999 999,99: восемь цифр до запятой и две после. Лишние знаки после запятой округляются, а лишние цифры до запятой вызывают ошибку:
SELECT 1234.567::numeric(6, 2);
SELECT 123456.7::numeric(6, 2);
numeric
---------
1234.57
ERROR: numeric field overflow
DETAIL: A field with precision 6, scale 2 must round to an absolute value less than 10^4.
Первое число аккуратно округлилось до копеек. Второму не хватило места до запятой, и Postgres отказался его записывать. Для денег так и надо: лучше ошибка, чем потерянный разряд.
Без параметров numeric хранит любое число любой длины, до тысяч цифр. Платят за точность скоростью: арифметика с numeric медленнее, чем с целыми. Для цен в магазине разница незаметна.
урок из курса
Урок из курса «PostgreSQL с нуля». Курс покупается один раз и остаётся навсегда: 500 ₽.
Оплата пока не подключена: премиум и курсы открываются промокодом.