私は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
);
明らかに、このようなチェック制約は機能しません。行ごとに動作し、データベース全体をチェックする場合があります。そのため、常に失敗し、実行が遅くなります。
私の質問は、この制約をモデル化する最良の方法は何ですか?私はこれまで基本的に2つのアイデアを見てきました。これらが唯一のものであるのか、誰かがより良い方法を持っているのか疑問に思う(アプリレベルまたはストアドプロシージャに任せる以外)。
- 元のエントリの本と最終エントリの本(一般仕訳帳と総勘定元帳)の違いの会計世界の概念からページを借りることができます。この点で、これをジャーナルエントリに添付されたジャーナル行の配列としてモデル化し、配列に制約を適用することができます(PostgreSQLの用語では、unnest(je.line_items)からsum(amount)= 0を選択します。これらを個々の列の制約をより簡単に実施でき、インデックスなどがより便利になる可能性のある明細テーブルに保存します。これが私が傾いている方向です。
- 一連の0の合計が常に0になるという考えで、トランザクションごとにこれを強制する制約トリガーをコーディングすることができます。
ストアドプロシージャでロジックを実行する現在のアプローチに対して、これらを比較検討しています。複雑さのコストは、制約の数学的証明が単体テストよりも優れているという考えと比較検討されています。上記#1の主な欠点は、タプルとしての型がPostgreSQLで一貫性のない動作や仮定の定期的な変更に遭遇する領域の1つであるため、この領域の動作が時間とともに変化することを期待することです。将来の安全なバージョンの設計はそれほど簡単ではありません。
この問題を解決するために、各テーブルで数百万件のレコードにスケールアップする他の方法はありますか?何か不足していますか?見逃したトレードオフはありますか?
バージョンに関する以下のCraigのポイントに応じて、最低限、これはPostgreSQL 9.2以降(おそらく9.1以降ですが、おそらくストレート9.2で実行できます)で実行する必要があります。