Дробная часть SQL

Делаю выборку из таблицы суммы поступлений (изначально столбец в формате float4). Если группирую по месяц, то все корректно отображается (суммы с дробной частью). Если же пытаюсь просто вывести значение без группировки, то выдается число с округлением до целого. Суммирую через SUM(). Пробовал через CAST менять принудительно на float, но не помогает.

select extract(month from pay_date) as month, sum(pay_summ) from kamtent.sales
where pay_date between '2024-01-01' and '2024-12-31'
group by month
order by month
month sum(pay_summ)
1 2406129.0
2 4156632.0
3 2371564.5
4 2435626.0
select sum(pay_summ) from kamtent.sales
where pay_date between '2024-01-01' and '2024-12-31'
sum(pay_summ)
11369952

Ответы (3 шт):

Автор решения: Герман Борисов

Вы видите не число, а то, что получается после перевода его сначала (1) в десятичную систему счисления, а затем (2) в строковое представление, с усечением точности, так как десятичное представление почти всегда является бесконечной дробью.

Первое преобразование прописано в стандарте IEEE 754, второе спрятано где-то внутри программы, в которой вы смотрите на результат.

По стандарту Float4 обеспечивает только 7 точных знаков, 8-й как повезёт, дальше чаще всего будет мусор.

В ваших примерах я вижу, что всё время выводится именно 8 значащих цифр (2406129.0 — 7 до разделителя, и 1 после; 11369952 — все восемь до).

Могу предположить, что представление Float4 как 8 десятичных знаков задано именно средой выполнения.

Пробовал через CAST менять принудительно на float, но не помогает.

Не вижу в документации по postgresql типа float, могу предположить, что этот псевдоним для float4. Попробуйте выполнить cast в float8.

А вообще для денег лучше использовать типы с фиксированной точностью, например, numeric(10,2)

→ Ссылка
Автор решения: CrazyElf

Судя по документации, в Postrgesql вообще всё печально для типа float4:

PostgreSQL воспринимает запись от float(1) до float(24) как выбор типа real

И далее:

real - 4 байта - вещественное число с переменной точностью - точность в пределах 6 десятичных цифр

Только 6 десятичных цифр гарантировано, что будут точно переданы, а у вас до запятой уже 7 цифр! Что уж тут беспокоиться про цифры после запятой. Я бы проверил, что сумма хотя бы до запятой одинаково посчиталась в обоих случаях.

В общем, используйте более точные типы данных для денег:

double precision - 8 байт - вещественное число с переменной точностью - точность в пределах 15 десятичных цифр

numeric - переменный - вещественное число с указанной точностью - до 131072 цифр до десятичной точки и до 16383 — после

Вообще принято для денег использовать decimal/numeric, чтобы гарантированно не потерять ни копейки при расчётах.

→ Ссылка
Автор решения: Денис Куликов

перевёл сначала в money (суммы корректно стали рассчитываться, но появился ? в конце), затем перевёл в numeric и всё стало ок, вроде))

→ Ссылка