LINUX.ORG.RU

Хранение денег в БД (Postgresql)

 , , ,


2

4

Господа, тут такая проблема...

В общем, нужно хранить данные о товарах. У товара есть закупочная цена (может быть в любой валюте), которая часто бывает дробной, 6 баксов и 56 центов, например. Есть курс валюты, из него высчитывается цена в гривнах (украшка). Гривны округляются до целых.

Собственно говоря, это уже реализованная система, работает около года, всё круто, я собой горд и всё такое, но это глючит. Раз в пару недель появляется какой-нибудь товар, у которого цена округлена почему-то вверх... Или товар не возвращается на склад, т.к. изменился курс доллара и цена в гривнах уже не та...

В общем, работает плохо это. Терпеть можно, но в будущей версии нужно переделывать. Посему вопрос, что посоветуете для хранение денежных величин? Сейчас использую поле numeric в postgresql, храню там дробные числа типа 6.56. Но хочу полностью обезопасить себя от ошибок с числами с плавающей запятой, чтобы в отношении денег всё работало идеально. Посоветуйте проверенные на практике способы?

★★★★★

у вс там деньга в float чтоли? тогда покури про decimal

Deleted ()

А чем тебе numeric не угодил? Это точный тип

unC0Rr ★★★★★ ()
Ответ на: комментарий от observer

Почему-то мне запомнилось, что им не рекомендуется пользоваться, но не вижу ничего такого в документации.

unC0Rr ★★★★★ ()
Ответ на: комментарий от unC0Rr

потому что в Эфиопии и Зимбабве такая инфляция что в этот тип не вложится.

splinter ★★★★★ ()

храни как беззнаковое большое целое и считай в копейках/центах. Точку добавляй уже в представлении.

BaBL ★★★★★ ()

а покажи ка структуру сущностей которые на этом завязаны.

exception13 ★★★★★ ()
Ответ на: комментарий от BaBL

храни как беззнаковое большое целое и считай в копейках/центах. Точку добавляй уже в представлении.

какой-то мускульный подход. PG таки СУБД повёрнутая к человеку лицом и в таких костылях не нуждается. Тем более беззнаковых в PG нет

mashina ★★★★★ ()
Ответ на: комментарий от mashina

СУБД повёрнутая к человеку лицом

Через лицо sql-ем не общаются, sql-ем только чрезопу, так что не то место вы лицом назвали.

Deleted ()
Ответ на: комментарий от mashina

в мускуле таки есть decimal с поддержкой дробной части заданной длины

Harald ★★★★★ ()
Ответ на: комментарий от observer

Since the output of this data type is locale-sensitive, it may not work to load money data into a database that has a different setting of lc_monetary.

а разве у постграса дампы не бинарные где пофиг на это? Я про pg_dump.

true_admin ★★★★★ ()
Ответ на: комментарий от true_admin

точность задается в lc_monetary при инициализации каталога с данными, если в дампе другая точность то ничего хорошего не будет

maxcom ★★★★★ ()
Ответ на: комментарий от true_admin

По умолчанию SQL, бинарный получается с опцией "--format custom". А вот у pg_restore только бинарные)

disarmer ★★★ ()

что посоветуете для хранение денежных величин?

Я думаю, ты понимаешь, что всплывшие проблемы отнюдь не от плохой реализации. Об этом плачутся уже поколения программистов, которым бухи запрещают иметь доли копейки и при этом жалуются на ошибки округления. Им нужна какая-то специальная арифметика =)

GAMer ★★★★★ ()
Ответ на: комментарий от GAMer

не надо бухов спрашивать, нужно хранить в базе и обрабатывать в программе с повышенной точностью (миллионные доли копеек, например), а печатать в интерфейсе и отчётах с округлением до целых копеек. Но при этом ошибки округления всё равно будут, и их надо явно оговаривать в договорах с клиентами

типа такого

«стоимость разговора округляется в большую сторону до целого числа копеек»

строчка такого вида, например, была в абонентском договоре какого-то сотового оператора

Harald ★★★★★ ()
Ответ на: комментарий от Harald

Но при этом ошибки округления всё равно будут, и их надо явно оговаривать в договорах с клиентами

Эти ошибки и будут оговорены в ТЗ: на совесть программы ляжет отслеживание этих ошибок и их автокоррекция.

Т.е. бухов не волнует, как ты там хранишь эти данные, но все отчёты «на гора» должны выдаваться без дробей и сходиться с точностью до копейки.

yyk ★★★★★ ()

Гривны округляются до целых.

А разве подобное допустимо при операциях с деньгами?

у которого цена округлена почему-то вверх...

Мусье прогуливал в начальных классах арифметику? Правила округления давай вспоминай и пиши сюда.

anonymous ()
Ответ на: комментарий от yyk

Т.е. бухов не волнует, как ты там хранишь эти данные, но все отчёты «на гора» должны выдаваться без дробей и сходиться с точностью до копейки.

не будут они сходиться до копейки

Harald ★★★★★ ()
Ответ на: комментарий от yyk

Наивный, видать не сдавал отчетов в ПФР. Представь - куча цифр по периодам, а потом поле ИТОГО, в котором считается сумма по периодам из _исходных_ данных, но которая естественно(так как по периодам в расчётах есть проценты) может не совпасть с суммой по периодам(п1+п2+п3). Вот и приходится кидать несколько рублей из одного периода в другой, чтобы убрать ошибки округления. Операторы связи об этом знают, вся Россия знает, но форма сделана по закону РФ, который отнюдь не математический =\

GAMer ★★★★★ ()
Ответ на: комментарий от mashina

у меня поле numeric, а точность кастомно настроена как «2 знака после запятой». Может в этом дело, а может и нет...

Alve ★★★★★ ()
Ответ на: комментарий от anonymous

А разве подобное допустимо при операциях с деньгами?

Ну это интернет-магазин. Так захотел заказчик, видимо ему возиться с копейками влом, а отчётность не страдает.

Alve ★★★★★ ()

Или товар не возвращается на склад, т.к. изменился курс доллара и цена в гривнах уже не та..

ёпт, и эти люди еще что-то кукарекают про 1сников

anonymous ()
Ответ на: комментарий от GAMer

Вот и приходится кидать несколько рублей из одного периода в другой, чтобы убрать ошибки округления.

Т.е. в итоге таблица всё-таки сходится до копейки? :)

yyk ★★★★★ ()
Ответ на: комментарий от yyk

В итоге-то сходится, но какой ценой... Бухи рыдают и стенают, домой идут уже к ночи... Самое паршивое, что фиксить это они не осиливают, и, в попытках выяснить, что кому куда по какой формуле нужно посчитать, приходится корячиться айтишникам =(

GAMer ★★★★★ ()
Последнее исправление: GAMer (всего исправлений: 2)
Ответ на: комментарий от maxcom

если в дампе другая точность то ничего хорошего не будет

по-моему, когда база зависит от переменных окружения это очень большой архитектурных косяк. Имхо так делать нельзя.

true_admin ★★★★★ ()
Ответ на: комментарий от true_admin

не годится постгрескьюель для ынтырпрайза, академики деньги считать не умеют :)

не то что мускль

Harald ★★★★★ ()
Ответ на: комментарий от true_admin

это не совсем переменные окружения, это переменные на момент когда инициализировалась БД. С lc_collate аналогичная фигня

maxcom ★★★★★ ()
Ответ на: комментарий от maxcom

Я честно говоря, вообще не понимаю сути проблемы. С базой никто напрямую не общается. Так зачем её вывод форматируется согласно какой-то локали? Пусть передаёт raw value которое уже db-прослойка сконвертирует во внутреннее представление программы, а отформатируется это всё перед выводом на экран пользователю.

true_admin ★★★★★ ()
Ответ на: комментарий от true_admin

На СУБД потому что можно переложить много функций. Любая более-менее нормальная СУБД (postgresql считаю таковой )) имеет мощный функционал для обработки множеств. Это сильно ускоряет работу ПО и позволяет скрыть от быдлокода часть бизнеслогики. Я например перекладываю на СУБД функции вычисления некоторых связанных с деньгами величин, вроде там результирующей оптовой или розничной цен. Получается очень быстро и надёжно. Если не считать проблемы с округлением :)

Alve ★★★★★ ()

храните деньги в сберегательной кассе

marvin_yorke ★★★ ()
Ответ на: комментарий от Alve

Да я не спорю что удобно. Но просто в данном случае локаль становится источником ошибок. Вот покажите мне программиста который никогда не заливал битый дамп в базу. Или же не косячил с кодировками. А между тем эти все проблемы решаемы.

Короче, я за error-prone решения.

true_admin ★★★★★ ()
Ответ на: комментарий от true_admin

Вот покажите мне программиста который никогда не заливал битый дамп в базу

так не программист это должен делать, а DBAшник и отвечать за это репой. По крайней мере, везде так где дело касается денег.

mashina ★★★★★ ()
Ответ на: комментарий от mashina

Суть в том что хоть раз ошибался каждый. Так вместо того чтобы набивать шишки давайте просто сделаем так чтобы всегда всё работало вне зависимости от локали.

true_admin ★★★★★ ()
Ответ на: комментарий от Harald

не надо бухов спрашивать, нужно хранить в базе и обрабатывать в программе с повышенной точностью (миллионные доли копеек, например), а печатать в интерфейсе и отчётах с округлением до целых копеек. Но при этом ошибки округления всё равно будут, и их надо явно оговаривать в договорах с клиентами

так как раз делать нельзя. Все конечные данные, т.е. которые проходят в документах и попадают в БД, хранить нужно ровно так, как говорят бухи - т.е. с точностью до копейки. Это, типа, закон - не можешь выставить счёт или что-то продать с дробными копейками (центами и т.п.).

Прорблемы с округлением возникают только в логической транзакции, например, когда нужно посчитать стоимость оказанной услуги. И только здесь можно использовать повышенную точность чтобы корректно округлить финальный результат и записать в БД. ТЗ должно оговаривать какие существуют логические транзакции и как правильно округлять в них результаты.

Если все значения хранить с повышенной точностью, то появление невязки в виде фантомных копеек неизбежно.

mashina ★★★★★ ()
Ответ на: комментарий от mashina

Все конечные данные, т.е. которые проходят в документах и попадают в БД, хранить нужно ровно

суммы денег, проходящие по документам и так будут с целыми копейками и повышенная точность их не испортит. Речь была про суммы, которые получаются в результате расчётов с умножением и делением. Например, начисление процентов и штрафов

Harald ★★★★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.