172 похожих чатов

Гайз, есть ли подводные камни при альтере поля с float

на decimal?

Как это правильно сделать? Что-то не гуглится. Будто это в принципе не принято делать

32 ответов

7 просмотров

> Гайз, есть ли подводные камни при альтере поля с float на decimal? Хмм... могут быть разве что проблемы с точностью (особенно если выбранного NUMERIC(x, y) не хватает для всех исходных значений). Но с float-ами так всегда. > Как это правильно сделать? Что-то не гуглится. Будто это в принципе не принято делать Я бы не ожидал, что для ALTER COLUMN col /* поле типа x */ TYPE y про каждую возможную пару (x,y) кто-то будет писать в интернете. ;)

Zamira-Norova Автор вопроса
Yaroslav Schekin
> Гайз, есть ли подводные камни при альтере поля с...

Спасибо. В принципе с флоат всегда такая фигня с точностью. Зачем-то у нас он оказывается для денег используется. Хочу поменять Ещё задумываюсь может на integer что бы центы хранить? Тогда при смене типа ещё на 100 умножить как-то надо. Есть ли способ без промежуточный таблицы для миграции?

Zamira Norova
Спасибо. В принципе с флоат всегда такая фигня с т...

> Ещё задумываюсь может на integer что бы центы хранить? При расчётах всё равно часто получаются / используются доли центов / копеек, так что обычно не стоит. > Есть ли способ без промежуточный таблицы для миграции? Просто ALTER COLUMN col TYPE y, если время есть (когда к этой таблице не будут обращаться). Если нет — всё сложнее, но возможно... тут совсем недавно про это спрашивали, кажется.

Zamira-Norova Автор вопроса
Yaroslav Schekin
> Ещё задумываюсь может на integer что бы центы хр...

Если переходить на integer что бы хранить центы, это придется же не просто альтерить. Там надо на 100 умножить

Zamira Norova
Если переходить на integer что бы хранить центы, э...

Это, как раз, несложно: ALTER COLUMN x TYPE bigint USING (100 * x). А вот приложения переписывать (на работу в центах) кто-то будет. ;) > Кстати доли центов не хотим использовать. Ну и ну... А Вы знаете, что в типичных случаях (при достаточных оборотах) Вы так "просеиваете" от единиц до сотен тысяч долларов в год (они просто "исчезают" из расчётов себестоимости, налогов, доходов)? И если есть какие-то контролирующие организации, последствия могут быть ещё более печальными...

Zamira Norova
Если переходить на integer что бы хранить центы, э...

не все валюты имеют размен на 100 частей. https://ru.wikipedia.org/wiki/Существующие_разменные_денежные_единицы#Современные_недесятичные_системы_денежного_счисления_и_другие_исключения

> В валюте долей центов не существует как выше сказали. Это же совершенно неважно! Простой пример: нужно заплатить, к примеру, 18% налог на 100 штук товара ценой 1.25$. "Наивный" расчёт в центах даёт: SELECT 100 * (125 * 18 / 100) = 22$ (а правильная сумма — 22.50$). И такие штуки вполне могут накапливаться (см. выше про "типичные" суммы), и кроме прямых потерь (на refund и т.п.), могут быть и косвенные — в виде штрафов, судебных издержек и стоимости работ по исправлению этого кошмара , если эти расчёты как-то законодательно регулируются. > Поэтому хочу сначала продвинуть идею хотя бы на decimal перейти. В большинстве случаев (если нужны правильные расчёты) для денег используется только этот тип данных.

Zamira-Norova Автор вопроса
Yaroslav Schekin
> В валюте долей центов не существует как выше ска...

Да, в вашем примере неправильный рассчет, если считать от юнит прайс, потом умножать на количество. Мы от line total считаем что бы хоть как-то убавить такие потери Спасибо за советы. Очень ценны. Понимаю проблемы, думаем как решать так, что бы усилия того стоили

Zamira Norova
Да, в вашем примере неправильный рассчет, если счи...

Ну так вот поэтому decimal (он же numeric) и используют в таких случаях — чтоб не думать, как считать, и получать точные результаты. Да и перейти на него в вашем случае проще, как я понял. > Мне очень не нравится поставленная задача перейти на центы А с центами придётся ещё думать, как считать — зачем это нужно? Кстати, см. https://wiki.postgresql.org/wiki/Don%27t_Do_This#Don.27t_use_money (потому что описываемые там проблемы — в основном от подхода "давайте считать в центах").

Zamira-Norova Автор вопроса
Yaroslav Schekin
Ну так вот поэтому decimal (он же numeric) и испол...

Спасибо за статью. Пошла читать Кроме явных проблем там переписывать все, что касается денег в online marketplace приложении. Как минимум по времени и новым багам того не стоит

Zamira-Norova Автор вопроса
Yaroslav Schekin
Ну так вот поэтому decimal (он же numeric) и испол...

Кстати на счет налогов я немного приврала. Мы сами не считаем. Считает сторонний сервис Avalara. Не рентабельно все типы американских налогов в разных штатах у себя реализовать. Хоть тут ответственность не на разработчиках 🙈

Yaroslav Schekin
> В валюте долей центов не существует как выше ска...

А правильная сумма будет 22, 22.50 или 23, в зависимости от местных традицый, на самом деле. Если речь идёт о Российском НДС, например -- то правильным будет 22 либо 23, на выбор. А 22.50 -- неправильным. При этом прямой рассчёт в NUMERIC -- даст 23, если что: (100::int*(1.25::NUMERIC(10,2)*(18::int/100::float))::NUMERIC(10,2))::NUMERIC(10,2); В общем, я во-первых не вижу заментой разницы между NUMERIC и int. Во-вторых -- какое значение является по-настоящему правильным -- это сложный вопрос, но почти во всём можно его правильно посчитать. Хоть во float (хотя боли будет большэ, хужэ того, начинающий разработчик с этим, скорее всего, не справится).

Ilya Anfimov
А правильная сумма будет 22, 22.50 или 23, в завис...

> А правильная сумма будет 22, 22.50 или 23, в зависимости от местных традицый, на самом деле. Возможно, но при работе с numeric это решает программист, а при работе с центами это решается "как повезёт" за него. > Если речь идёт о Российском НДС, например -- то правильным будет 22 либо 23, на выбор. А 22.50 -- неправильным. Я давно не работал с Российским НДС, но раньше это было точно не так. И последствия "в виде штрафов, судебных издержек и стоимости работ по исправлению этого кошмара" именно по этому поводу я видел своими глазами. Кто-то сходу знает, какие там сейчас требования, может прокомментировать? > При этом прямой рассчёт в NUMERIC -- даст 23, если что: Показанный пример не называется "прямой рассчёт в NUMERIC" — это какая-то каша. > В общем, я во-первых не вижу заментой разницы между NUMERIC и int. А она есть, и была продемонстрирована мной выше. Честное слово, у меня уже складывается ощущение (по результатам предыдущих обсуждений), что если Вам показать результат вроде SELECT 23 = 22.50; → f, Вы и с ним будете способны спорить, чтобы "доказать" свою точку зрения, извините. ;( > Хоть во float (хотя боли будет большэ, хужэ того, начинающий разработчик с этим, скорее всего, не справится). Да-да, конечно. См. вот это https://t.me/pgsql/340458 и удачи в расчётах. Мне помнится, у нас так один (начинающий, правда) разработчик бился головой об клавиатуру две недели, пытаясь найти, куда же пропадают копейки в его отчётах. Зато с тех пор навсегда отучился хранить деньги во float. ;)

Yaroslav Schekin
> А правильная сумма будет 22, 22.50 или 23, в зав...

>при работе с центами это решается "как повезёт" за него. Нет. Я могу получить любое из этих чисел при работе что с numeric, что с цэнтами, что с float. Более того, работа с numeric и цэнтами отличается очень несильно. >Я давно не работал с Российским НДС, но раньше это было точно не так. На самом деле это очень давно не менялось -- и я заметно упростил. 22 и 23 -- это на 100 различных продаж (в т.ч., например, при составлении ежэмесячной СФ на продажы физ.лицам). Если это одна строчка счёта-фактуры -- то будет 22,50.

Ilya Anfimov
>при работе с центами это решается "как повезёт" з...

> Нет. Я могу получить любое из этих чисел при работе что с numeric, что с цэнтами, что с float. Не можете. Особенно в случае с float... да я просто процитирую документацию (сколько можно уже!): Inexact means that some values cannot be converted exactly to the internal format and are stored as approximations, so that storing and retrieving a value might show slight discrepancies. Managing these errors and how they propagate through calculations is the subject of an entire branch of mathematics and computer science and will not be discussed here, except for the following points: . If you require exact storage and calculations (such as for monetary amounts), use the numeric type instead. <skip> On all currently supported platforms, the real type has a range of around 1E-37 to 1E+37 with a precision of at least 6 decimal digits. (Выделение моё.) Как возможно считать деньги с precision в шесть десятичных цифр, лично мне непонятно. А (см. сообщение ранее) на принципиальную недетерминированность таких расчётов в SQL Вам есть что сказать?

Yaroslav Schekin
> Нет. Я могу получить любое из этих чисел при раб...

Во-первых, я говорил про float, который здесь double precision, а не real. С real -- действительно всё тяжэлее было бы.

Yaroslav Schekin
> Нет. Я могу получить любое из этих чисел при раб...

И да, у меня нет проблем с тем, что оно inexact -- если вовремя выкидывать ошыбки при помощи округления. (Например, в perl по сути все числа -- double precision floating point, и ничего. Округлял до двух знаков после запятой тем или иным способом на каждом шаге -- и всё работало).

Ilya Anfimov
И да, у меня нет проблем с тем, что оно inexact --...

Да-да, конечно. При чём тут императивный perl (в котором можно точно задать последовательность вычислений)?! Мы SQL тут обсуждаем или что-то "левое"?

Yaroslav Schekin
Да-да, конечно. При чём тут императивный perl (в к...

Я и в SQL могу задать последовательность вычислений. Если надо. Или сделать вычисления, которые не зависят от их последовательности (округление до копеек именно это и делало, если что).

Ilya Anfimov
Во-первых, я говорил про float, который здесь doub...

Это уже [немного] лучше, но Вы же сами писали про максимальные размеры сумм, я правильно помню?

Yaroslav Schekin
Это уже [немного] лучше, но Вы же сами писали про ...

Их надо помнить, да. И ставить лимиты, и делать что-то ещё когда к ним подходишь. Я нигде не утверждал, что будет легко.

Ilya Anfimov
Я и в SQL могу задать последовательность вычислени...

> Я и в SQL могу задать последовательность вычислений. Если надо. "Закат солнца вручную" (и не факт, что каждый раз сделаете, кстати). А вот с numeric ничего задавать не надо — оно просто работает. > округление до копеек именно это и делало, если что Не делало (особенности поведения типов от этого не меняются). Если что-то "считается" специальным образом ("подгоняется" под правила расчётов, которые не соответствуют математике) — это совсем другое дело. И, опять-таки, см. про фундамент.

Ilya Anfimov
Их надо помнить, да. И ставить лимиты, и делать чт...

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

Yaroslav Schekin
А я (и не только я, см. хоть документацию, хоть......

Зато numeric достаточно спецыфичен для SQL, хужэ того, то на что вы рассчитываете — вообще для postgres, а int64 есть везде.

Ilya Anfimov
Зато numeric достаточно спецыфичен для SQL, хужэ т...

> Зато numeric достаточно спецыфичен для SQL Эээ... сейчас не 1990-ые, и arbitrary precision types в современных языках общего назначения сильно прибавилось. > то на что вы рассчитываете — вообще для postgres В других СУБД, насколько мне известно, (constrained) numerics / decimals работают ровно так же. К тому же, кого волнует, что там в других СУБД? ;)

Ilya Anfimov
Зато numeric достаточно спецыфичен для SQL, хужэ т...

Как минимум в java есть BigDecimal, который нативно маппится с numeric в обе стороны

Yaroslav Schekin
> Зато numeric достаточно спецыфичен для SQL Эээ....

Например, вы предлагали сначала unconstrained. Кроме того, например, правила вычисления scale у оракла я так и не понял... Но рассчитывать на то, что оно просто работает — не приходится.

Ilya Anfimov
Например, вы предлагали сначала unconstrained. Кро...

> Например, вы предлагали сначала unconstrained. Хмм... разве? Тем не менее, для работы с деньгами в PostgreSQL хватит и их. > правила вычисления scale у оракла я так и не понял... И, опять-таки, кого это волнует? Это проблемы тех, кто собирается использовать COBOL Oracle. ;) Кстати, можно поискать, какие конкретные типы данных используются для денег в БД "больших" серийных ERP и т.п. систем. > Просто скобки в правильном порядке расставить. Может, с бубном ещё сплясать? От радости работы с системами, где от перемены мест слагаемых меняется сумма надо тщательно выбирать, какое из математически эквивалентных выражений работает так, как нужно... > Возьмём тогда типичную ставку 0.1(6) Я не понял, какую (и где она типична).

Yaroslav Schekin
> Например, вы предлагали сначала unconstrained. ...

Ставку в долях ноль запятая один и шэсть в периоде. Это сейчас российский НДС, если считать его от цэны товара.

Yaroslav Schekin
> Например, вы предлагали сначала unconstrained. ...

И да, сплясать — обязательно. Это налоговый кодэкс, без плясок тут вообще никак. А выбирать — считать налог по каждой позицыи и это суммировать либо суммировать и считать налог — тожэ обязательно. Как раз попытки игнорировать вопрос — как оно считается правильно — и, например, считать всегда с запредельной точностью, и приводят к результатам, не подтверждающимся документами.

Ilya Anfimov
И да, сплясать — обязательно. Это налоговый кодэкс...

> Это сейчас российский НДС, если считать его от цэны товара. А, 20/120 (выделение НДС / "обратная ставка"), ясно. Тем не менее, где-то что-то должно быть написано про требования к вычислениям и округлению — от них и отталкиваются. > И да, сплясать — обязательно. Это налоговый кодэкс, без плясок тут вообще никак. Не надо путать "пляски" с самими вычислениями (которые лежат в фундаменте расчётов) и "пляски" с тем, чтобы "подогнать" результаты под налоговый кодекс. > Как раз попытки игнорировать вопрос Я тут ничего не игнорирую, это Вы пытаетесь мешать мух (проблемы самих типов данных) с котлетами (задачей считать так, чтобы это соответствовало чьим-то требованиям).

Yaroslav Schekin
> Например, вы предлагали сначала unconstrained. ...

Кстати, в COBOL как раз вполне вменяемый decimal и управляемое округление.

Похожие вопросы

Обсуждают сегодня

Вопрос по диагностике ошибок (я знаю в чем, в данном конкретном примере, я знаю, как исправить, пример модельный, понятно, что в реальности бывает намного запутаннее). module...
ⰄⰎⰋⰐⰐⰑⰛⰤⰧⰧⰩⰄ ⰊⰑⰁⰓⰡⰛⰦⰕⰫ
10
А дальше что?.. Записать в файл, потом в Код?.. И потом разбирать как-то?..
Хаскель Моисеевич Гопник
14
Есть какой-нибудь для Delphi/FPC T*Compression(Decompression)Stream на базе LZ4/Zstd/любой другой быстрый(и хорошо сжимающий) алгоритм А ещё лучше в pure pascal А ещё лучше од...
notme
52
А чем вам питонисты не угодили?😂
.
79
доброго времени. db, dw и прочие исполняются при трансляции или при выполнении программы?
lutayyy
10
type TObj = object procedure Init; virtual; end; TObj1 = object(TObj) procedure Init; override; end; procedure TObj1.Init; begin inherited; end; procedur...
Alexander 👋
29
Всем привет, написал код ниже, но он выдает сегфолт, в чем причина? #include <stdio.h> #include <stdlib.h> #include <string.h> struct product { char *name; float price; };...
buzz базз
86
Есть предложения, как подобное можно упростить?
Hemul GM
12
@y0zhig @shizzard А можно я опишу цель и может вообще ерланг мне не подходит. На текущий момент как я понимаю у ерланга есть легковесные потоки и задача выполняется в каком т...
Дмитрий Спиридонов
5
У меня вопросик назрел. Почему, создав класс без наследования и реализации деструктора Destroy, деструктор не вызывался при free. Потом указал наследование от tobject и overri...
Сергей Бычков
9
Карта сайта