Числовые функции
Функции для работы с числами
Теория
Числовые функции нужны именно для этого. Вы передаёте функции число или числовое выражение, а она возвращает уже обработанный результат.
Наиболее частой операцией при работе с числами является округление. На эту операцию сделаем акцент.
Возможности функции округления ROUND():
• если передать один аргумент, например ROUND(value), функция по умолчанию округлит число до целого;
• если передать второй аргумент, например ROUND(value::numeric, 2), можно управлять точностью округления в дробной части;
• если второй аргумент отрицательный, например ROUND(value::numeric, -2), функция начнёт округлять уже не дробную часть, а десятки, сотни и тысячи;
• при округлении до нескольких знаков после запятой в PostgreSQL часто нужен тип numeric, потому что с типами вроде double precision в таком вызове легко получить ошибку.
Числовые функции нужны не ради абстрактной математики, а чтобы быстро привести число к такому виду, который нужен вам в запросе, отчёте или тренировочном сценарии.
Синтаксис
SELECT ROUND(value),
ROUND(value::numeric, 2),
CEIL(value),
FLOOR(value),
TRUNC(value::numeric, 1),
ABS(value)
FROM table_name;
SELECT POWER(value, 2),
SQRT(value),
MOD(value, 3),
DIV(value::numeric, 3::numeric),
RANDOM(),
RANDOM(1, 100);
SQL
Компактная шпаргалка по функциям.
| Пример | Результат | Что делает |
|---|---|---|
| ROUND(12.7) | 13 | Округляет до целого |
| ROUND(12.675::numeric, 2) | 12.68 | Округляет до нужного количества знаков после запятой |
| ROUND(12567::numeric, -2) | 12600 | Округляет до десятков, сотен, тысяч |
| CEIL(12.1) | 13 | Округляет число до ближайшего верхнего целого |
| FLOOR(12.9) | 12 | Округляет число до ближайшего нижнего целого |
| TRUNC(12.78::numeric, 1) | 12.7 | Обрезает дробную часть без округления |
| ABS(-25) | 25 | Убирает знак минус |
| POWER(5, 3) | 125 | Возводит число в степень |
| SQRT(144) | 12 | Считает квадратный корень |
| MOD(29, 6) | 5 | Показывает остаток от деления: 29 = 6 * 4 + 5 |
| DIV(29::numeric, 6::numeric) | 4 | Показывает количество полных частей: число 6 помещается в 29 четыре раза |
| RANDOM(), RANDOM(1, 100) | Каждый раз новое число | Возвращает случайное число |
Теперь разберём важные нюансы.
1. Один аргумент у ROUND — это округление до целого
Если написать просто ROUND(value), PostgreSQL по умолчанию округлит число до ближайшего целого. Это базовый вариант, про который легко забыть, когда всё внимание уходит на второй аргумент.
2. ROUND и TRUNC — это не одно и то же
ROUND(12.78::numeric, 1) даст 12.8, потому что число округляется. TRUNC(12.78::numeric, 1) даст 12.7, потому что лишняя часть просто отрезается без округления.
3. Второй аргумент у ROUND умеет работать в обе стороны
Если он положительный, речь идёт о знаках после запятой. Если он равен нулю, округляем до целого. Если он отрицательный, функция начинает округлять десятки, сотни, тысячи.
4. Почему рядом с ROUND часто появляется numeric
Если нужно округлить число до нескольких знаков после запятой, в PostgreSQL часто приходится явно писать value::numeric. Причина в том, что дробные типы вроде double precision хранят приближённые значения, а numeric как раз даёт предсказуемую точность. Поэтому запись вроде ROUND(value::numeric, 2) выглядит длиннее, но работает надёжнее.
5. Что важно помнить про RANDOM()
Без аргументов RANDOM() возвращает случайное число от 0 до почти 1. А запись вроде RANDOM(1, 10000) доступна в PostgreSQL 17 и выше и сразу даёт случайное число в нужном диапазоне.
6. Функции можно вкладывать друг в друга
Это совершенно нормальная практика. Например, можно сначала получить случайное число, а потом привести его к более удобному виду через другую функцию. То же самое относится и к математическим выражениям вроде POWER(SQRT(81), 2).
7. Результат функции лучше сразу называть через псевдоним
Записи вроде ROUND(value::numeric, -2) AS value_to_hundreds или ABS(value - 100000) AS diff_from_target читаются заметно лучше, чем безымянные вычисляемые столбцы.
Примеры
1. Сравниваем функции ROUND, CEIL, FLOOR и TRUNC
🔄 Попробуйте изменить запрос:
- • Замените 42.56 на 42.44 и сравните, как изменится ROUND
- • Поменяйте TRUNC(42.99::numeric, 1) на ROUND(42.99::numeric, 1) и сравните результат
2. Получаем случайное число в нужном диапазоне
🔄 Попробуйте изменить запрос:
- • Поменяйте верхнюю границу 10000 на 2500
- • Запустите запрос несколько раз подряд и посмотрите, как меняются значения
3. Округляем число до двух знаков после запятой
🔄 Попробуйте изменить запрос:
- • Поменяйте 12.675 на 12.674 и сравните результат
- • Замените аргумент 2 на 1 и посмотрите, как изменится округление
4. Округляем не дробную часть, а десятки, сотни и тысячи
🔄 Попробуйте изменить запрос:
- • Поменяйте число 15432 на 14999 и сравните результат округления до сотен и тысяч
- • Замените -3 на 0 и посмотрите, как функция снова переключится на округление до целого
5. Считаем отклонение зарплаты от заданного уровня
🔄 Попробуйте изменить запрос:
- • Замените 100000 на 85000
- • Добавьте в фильтр только отделы 1 и 2
6. Используем POWER и SQRT в одном выражении
🔄 Попробуйте изменить запрос:
- • Поменяйте POWER(5, 3) на POWER(7, 2)
- • Замените 81 на 49 и посмотрите, как изменится вложенное вычисление
7. Считаем полные упаковки и остаток
🔄 Попробуйте изменить запрос:
- • Поменяйте 6 на 8 и посмотрите, как изменятся количество полных коробок и остаток
8. Считаем, сколько полных коробок потребуется для количества товара
🔄 Попробуйте изменить запрос:
- • Поменяйте размер коробки с 4.0 на 6.0
- • Попробуйте заменить CEIL на FLOOR и объясните, почему коробок станет не хватать
Типичные ошибки
Путают ROUND и TRUNC
ROUND округляет, а TRUNC просто отрезает лишнее. Это две разные идеи, и результат у них легко может отличаться.
Не учитывают, что для ROUND(number, digits) часто нужен numeric
Если нужно округлить число до нескольких знаков после запятой, в PostgreSQL нередко приходится явно писать что-то вроде ROUND(value::numeric, 2). Без перевода типа можно упереться в ошибку.
Не знают, что у ROUND второй аргумент может быть отрицательным
ROUND(12567::numeric, -2) — это не ошибка. Так функция округляет число до сотен. Для отчётов и укрупнённых расчётов это очень полезно.
Думают, что CEIL и FLOOR работают как обычное округление
Нет. CEIL всегда идёт вверх, а FLOOR всегда идёт вниз. Даже если число очень близко к целому, логика у них остаётся именно такой.
Путают DIV и MOD
DIV показывает количество полных частей, а MOD — то, что осталось после деления. Обычно они лучше всего понимаются именно в паре.
Путают старый и новый сценарий работы с RANDOM()
Без аргументов RANDOM() возвращает дробное число от 0 до почти 1. А запись вроде RANDOM(1, 10000) доступна в PostgreSQL 17 и выше и сразу даёт число в нужном диапазоне.
Оставляют вычисляемый столбец без понятного имени
Записи вроде ABS(salary - 100000) или ROUND(price::numeric, -2) лучше сразу называть через AS: например diff_from_target или price_to_hundreds. Тогда результат читается намного легче.
Практика
Проверь себя
Ответьте на вопросы, чтобы закрепить материал: