Как стать автором
Обновить

Комментарии 53

Поддерживаю вопрос и автору нужно написать статью как устроен этот тип в Postgres.
Когда игрался просто для себя, то обнаружил, что этот тип поля подтягивает валюту из локали, которые очень желательно установить (на случай, если вы хотите использовать "местную" валюту).
Но вроде как можно управлять этим по хитрому, задавая временно локаль при вставке значения (но это не точно, а проверять лень).
Документация прям крайне скупа на счет этого типа https://www.postgresql.org/docs/current/datatype-money.html

Это обертка над decimal

Если бы. Это обертка над bigint/int8. То есть двоичное с фиксированной запятой, проблемы которого при делении я показал в статье.

Поправочка. НДС не считается по документу.

2. Сумма налога, предъявляемая налогоплательщиком покупателю товаров (работ, услуг), исчисляется по каждому виду этих товаров (работ, услуг) как соответствующая налоговой ставке процентная доля ...

Да, для туториала я взял упрощенный пример и использовал только одну ставку НДС 18%, вместо нескольких. В противном случае итоги считаются по каждой налоговой ставке отдельно.

да даже при одинаковой налоговой ставке, сумма налога считается по каждой строке и никогда не считается от суммы документа

если мы говорим про российский бух учет конечно

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

Все верно. И в книгу покупок и продаж попадает именно сумма налога из строк фактуры, а не вычисленная умножением суммы документа на ставку. Это будет та-же самая сумма которая отображается в печатной форме сф в итоговой строке.

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

Она и не будет. Т,к. если в случае корректировки фактуры разные строки будут давать увеличение и уменьшение суммы, то они попадают в разные книги. Никто не оперирует ндс-ом по документу. Всегда обрабатывается ндс по строкам. А если у вас математика по строке не пойдет - то либо бухгалтерия съест либо потребитель.

А при чем тут корректировка? Речь идет о формировании новой счет-фактуры с одинаковой ставкой НДС по всем строкам.

Никто не оперирует ндс-ом по документу.

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

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

Ну т.е. по факту вы подгоняете сумму ндс по общую сумму документа?

В примере, так как ставка НДС во всех строках одинаковая - да. На практике - в разрезе ставок НДС.

ни разу не встречал бухгалтерию которая бы так работала

В связи с тем, что я еще с 90-х годов занимался локализацией зарубежных ERP систем (Platinum, ERA, Navision, Axapta), то сталкивался с подобными требования регулярно. Возможно, среди всей Вашей кучи заказчиков просто не было поставщиков, формирующих счета-фактуры из сотен строк, а на копеечные отклонения в книге покупок ФНС не заостряла внимание. Следует понимать, что для того, чтобы расхождение достигло рубля, на которое уже точно ФНС обратит внимание, счет-фактура должна содержать хотя бы пару сотен строк.

И сумму ндс по книге как раз никто не сравнивает.

То есть Вы опросили абсолютно всех в РФ бухгалтеров и работников ФНС и не нашли среди них ни одного проверяющего расчет НДС в строках книги покупок? И к тому же уверены, что час назад такой не появился?

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

0.3*0.18=0.072

Тут правильно 0.4*0.18=0.072

Спасибо! Исправил.

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

Слышал разные точки зрения от бухгалтеров.

Слышал разные точки зрения от бухгалтеров.

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

Мне кажется, что общую погрешность точно не надо распределять на те строки, где нет "своей" погрешности - например, на строки без копеек или с 50 копейками (для 18%). А только на строки, где погрешность и возникает.

Возможный подход. Но не лучший. Формально, если посчитать относительную погрешность между точным и откорректированным для нивелирования погрешности результатом, то ваш способ даст бОльшее значение максимальной относительной погрешности. Как показательный пример - надо отнять избыточную копейку из трёх сумм, две из них по одной копейке, третья - рубль. По вашей логике следует лишнюю копейку отнять от одной из копеек, обнулив её... Тут видны сразу два косяка - и нулевая итоговая сумма, и разные финальные суммы для тех, что были одинаковы до корректировки.

Мне, кстати, лет 20 назад приходил квиток на доплату квартплаты в 0-00, причём его присылали аж два раза. Хорошо, что третий раз его включили отдельной строкой в квиток за следующий месяц, а то, может, я б эту задолженность и до сих пор не оплатил...

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

Разные варианты бывают.

нулевая итоговая сумма

Это как раз нормально. НДС с суммы 1-2 копеек и так получается нулевым. Базовые суммы то мы не трогаем.

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

Я имел в виду ситуацию примерно как на картинке. Тут получается расхождение в 1 копейку, но если добавить её к первой строке с 100 руб. будет выглядеть как минимум странно: вместо 18 руб почему-то 18.01 руб. По мне так корректнее добавить к одной из других строк, где есть погрешность.

Проверьте Ваш пример на запросе из статьи. Можете менять как угодно порядок строк. На строку, где нет погрешности при вычислении НДС, накопленная погрешность никогда не попадет.

Этот способ имеет тот недостаток, что уменьшая относительную погрешность приводит к увеличению абсолютной. И если к погрешности в одну копейку в строке ФНС точно не придерется, то к погрешности в рубль - вполне.

Одно время с клиентом на эту тему официально общались. Там главбух тоже сначала хотел относить ошибку округления на наибольшие суммы. Привели ему пример счет-фактуру Metro Cash&Carry из нескольких сотен позиций с одинаковой суммой, на которых накапливалась ошибка в минус(!) больше рубля. Если отнести её на единственную строку с максимальной суммой, то получался явный косяк.

Сейчас ФНС, не редко, спокойно относится к погрешности до рубля. Но как только на строке или в итоге погрешность достигнет рубля - счет-фактуру почти наверняка признают недействительной.

А тут просто иных вариантов нет, кроме распределения. Например, в книгу покупок и книгу продаж попадает счет-фактура, а не строки по ней.

При ручном распределении, обычно, списывают все эти копейки на строку с максимальной суммой. При автоматическом - используется предложенный в статье способ размазывания не более, чем по 1 копейке на строку.

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

Давайте сформулируем результат немножко по-другому: применяя такой подход, мы получаем недетерминированный запрос.

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

применяя такой подход, мы получаем недетерминированный запрос

и сами же ответили

ввели поле Line, которое однозначно фиксирует порядок записей в группе

Но чисто по опыту - количество систем, имеющих подобную фичу

У нас опыт разный. Я то застал момент, когда появились счета-фактуры, поставившие на уши всех разработчиков ERP и учетных систем как раз из-за необходимости распределения накопленной ошибки округления по строкам документов. Это сейчас об этом стали забывать, как о давно написанном функционале )

Хорошая тема. На самом деле объемная. Тут много аспектов разных.

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

Так вот, все суммы, все расчеты всегда ведутся в миноритарных единицах. Т.е. при том, что формат хранения сумм - фиксированная точка, но формат всегда с 0 знаков после запятой.

Так сделано потому что банк работает с многими валютами. И не для всех подходит два знака после запятой. Есть валюты (например, бельгийский франк BEF, итальянская лира ITL, японская йена JPY) где миноритарных единиц вообще нет. А есть валюты (бахрейнский динар BHD, оманский реал OMR, тунисский динар TND) где в одной мажоритарной 1000 миноритарных единиц. И чтобы все это привести к единому знаменателю используется такой вот прием - все считается в миноритарных. Ну а при отображении, конвертации уже смотрим по справочнику валют.

Второй момент - мы используем для бизнес-логики язык RPG (пропертиарный язык IBM, распространен на платформе IBM i на которой работают наши сервера я писал о нем). Там на уровне самого языка поддерживаются все типы данных из БД и арифметика с ними. И там поддерживаются операции с округлением когда для присвоении значения с большим количеством десятичных разрядов переменной с меньшим количеством десятичных разрядов "незначащие" разряды отбрасываются с округлением:

dcl-s val packed(15: 2); // тип с фиксированной точкой, соответсвующий SQL типу decimal(15, 0)

val = 79.90 *18 / 118; // ~= 12.1881 -последние два разряда будут отброшены, val = 12.18
eval(h) val = 79.90 * 18 / 118; // а вот тут уже используется команда eval(h) - операция с округлением и val = 12.19

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

И тут еще может возникнуть переполнение, которое вызовет системное исключение (результат неправильный, работать дальше нельзя). Которое, если все делать правильно, тоже нужно обрабатывать. Или заранее проверять:

dcl-s minVal    packed(15: 0) inz(*loval) const;  // Спецальное значение - "минимально возможное значени для данного типа" - в данном случае -999999999999999
dcl-s maxVal    packed(15: 0) inz(*hival) const;  // Спецальное значение - "максимально возможное значени для данного типа" - в данном случае 999999999999999
dcl-s interRslt packed(63: 0);                    // Для хранения промежуточного результата
dcl-s val1      packed(15: 0);
dcl-s val2      packed(15: 0);
dcl-s val3      packed(15: 0);

eval(h) interRslt = (val1 * val2) * 18 / 118;

select;
  when interRslt < minVal;
    val3 = minVal;
    // и тут генеируем ошибку "выход за нижнюю границу"
  when interRslt > maxVal;
    val3 = maxVal;
    // и тут генеируем ошибку "выход за верхнюю границу"
  other;
    val3 = interRslt;
    // тут все хорошо - переполнения не будет, результат корректный
endsl;  

Примерно как-то так. Если не важно за какую границу выехали, то можно и проще (аналог try/catch)

dcl-s val1      packed(15: 0);
dcl-s val2      packed(15: 0);
dcl-s val3      packed(15: 0);

monitor;
  eval(h) val3 = (val1 * val2) * 18 / 118;
on-excp 'MCH1210';
  // Перехват исключения о переполнении с кодом MCH1210 - Receiver value too small to hold result
  // возвращаем соотв. ошибку, падения программы при это не происходит т.к. исключение перехвачено и обработано
endmon;

Так что поднятая в статье тема финансовых расчетов не такая простая как кажется. И ошибки тут недопустимы ни в коем случае. Потому что

  • речь идет о деньгах

  • речь идет о чужих деньгах

  • речь идет о (потенциально) очень больших чужих деньгах

Цена ошибки может быть очень высока.

я тоже сразу подумал, что хранить и производить вычисления лучше в копейках. а как у вас пользователи вводят значения - сразу в миноритарных единицах или для каждой валюты пересчитываете из маж. в мин.?

Вот насчет как вводят не в курсе, увы... Я не по этой теме работаю - "автоматизация процессов комплаенс-контроля". Там все больше клиентские данные да всякие злодеи-бармалеи (террористы-экстремисты) - поиск совпадений по данным с данными из списков росфинмониторинга и т.п.

Просто приходилось в рамках задачи комплаенс-проверок для контроля платежей в системе расчетов проверять "суммы на кредитных/депозитных счетах клиента в рублевом эквиваленте".

Думаю, что вводят нормально, потом уже в БД это кладется в миноритарных по справочнику валют. Там вообще все сложно - сервера от внешнего мира изолированы. Ввод идет где-нибудь на "внешней системе", дальше через REST API дергается веб-сервис (Java) на нашей UWS шине а он уже дергает связанный с ним сервис-модуль (RPG) на сервере...

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

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

Есть правила регулятора - когда с округлением, когда без... Благо язык все это поддерживает (потому, собственно, и используется - на этой платформе на нем более 80% кода написано - там достаточно мощно в плане работы с БД и всяких операций с суммами, датами, временем и т.п. и по скорости хорош).

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

Как я указал выше, это приводит к корректному результату только при отсутствии операций деления. Ну или при каждом целочисленном делении нужно выделять так же остаток от деления, сдвигать его на один бит влево и сравнивать с делителем. Если делитель окажется меньше или равен - инкрементировать частное. В качестве примера можно посмотреть, как это делается в dotnet-core функцией VarDecDiv.

В случае PostgreSQL такой алгоритм - большой геморрой.

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

При чем тут целочисленное деление? Форматы с фиксированной точкой (а все финансовые расчеты делаются в этих форматах), даже если указано 0 знаков после запятой, не целочисленные. Есть формат конечного результата, есть формат промежуточного результата. Промежуточный результат всегда обеспечивает максимальную точность. А дальше уже указываем как его заносить в окончательный - с округлением или без.

Все это документировано - Precision Rules for Numeric Operations и абсолютно прозрачно и предсказуемо.

Форматы с фиксированной точкой (а все финансовые расчеты делаются в этих форматах), даже если указано 0 знаков после запятой, не целочисленные.

Это не так. В том числе и money в PostgreSQL, и Decimal в dotnet-core или Java.

Поэтому для финансовых расчетов используются либо десятичные форматы (decimal/numeric), либо, как в dotnet-core по моей ссылке, применяется алгоритм коррекции частного после деления.

Конкретно в RPG, результат деления всегда либо float, либо packed decimal. Но никогда не целое. То есть для Вас в RPG в финансовых расчетах целое прозрачно конвертируется в decimal, что и позволяет избежать проблемы целочисленного деления.

То есть для Вас в RPG в финансовых расчетах целое прозрачно конвертируется в decimal

Нет. packed decimal - это нативно поддерживаемый в языке тип данных. Называется packed. 100% соответствует типу decimal в SQL. Вся арифметика с ним реализована не в языке, а в системе, ниже SLIC. Для арифметики используются соотв. MI - ADDN/SUBN/MULT/DIV Что там дальше (ниже) - я не в курсе, ниже SLIC доступ только разработчикам ядра ОС.

На уровне языка мы используем именно packed (для финансовых расчетов). Расчеты "в копейках" - они не для целочисленности, а потому что количество "копеек в рубле" у разных валют разное. У кого-то "копеек" вообще нет. У кого-то их "в рубле" 1000 штук. Поэтому все суммы в packed(15:0) или packed(23:0)

packed decimal - это нативно поддерживаемый в языке тип данных

Я Вам даже больше скажу, он еще на IBM/360 поддерживался аппаратно. Еще с тех были машинные команды арифметических операций с упакованными десятичными числами.

100% соответствует типу decimal в SQL.

А вот тут Вы уже заблуждаетесь. SQL есть разные. Например в MS SQL decimal/numeric могут содержать только 38 десятичных знаков. А в PostgreSQL decimal/numeric имеют точность до 131072 десятичных цифр до десятичной точки и 16383 - после. Тогда как RPG, как раз из-за упомянутых мной аппаратных ограничений, поддерживает лишь 32-байтные упакованные десятичные числа - 63 десятичных знака. Поэтому число π на plpgsql я с точностью в 1000 знаков легко посчитаю, а на РПГ это выльется в весьма непростую задачу.

потому что количество "копеек в рубле" у разных валют разное.

Понятно, что если в мальтийском скудо 12 тари или 240 грано, то, хоть убейся, в десятичное представление можно засунуть только грано или тари, не рискуя получить бесконечную периодическую дробь.

Поэтому все суммы в packed(15:0) или packed(23:0)

И точно в соответствии с выводами статьи используются decimal/numeric, но уж никак не двоичные числа с плавающей или фиксированной запятой.

А вот тут Вы уже заблуждаетесь. SQL есть разные. Например в MS SQL decimal/numeric могут содержать только 38 десятичных знаков. А в PostgreSQL decimal/numeric имеют точность до 131072 десятичных цифр до десятичной точки и 16383 - после.

Тут я неточно выразился. Имел ввиду тот decimal, который используется в DB2. Максимум, если правильно помню, 63 знака и 31 после запятой.

В С тут, кстати, есть тип decimal(n,m), в С++ - _DecimalT<n,m>

А я уж думал попросите π посчитать и на опережение попробовал. За 800 циклов 1000 знаков совпали:

DO $func$
DECLARE
  arctg5 decimal = 0;
  arctg239 decimal = 0;
  x5 decimal = 1/5::decimal;
  x5s decimal = x5*x5;
  x239 decimal = 1/239::decimal;
  x239s decimal = x239*x239;
  xscale decimal = 1;
BEGIN
  FOR i IN 1..800 LOOP
    arctg5 = arctg5 + x5/xscale;
    arctg239 = arctg239 + x239/xscale;
    x5 = x5*x5s;
    x239 = x239*x239s;
    xscale = -sign(xscale) * (abs(xscale) + 2);
  END LOOP;
  RAISE NOTICE '%', (4 * arctg5 - arctg239)*4;
END $func$ LANGUAGE plpgsql;

Ну вообще есть тест на накопление ошибок округления. Называется рекуррентное соотношение Мюллера

В среднем, числа с фиксированной точкой показывают примерно в два раза большую устойчивость к накоплению ошибок по сравнению с числами с плавающей точкой.

Согласен с Вами. У меня явно "коленочный" вариант, просто демонстрирующий возможность расчетов с почти произвольной точностью

Ну и опять же, все это синтетика немного...

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

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

Так что тут скорее важны возможности фиксированного количества знаков после запятой и округления результата на каждом этапе (ради этого, иногда, несколько действий, которые можно записать в одну строку, приходится разбивать на одиночные действия) в соответствии с требованиями и правилами. Правильность результата - не математическая его точность до 100500-го знака, а соответствие требованиям.

Когда на одном сайте вводили пересчёт сумм донатов клиентов в разные валюты, пришли именно к такому варианту - для хранения в базе и операций с ними все суммы умножаются на 100, для показа клиентам, соответственно, делятся на 100. То есть любые операции производятся над целыми числами. При использовании в расчётах нецелых чисел погрешности неизбежны.

А если закостылить для немозгоимения: округляем всегда ндс по каждой позиции в большую сторону,а то что сумма всех ндс будет больше чем ндс от итоговой суммы то и наплевать. Кого волнует, что мы с миллионного оборота на 10000 позиций заплатили в бюджет ндс лишние 100 рублей? зато никакой путаницы.

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

А разве правилами не регламентировано как тот же НДС исчислять - со всего договора, или по каждой позиции отдельно?

Ну и как округлять тоже должно быть где-то прописано.

Изначально, в постановлении № 914 от 02.12.2000 этот вопрос вообще не рассматривался и ГНИ (ФНС тогда еще не было) трактовали его произвольно. Ввод в действие второй части НК РФ с 01.01.2001 никакой ясности в этом вопросе не внес.

На данный момент, п.2 ст.168 НК РФ требует расчета НДС по каждому виду этих товаров (работ, услуг). При этом ст. 154, особенно в рамках частичной оплаты, указывает на необходимость суммарного исчисления базы налога, а п.1 ст. 166 требует умножать на ставку НДС эту базу. Что делать, если сумма полученная в соответствии п.1 ст. 166 не совпадает с суммой полученной по п.2 ст.168 - законодатель не разъясняет.

С точки зрения минфина, ошибки до 1 рубля считаются несущественными для бухгалтерского учета и могут не исправляться при их выявлении. Поэтому ФНС отдает себе отчет, что налогоплательщик через суд вполне может опротестовать решение о недействительности счета-фактуры, если ошибка в ней меньше рубля. Так что проблема округления сейчас действительно актуальна только для счет-фактур из сотен строк.

Вот контрагент-покупатель будет рад! Он ведь отраженный в счёте-фактуре НДС выставит в своей отчетности, как НДС входящий, и на его основе рассчитает свой НДС к уплате. Потом ФНС пересчитает и скажет, что ты ошибся, у тебя переплата, а у твоего контрагента неверно расчитанный НДС, штраф, пени. Ведь твоя счётная ошибка дает тебе право на возмещение излишне уплаченного и, наоборот, не предоставляет прав или освобождения от обязанностей твоего контрагента. С учётом сальдо штраф+пени+доначисленный НДС-твоя переплата по НДС, профицит такой схемы для ФНС не оставит твоему контрагенту шанса избежать веселья с несколькими кругами судов, в лучшем (в финансовом смысле) случае.

Помимо арифметических действий с деньгами, в финансах важны также даты и интервалы времени.

Вот у Oracle функции MONTHS_BETWEEN и ADD_MONTHS имеют полезное свойство: если дата у аргумента -- последний день месяца, то и у результата тоже будет последний день месяца.

-- К последнему дню января прибавляем 1 месяц, получаем последний день февраля,
--   при этом номер дня уменьшился.
ADD_MONTHS(DATE '2024-01-31', 1) = DATE '2024-02-29'
-- К последнему дню февраля прибавляем 3 месяца, получаем последний день мая,
--   при этом номер дня увеличился.
ADD_MONTHS(DATE '2023-02-28', 3) = DATE '2023-05-31'
-- Ко дню в середине февраля прибавляем 3 месяца, получаем то же число в мае.
ADD_MONTHS(DATE '2023-02-27', 3) = DATE '2023-05-27'
-- разница между последним днём февраля и последним днём марта - ровно 1 месяц
MONTHS_BETWEEN(DATE '2023-03-31', DATE '2023-02-28') = 1

Хорошо, если бы Postgresql тоже снабдили бы такими функциями.

Вообще-то уже давно.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории