Я использую PostgreSQL, но я считаю, что большинство топовых БД должны обладать некоторыми похожими возможностями, и, кроме того, решения для них могут вдохновить меня на решение, так что не рассматривайте это для PostgreSQL.
Я знаю, что я не первый, кто пытается решить эту проблему, поэтому думаю, что здесь стоит спросить, но я пытаюсь оценить затраты на моделирование данных бухгалтерского учета таким образом, чтобы каждая транзакция была фундаментально сбалансированной. Данные бухгалтерского учета только для добавления. Общее ограничение (написанное в псевдокоде) здесь может выглядеть примерно так:
CREATE TABLE journal_entry (
id bigserial not null unique, --artificial candidate key
journal_type_id int references journal_type(id),
reference text, -- source document identifier, unique per journal
date_posted date not null,
PRIMARY KEY (journal_type_id, reference)
);
CREATE TABLE journal_line (
entry_id bigint references journal_entry(id),
account_id int not null references account(id),
amount numeric not null,
line_id bigserial not null unique,
CHECK ((sum(amount) over (partition by entry_id) = 0) -- this won't work
);
Очевидно, что такое ограничение проверки никогда не сработает. Он работает для каждой строки и может проверять всю базу данных. Так что он всегда будет терпеть неудачу и будет делать это медленно.
Итак, мой вопрос, каков наилучший способ смоделировать это ограничение? Я в основном посмотрел на две идеи до сих пор. Хотите знать, являются ли они единственными, или если у кого-то есть лучший способ (кроме как оставить его на уровне приложения или хранимого процесса).
- Я мог бы позаимствовать страницу из концепции бухгалтерского мира о разнице между книгой первоначальной записи и книгой окончательной записи (общий журнал и общая бухгалтерская книга). В связи с этим я мог бы смоделировать это как массив строк журнала, прикрепленных к записи журнала, применить ограничение к массиву (в терминах PostgreSQL выберите sum (amount) = 0 из unnest (je.line_items). Триггер может расширяться и сохраните их в таблице отдельных позиций, где проще было бы применить ограничения на отдельные столбцы и где индексы и т. д. могли бы быть более полезными.
- Я мог бы попытаться закодировать триггер ограничения, который бы применял это для каждой транзакции с идеей, что сумма серии 0 всегда будет равна 0.
Я сравниваю их с текущим подходом применения логики в хранимой процедуре. Стоимость сложности сопоставляется с идеей, что математическое доказательство ограничений превосходит модульные тесты. Основным недостатком # 1 выше является то, что типы как кортежи являются одной из тех областей в PostgreSQL, где каждый сталкивается с противоречивым поведением и регулярно изменяет предположения, и поэтому я даже надеюсь, что поведение в этой области со временем может измениться. Создание будущей безопасной версии не так просто.
Существуют ли другие способы решения этой проблемы, которые увеличат до миллионов записей в каждой таблице? Я что-то пропустил? Есть ли компромисс, который я пропустил?
В ответ на замечание Крейга о версиях, как минимум, это должно работать на PostgreSQL 9.2 и выше (возможно, 9.1 и выше, но, вероятно, мы можем перейти с прямой 9.2).