> SmartGate 41 752 9863

Числовые функции

Функции для работы с числами

Теория

Достаточно часто числовые значения приходится каким-то образом подготавливать под результат опредеденной задачи: где-то округлить цену, где-то отбросить дробную часть, где-то посчитать остаток от деления, где-то понять, сколько полных упаковок получится собрать, а где-то получить случайное число для тестового сценария.

Числовые функции нужны именно для этого. Вы передаёте функции число или числовое выражение, а она возвращает уже обработанный результат.

Наиболее частой операцией при работе с числами является округление. На эту операцию сделаем акцент.

Возможности функции округления 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

Это хороший пример, потому что сразу видно разницу между похожими функциями. ROUND округляет по обычным правилам, CEIL всегда округляет вверх к целому, FLOOR всегда вниз, а TRUNC вообще не округляет — просто отрезает лишнее.

🔄 Попробуйте изменить запрос:

  • • Замените 42.56 на 42.44 и сравните, как изменится ROUND
  • • Поменяйте TRUNC(42.99::numeric, 1) на ROUND(42.99::numeric, 1) и сравните результат

2. Получаем случайное число в нужном диапазоне

Вызов RANDOM() без аргументов возвращает случайное дробное число от 0 до почти 1. А вызовы вроде RANDOM(1, 10000) и RANDOM(50, 500) выводят случайное число в нужном диапазоне. Важно: такой вариант с двумя аргументами доступен в PostgreSQL 17 и выше.

🔄 Попробуйте изменить запрос:

  • • Поменяйте верхнюю границу 10000 на 2500
  • • Запустите запрос несколько раз подряд и посмотрите, как меняются значения

3. Округляем число до двух знаков после запятой

В первом столбце число округляется до двух знаков после запятой, а во втором для сравнения просто обрезается через TRUNC. Пример еще раз показывает разницу между округлением и простым отсечением лишних цифр.

🔄 Попробуйте изменить запрос:

  • • Поменяйте 12.675 на 12.674 и сравните результат
  • • Замените аргумент 2 на 1 и посмотрите, как изменится округление

4. Округляем не дробную часть, а десятки, сотни и тысячи

Отрицательный второй аргумент означает, что функция работает уже не с дробной частью, а с порядками числа. Поэтому можно отдельно увидеть округление до десятков, сотен и тысяч.

🔄 Попробуйте изменить запрос:

  • • Поменяйте число 15432 на 14999 и сравните результат округления до сотен и тысяч
  • • Замените -3 на 0 и посмотрите, как функция снова переключится на округление до целого

5. Считаем отклонение зарплаты от заданного уровня

Столбец raw_diff показывает обычное отклонение: оно может быть отрицательным или положительным. Функция ABS убирает знак и оставляет только сам размер отклонения. Благодаря этому легко сравнивать, чья зарплата ближе к нужной точке, даже если у одного она выше, а у другого ниже.

🔄 Попробуйте изменить запрос:

  • • Замените 100000 на 85000
  • • Добавьте в фильтр только отделы 1 и 2

6. Используем POWER и SQRT в одном выражении

Числовые функции можно сочетать между собой. В выражении POWER(SQRT(81) + 1, 2) вычисления идут так: сначала SQRT(81) даёт 9, потом к результату прибавляется 1, и уже после этого POWER(10, 2) выводит в результате 100. Такая вложенность нужна не ради красоты, а ради нового вычисления, если оно действительно необходимо.

🔄 Попробуйте изменить запрос:

  • • Поменяйте POWER(5, 3) на POWER(7, 2)
  • • Замените 81 на 49 и посмотрите, как изменится вложенное вычисление

7. Считаем полные упаковки и остаток

Например, есть 29 товаров. В одну коробку помещается 6 штук. Тогда DIV покажет, сколько полных коробок получится собрать, а MOD — сколько товаров останется сверх этого.

🔄 Попробуйте изменить запрос:

  • • Поменяйте 6 на 8 и посмотрите, как изменятся количество полных коробок и остаток

8. Считаем, сколько полных коробок потребуется для количества товара

Если в одну коробку помещается 4 штуки товара, то для 17 штук товара не хватит 4 коробок. Нужна пятая, потому что после раскладки 16 штук одна всё равно останется. Поэтому здесь используется CEIL: функция помогает получить количество коробок с запасом под остаток. Во втором столбце показана та же логика уже для другого размера коробки.

🔄 Попробуйте изменить запрос:

  • • Поменяйте размер коробки с 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. Тогда результат читается намного легче.

Практика

Проверь себя

Ответьте на вопросы, чтобы закрепить материал:

1
В чём главное отличие ROUND от TRUNC?
2
Что делает второй аргумент в выражении ROUND(12567::numeric, -2)?
3
Что вернёт выражение MOD(29, 6)? Введите только число.
4
Какой вариант обычно нужен в PostgreSQL, если вы хотите округлить результат RANDOM() до двух знаков после запятой?
5
Что вернёт выражение ROUND(12567::numeric, -2)? Введите только число.
6
Какая функция всегда округляет число вверх до следующего целого?
7
Напишите запрос к таблице order_items, который выведет order_item_id, order_id, quantity и столбец quantity_remainder. В quantity_remainder нужно показать остаток от деления quantity на 4 через MOD. Оставьте только строки, где quantity >= 3. Сначала должны идти меньшие остатки, потом при одинаковом остатке — большие значения quantity, а потом order_item_id.
8
Напишите запрос к таблице products, который выведет product_id, product_name, price и столбец price_thousands_floor. В price_thousands_floor нужно показать, сколько полных тысяч помещается в цене товара, используя FLOOR(price / 1000.0). Оставьте только товары с ценой от 30000 до 95000. Сначала должны идти большие значения price_thousands_floor, а при равенстве — большие цены.