ROUND — это функция округления. Она нужна почти везде, где сухое число из базы превращается в понятный результат для человека: цена товара, средний чек, процент конверсии, зарплата за месяц, сумма заказа.
Например, база может честно посчитать средний чек как 1487.6666666667, но пользователю, менеджеру или бухгалтерскому отчёту обычно нужен аккуратный вид: 1487.67.
На первый взгляд всё просто: взяли число, округлили, показали. Но в PostgreSQL у ROUND есть важная ловушка: форма с двумя аргументами работает с типом numeric, а не с double precision. Из-за этого запрос может упасть там, где вы ждёте обычного округления.
Разберём спокойно: как работает ROUND, что означает второй аргумент, зачем нужно отрицательное округление и почему для денег лучше сразу использовать numeric.
Что делает ROUND
Чаще всего ROUND используют так:
ROUND(x, n)
Здесь:
x — число, которое нужно округлить;
n — сколько знаков оставить после запятой.
Например, ROUND(3.14159, 2) оставит два знака после запятой и вернёт 3.14.
SELECT
ROUND(3.14159, 2) AS pi_2,
ROUND(3.14159, 0) AS pi_0,
ROUND(2.5, 0) AS half_value;
Результат будет таким:
| pi_2 |
pi_0 |
half_value |
| 3.14 |
3 |
3 |
Если второй аргумент не указать, PostgreSQL округлит число до целого:
SELECT ROUND(12.78) AS rounded_value;
Результат:
То есть эти два выражения по смыслу близки:
SELECT
ROUND(12.78) AS without_scale,
ROUND(12.78, 0) AS with_zero_scale;
Как округляется половина
В PostgreSQL для типа numeric значение ровно посередине округляется от нуля.
Это значит:
2.5 превращается в 3;
-2.5 превращается в -3.
SELECT
ROUND(2.5, 0) AS positive_half,
ROUND(-2.5, 0) AS negative_half;
Такое поведение важно помнить, если вы считаете деньги, бонусы, комиссии или любые суммы, где значение .5 может влиять на итог.
ROUND — это не усечение
Новички иногда путают округление с отбрасыванием лишних знаков.
ROUND округляет число по правилам математики:
SELECT ROUND(3.99, 1) AS rounded_value;
Результат:
А TRUNC просто отрезает лишнее:
SELECT TRUNC(3.99, 1) AS truncated_value;
Результат:
Разница простая:
ROUND смотрит на следующий знак и может увеличить число;
TRUNC ничего не увеличивает, он просто отбрасывает лишние цифры.
Если вы показываете пользователю средний чек, чаще нужен ROUND. Если строите техническую границу или хотите именно «отрезать хвост», тогда может подойти TRUNC.
Округление до двух знаков: цены, суммы и проценты
Самый частый сценарий — округлить сумму до двух знаков после запятой.
Допустим, есть таблица заказов:
SELECT
id,
amount,
ROUND(amount, 2) AS rounded_amount
FROM orders;
Такой запрос удобен, когда сумма может быть рассчитана через деление, скидки, комиссии или среднее значение.
Например, посчитаем средний чек по оплаченным заказам:
SELECT
ROUND(AVG(amount), 2) AS avg_paid_order
FROM orders
WHERE status = 'paid';
Без ROUND база может вернуть длинную дробь. С ROUND результат будет выглядеть аккуратно и привычно для отчёта.
То же самое с процентами:
SELECT
ROUND(paid_orders::numeric / total_orders * 100, 2) AS paid_percent
FROM daily_stats;
Если paid_orders = 37, а total_orders = 125, результат будет 29.60.
Отрицательный второй аргумент: округление до десятков, сотен и тысяч
У ROUND есть возможность, о которой часто забывают: второй аргумент может быть отрицательным.
Если положительное n округляет вправо от запятой, то отрицательное n округляет влево от запятой.
SELECT
ROUND(12345.678, -1) AS to_tens,
ROUND(12345.678, -2) AS to_hundreds,
ROUND(12345.678, -3) AS to_thousands;
Результат:
| to_tens |
to_hundreds |
to_thousands |
| 12350 |
12300 |
12000 |
Что здесь происходит:
-1 — округление до десятков;
-2 — до сотен;
-3 — до тысяч.
Это очень удобно для аналитики. Например, можно быстро разложить заказы по «корзинам» стоимости.
SELECT
ROUND(amount, -2) AS amount_bucket,
COUNT(*) AS orders_count
FROM orders
WHERE status = 'paid'
GROUP BY ROUND(amount, -2)
ORDER BY amount_bucket;
Так заказы с суммами около 1000, 1100, 1200 и дальше попадут в понятные группы. Получится простая гистограмма без отдельной таблицы диапазонов.
Например, результат может выглядеть так:
| amount_bucket |
orders_count |
| 500 |
18 |
| 1000 |
42 |
| 1500 |
31 |
| 2000 |
14 |
Такой отчёт сразу показывает, в каком ценовом диапазоне у вас больше всего заказов.
Главная ловушка PostgreSQL: numeric против double precision
Теперь самый важный момент.
В PostgreSQL есть функция:
ROUND(numeric, integer)
Но нет функции:
ROUND(double precision, integer)
Из-за этого запрос может неожиданно упасть.
Например:
SELECT ROUND(salary / 12.0, 2) AS monthly_pay
FROM employees;
PostgreSQL может выдать ошибку:
ERROR: function round(double precision, integer) does not exist
На первый взгляд странно: ведь ROUND существует. Проблема не в самой функции, а в типе данных.
Выражение salary / 12.0 может стать значением типа double precision. А PostgreSQL не умеет применять двухаргументный ROUND к double precision.
Решение — явно привести число к numeric:
SELECT
name,
ROUND(salary::numeric / 12, 2) AS monthly_pay
FROM employees;
Теперь PostgreSQL понимает, какую именно версию функции нужно вызвать.
Почему ошибка кажется особенно коварной
Одноаргументный ROUND для double precision в PostgreSQL есть.
То есть такой запрос может работать:
SELECT ROUND(salary / 12.0) AS monthly_pay
FROM employees;
А такой — уже нет:
SELECT ROUND(salary / 12.0, 2) AS monthly_pay
FROM employees;
Получается неприятная ситуация: пока вы округляете до целого, всё хорошо. Как только добавляете второй аргумент, запрос ломается.
Поэтому для PostgreSQL полезно запомнить простое правило:
если используете ROUND(x, n), особенно для денег, приводите значение к numeric или храните его как numeric изначально.
Почему для денег лучше numeric
double precision хранит число приближённо. Это тип с плавающей точкой, и он не всегда может точно представить десятичные дроби.
Например, значение 0.1 в таком формате может храниться не как идеально точное 0.1, а как очень близкое к нему двоичное приближение.
Для научных расчётов, координат, измерений или статистики это часто нормально. Но для денег такие мелкие погрешности могут превращаться в неприятные копеечные расхождения.
Для денежных сумм лучше использовать десятичный тип:
CREATE TABLE orders (
id bigint,
amount numeric(12, 2),
status text
);
numeric(12, 2) означает:
- всего до 12 цифр;
- 2 цифры после запятой.
Например, туда хорошо ложатся суммы вроде 9999999999.99.
Если сумма изначально хранится как numeric, запросы становятся проще:
SELECT
ROUND(SUM(amount), 2) AS total_amount
FROM orders
WHERE status = 'paid';
Не нужно каждый раз думать, почему PostgreSQL не нашёл подходящую функцию.
ROUND не отвечает за красивый внешний вид
ROUND округляет число. Но он не делает из числа красивую денежную строку.
Он не обязан:
- добавлять знак валюты;
- ставить разделители тысяч;
- красиво выравнивать число;
- превращать результат в текст для интерфейса.
Для внешнего вида в PostgreSQL используют to_char.
Посчитаем общую сумму заказов пользователя:
SELECT
u.name,
SUM(o.amount) AS raw_total,
ROUND(SUM(o.amount), 2) AS rounded_total,
to_char(ROUND(SUM(o.amount), 2), 'FM999G999D00') AS pretty_total
FROM users u
JOIN orders o ON o.user_id = u.id
WHERE o.status = 'paid'
GROUP BY u.name;
Что здесь происходит:
SUM(o.amount) считает исходную сумму;
ROUND(SUM(o.amount), 2) округляет её до двух знаков;
to_char превращает число в красиво отформатированную строку.
Маска FM999G999D00 читается так:
FM убирает лишние пробелы;
G ставит разделитель групп разрядов;
D обозначает десятичный разделитель;
00 фиксирует два знака после запятой.
Хорошая привычка: отдельно считайте число и отдельно форматируйте его для показа.
ROUND — для точности.
to_char — для внешнего вида.
Пример из реального отчёта
Допустим, нужно показать по каждому пользователю:
- сколько заказов он оплатил;
- общую сумму;
- средний чек;
- красивую сумму для интерфейса.
SELECT
u.name,
COUNT(o.id) AS paid_orders,
ROUND(SUM(o.amount), 2) AS total_amount,
ROUND(AVG(o.amount), 2) AS avg_order_amount,
to_char(ROUND(SUM(o.amount), 2), 'FM999G999D00') AS pretty_total
FROM users u
JOIN orders o ON o.user_id = u.id
WHERE o.status = 'paid'
GROUP BY u.name
ORDER BY total_amount DESC;
Такой запрос уже похож на настоящий кусок аналитики для личного кабинета, админки или финансового отчёта.
Здесь ROUND делает результат аккуратным, но сами расчёты остаются числовыми. Это важно: если вы слишком рано превратите сумму в текст, её будет неудобно сортировать, складывать и использовать в дальнейших вычислениях.
Отличия MySQL
В MySQL двухаргументный ROUND(x, n) работает привычно и принимает разные числовые типы без такого сюрприза, как в PostgreSQL с double precision.
SELECT
ROUND(amount, 2) AS rounded_amount
FROM orders;
Отрицательный второй аргумент тоже работает:
SELECT
ROUND(amount, -2) AS amount_bucket,
COUNT(*) AS orders_count
FROM orders
GROUP BY ROUND(amount, -2)
ORDER BY amount_bucket;
Для красивого денежного формата с двумя знаками после запятой в MySQL можно использовать FORMAT.
SELECT
FORMAT(ROUND(amount, 2), 2) AS pretty_amount
FROM orders;
Но идея остаётся той же: округление и форматирование — разные задачи.
Отличия ClickHouse
В ClickHouse у ROUND тоже есть форма с двумя аргументами:
SELECT round(amount, 2) AS rounded_amount
FROM orders;
Но у ClickHouse есть важная особенность: для чисел с плавающей точкой округление половины может быть банковским, то есть к ближайшему чётному числу.
Например:
SELECT
round(2.5) AS rounded_2_5,
roundBankers(3.5) AS bankers_3_5;
Результат может отличаться от привычного ожидания в PostgreSQL или MySQL:
| rounded_2_5 |
bankers_3_5 |
| 2 |
4 |
Банковское округление называют half to even: если число ровно посередине, выбирается ближайшее чётное значение.
Поэтому при переносе запросов между PostgreSQL, MySQL и ClickHouse не стоит слепо доверять одному названию ROUND. Лучше проверить поведение на простых значениях:
SELECT
round(2.5) AS test_1,
round(3.5) AS test_2,
round(4.5) AS test_3;
Особенно это важно для финансовых расчётов, комиссий и отчётов, где правила округления должны быть одинаковыми.
Частые сценарии использования ROUND
ROUND чаще всего встречается в таких задачах:
- Округлить средний чек:
SELECT
ROUND(AVG(amount), 2) AS avg_order_amount
FROM orders
WHERE status = 'paid';
- Посчитать процент:
SELECT
ROUND(success_count::numeric / total_count * 100, 2) AS success_percent
FROM metrics;
- Сгруппировать суммы по сотням:
SELECT
ROUND(amount, -2) AS amount_bucket,
COUNT(*) AS orders_count
FROM orders
GROUP BY ROUND(amount, -2)
ORDER BY amount_bucket;
- Округлить результат деления:
SELECT
name,
ROUND(total_score::numeric / attempts_count, 2) AS avg_score
FROM students;
- Подготовить число для отчёта:
SELECT
category,
ROUND(SUM(revenue), 2) AS revenue
FROM sales
GROUP BY category
ORDER BY revenue DESC;
Что важно запомнить
ROUND(x, n) округляет число x до n знаков после запятой.
Если n не указать, число округляется до целого:
SELECT ROUND(9.7) AS rounded_value;
Если n положительное, округление идёт вправо от запятой:
SELECT ROUND(9.876, 2) AS rounded_value;
Если n отрицательное, округление идёт влево от запятой:
SELECT ROUND(9876, -2) AS rounded_value;
В PostgreSQL двухаргументная форма ROUND(x, n) работает с numeric, но не с double precision.
Поэтому для таких выражений лучше явно делать приведение:
SELECT ROUND(value::numeric, 2) AS rounded_value
FROM measurements;
Для денег лучше хранить суммы как numeric(12, 2) или другой подходящий numeric, а не как double precision.
ROUND округляет число, но не форматирует его для красивого вывода. Для внешнего вида в PostgreSQL используйте to_char.
Главное правило простое: используйте ROUND, когда нужна числовая точность, и не забывайте про numeric, если работаете в PostgreSQL с двумя аргументами.
ROUND— это функция округления. Она нужна почти везде, где сухое число из базы превращается в понятный результат для человека: цена товара, средний чек, процент конверсии, зарплата за месяц, сумма заказа.Например, база может честно посчитать средний чек как
1487.6666666667, но пользователю, менеджеру или бухгалтерскому отчёту обычно нужен аккуратный вид:1487.67.На первый взгляд всё просто: взяли число, округлили, показали. Но в PostgreSQL у
ROUNDесть важная ловушка: форма с двумя аргументами работает с типомnumeric, а не сdouble precision. Из-за этого запрос может упасть там, где вы ждёте обычного округления.Разберём спокойно: как работает
ROUND, что означает второй аргумент, зачем нужно отрицательное округление и почему для денег лучше сразу использоватьnumeric.Что делает ROUND
Чаще всего
ROUNDиспользуют так:Здесь:
x— число, которое нужно округлить;n— сколько знаков оставить после запятой.Например,
ROUND(3.14159, 2)оставит два знака после запятой и вернёт3.14.SELECT ROUND(3.14159, 2) AS pi_2, ROUND(3.14159, 0) AS pi_0, ROUND(2.5, 0) AS half_value;Результат будет таким:
Если второй аргумент не указать, PostgreSQL округлит число до целого:
SELECT ROUND(12.78) AS rounded_value;Результат:
То есть эти два выражения по смыслу близки:
SELECT ROUND(12.78) AS without_scale, ROUND(12.78, 0) AS with_zero_scale;Как округляется половина
В PostgreSQL для типа
numericзначение ровно посередине округляется от нуля.Это значит:
2.5превращается в3;-2.5превращается в-3.SELECT ROUND(2.5, 0) AS positive_half, ROUND(-2.5, 0) AS negative_half;Такое поведение важно помнить, если вы считаете деньги, бонусы, комиссии или любые суммы, где значение
.5может влиять на итог.ROUND — это не усечение
Новички иногда путают округление с отбрасыванием лишних знаков.
ROUNDокругляет число по правилам математики:SELECT ROUND(3.99, 1) AS rounded_value;Результат:
А
TRUNCпросто отрезает лишнее:SELECT TRUNC(3.99, 1) AS truncated_value;Результат:
Разница простая:
ROUNDсмотрит на следующий знак и может увеличить число;TRUNCничего не увеличивает, он просто отбрасывает лишние цифры.Если вы показываете пользователю средний чек, чаще нужен
ROUND. Если строите техническую границу или хотите именно «отрезать хвост», тогда может подойтиTRUNC.Округление до двух знаков: цены, суммы и проценты
Самый частый сценарий — округлить сумму до двух знаков после запятой.
Допустим, есть таблица заказов:
SELECT id, amount, ROUND(amount, 2) AS rounded_amount FROM orders;Такой запрос удобен, когда сумма может быть рассчитана через деление, скидки, комиссии или среднее значение.
Например, посчитаем средний чек по оплаченным заказам:
SELECT ROUND(AVG(amount), 2) AS avg_paid_order FROM orders WHERE status = 'paid';Без
ROUNDбаза может вернуть длинную дробь. СROUNDрезультат будет выглядеть аккуратно и привычно для отчёта.То же самое с процентами:
SELECT ROUND(paid_orders::numeric / total_orders * 100, 2) AS paid_percent FROM daily_stats;Если
paid_orders = 37, аtotal_orders = 125, результат будет29.60.Отрицательный второй аргумент: округление до десятков, сотен и тысяч
У
ROUNDесть возможность, о которой часто забывают: второй аргумент может быть отрицательным.Если положительное
nокругляет вправо от запятой, то отрицательноеnокругляет влево от запятой.SELECT ROUND(12345.678, -1) AS to_tens, ROUND(12345.678, -2) AS to_hundreds, ROUND(12345.678, -3) AS to_thousands;Результат:
Что здесь происходит:
-1— округление до десятков;-2— до сотен;-3— до тысяч.Это очень удобно для аналитики. Например, можно быстро разложить заказы по «корзинам» стоимости.
SELECT ROUND(amount, -2) AS amount_bucket, COUNT(*) AS orders_count FROM orders WHERE status = 'paid' GROUP BY ROUND(amount, -2) ORDER BY amount_bucket;Так заказы с суммами около
1000,1100,1200и дальше попадут в понятные группы. Получится простая гистограмма без отдельной таблицы диапазонов.Например, результат может выглядеть так:
Такой отчёт сразу показывает, в каком ценовом диапазоне у вас больше всего заказов.
Главная ловушка PostgreSQL: numeric против double precision
Теперь самый важный момент.
В PostgreSQL есть функция:
ROUND(numeric, integer)Но нет функции:
ROUND(double precision, integer)Из-за этого запрос может неожиданно упасть.
Например:
SELECT ROUND(salary / 12.0, 2) AS monthly_pay FROM employees;PostgreSQL может выдать ошибку:
На первый взгляд странно: ведь
ROUNDсуществует. Проблема не в самой функции, а в типе данных.Выражение
salary / 12.0может стать значением типаdouble precision. А PostgreSQL не умеет применять двухаргументныйROUNDкdouble precision.Решение — явно привести число к
numeric:SELECT name, ROUND(salary::numeric / 12, 2) AS monthly_pay FROM employees;Теперь PostgreSQL понимает, какую именно версию функции нужно вызвать.
Почему ошибка кажется особенно коварной
Одноаргументный
ROUNDдляdouble precisionв PostgreSQL есть.То есть такой запрос может работать:
SELECT ROUND(salary / 12.0) AS monthly_pay FROM employees;А такой — уже нет:
SELECT ROUND(salary / 12.0, 2) AS monthly_pay FROM employees;Получается неприятная ситуация: пока вы округляете до целого, всё хорошо. Как только добавляете второй аргумент, запрос ломается.
Поэтому для PostgreSQL полезно запомнить простое правило:
если используете
ROUND(x, n), особенно для денег, приводите значение кnumericили храните его какnumericизначально.Почему для денег лучше numeric
double precisionхранит число приближённо. Это тип с плавающей точкой, и он не всегда может точно представить десятичные дроби.Например, значение
0.1в таком формате может храниться не как идеально точное0.1, а как очень близкое к нему двоичное приближение.Для научных расчётов, координат, измерений или статистики это часто нормально. Но для денег такие мелкие погрешности могут превращаться в неприятные копеечные расхождения.
Для денежных сумм лучше использовать десятичный тип:
CREATE TABLE orders ( id bigint, amount numeric(12, 2), status text );numeric(12, 2)означает:Например, туда хорошо ложатся суммы вроде
9999999999.99.Если сумма изначально хранится как
numeric, запросы становятся проще:SELECT ROUND(SUM(amount), 2) AS total_amount FROM orders WHERE status = 'paid';Не нужно каждый раз думать, почему PostgreSQL не нашёл подходящую функцию.
ROUND не отвечает за красивый внешний вид
ROUNDокругляет число. Но он не делает из числа красивую денежную строку.Он не обязан:
Для внешнего вида в PostgreSQL используют
to_char.Посчитаем общую сумму заказов пользователя:
SELECT u.name, SUM(o.amount) AS raw_total, ROUND(SUM(o.amount), 2) AS rounded_total, to_char(ROUND(SUM(o.amount), 2), 'FM999G999D00') AS pretty_total FROM users u JOIN orders o ON o.user_id = u.id WHERE o.status = 'paid' GROUP BY u.name;Что здесь происходит:
SUM(o.amount)считает исходную сумму;ROUND(SUM(o.amount), 2)округляет её до двух знаков;to_charпревращает число в красиво отформатированную строку.Маска
FM999G999D00читается так:FMубирает лишние пробелы;Gставит разделитель групп разрядов;Dобозначает десятичный разделитель;00фиксирует два знака после запятой.Хорошая привычка: отдельно считайте число и отдельно форматируйте его для показа.
ROUND— для точности.to_char— для внешнего вида.Пример из реального отчёта
Допустим, нужно показать по каждому пользователю:
SELECT u.name, COUNT(o.id) AS paid_orders, ROUND(SUM(o.amount), 2) AS total_amount, ROUND(AVG(o.amount), 2) AS avg_order_amount, to_char(ROUND(SUM(o.amount), 2), 'FM999G999D00') AS pretty_total FROM users u JOIN orders o ON o.user_id = u.id WHERE o.status = 'paid' GROUP BY u.name ORDER BY total_amount DESC;Такой запрос уже похож на настоящий кусок аналитики для личного кабинета, админки или финансового отчёта.
Здесь
ROUNDделает результат аккуратным, но сами расчёты остаются числовыми. Это важно: если вы слишком рано превратите сумму в текст, её будет неудобно сортировать, складывать и использовать в дальнейших вычислениях.Отличия MySQL
В MySQL двухаргументный
ROUND(x, n)работает привычно и принимает разные числовые типы без такого сюрприза, как в PostgreSQL сdouble precision.SELECT ROUND(amount, 2) AS rounded_amount FROM orders;Отрицательный второй аргумент тоже работает:
SELECT ROUND(amount, -2) AS amount_bucket, COUNT(*) AS orders_count FROM orders GROUP BY ROUND(amount, -2) ORDER BY amount_bucket;Для красивого денежного формата с двумя знаками после запятой в MySQL можно использовать
FORMAT.SELECT FORMAT(ROUND(amount, 2), 2) AS pretty_amount FROM orders;Но идея остаётся той же: округление и форматирование — разные задачи.
Отличия ClickHouse
В ClickHouse у
ROUNDтоже есть форма с двумя аргументами:SELECT round(amount, 2) AS rounded_amount FROM orders;Но у ClickHouse есть важная особенность: для чисел с плавающей точкой округление половины может быть банковским, то есть к ближайшему чётному числу.
Например:
SELECT round(2.5) AS rounded_2_5, roundBankers(3.5) AS bankers_3_5;Результат может отличаться от привычного ожидания в PostgreSQL или MySQL:
Банковское округление называют
half to even: если число ровно посередине, выбирается ближайшее чётное значение.Поэтому при переносе запросов между PostgreSQL, MySQL и ClickHouse не стоит слепо доверять одному названию
ROUND. Лучше проверить поведение на простых значениях:SELECT round(2.5) AS test_1, round(3.5) AS test_2, round(4.5) AS test_3;Особенно это важно для финансовых расчётов, комиссий и отчётов, где правила округления должны быть одинаковыми.
Частые сценарии использования ROUND
ROUNDчаще всего встречается в таких задачах:SELECT ROUND(AVG(amount), 2) AS avg_order_amount FROM orders WHERE status = 'paid';SELECT ROUND(success_count::numeric / total_count * 100, 2) AS success_percent FROM metrics;SELECT ROUND(amount, -2) AS amount_bucket, COUNT(*) AS orders_count FROM orders GROUP BY ROUND(amount, -2) ORDER BY amount_bucket;SELECT name, ROUND(total_score::numeric / attempts_count, 2) AS avg_score FROM students;SELECT category, ROUND(SUM(revenue), 2) AS revenue FROM sales GROUP BY category ORDER BY revenue DESC;Что важно запомнить
ROUND(x, n)округляет числоxдоnзнаков после запятой.Если
nне указать, число округляется до целого:SELECT ROUND(9.7) AS rounded_value;Если
nположительное, округление идёт вправо от запятой:SELECT ROUND(9.876, 2) AS rounded_value;Если
nотрицательное, округление идёт влево от запятой:SELECT ROUND(9876, -2) AS rounded_value;В PostgreSQL двухаргументная форма
ROUND(x, n)работает сnumeric, но не сdouble precision.Поэтому для таких выражений лучше явно делать приведение:
SELECT ROUND(value::numeric, 2) AS rounded_value FROM measurements;Для денег лучше хранить суммы как
numeric(12, 2)или другой подходящийnumeric, а не какdouble precision.ROUNDокругляет число, но не форматирует его для красивого вывода. Для внешнего вида в PostgreSQL используйтеto_char.Главное правило простое: используйте
ROUND, когда нужна числовая точность, и не забывайте проnumeric, если работаете в PostgreSQL с двумя аргументами.