Дробная часть 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)
Судя по документации, в Postrgesql
вообще всё печально для типа float4
:
PostgreSQL воспринимает запись от
float(1)
доfloat(24)
как выбор типаreal
И далее:
real
- 4 байта - вещественное число с переменной точностью - точность в пределах 6 десятичных цифр
Только 6 десятичных цифр гарантировано, что будут точно переданы, а у вас до запятой уже 7 цифр! Что уж тут беспокоиться про цифры после запятой. Я бы проверил, что сумма хотя бы до запятой одинаково посчиталась в обоих случаях.
В общем, используйте более точные типы данных для денег:
double precision
- 8 байт - вещественное число с переменной точностью - точность в пределах 15 десятичных цифр
numeric
- переменный - вещественное число с указанной точностью - до 131072 цифр до десятичной точки и до 16383 — после
Вообще принято для денег использовать decimal
/numeric
, чтобы гарантированно не потерять ни копейки при расчётах.
перевёл сначала в money (суммы корректно стали рассчитываться, но появился ? в конце), затем перевёл в numeric и всё стало ок, вроде))