Postgresql

交易、參考以及如何執行複式記賬?(PG)

  • June 4, 2013

複式記賬是

在財務會計系統中記錄財務資訊的一套規則,其中每筆交易或事件都會改變至少兩個不同的名義分類賬。

一個帳戶可以“借記”或“貸記”,所有貸記的總和必須等於所有借記的總和。

您將如何在 Postgres 數據庫中實現這一點?指定以下 DDL:

CREATE TABLE accounts(
   account_id serial NOT NULL PRIMARY KEY,
   account_name varchar(64) NOT NULL
);


CREATE TABLE transactions(
   transaction_id serial NOT NULL PRIMARY KEY,
   transaction_date date NOT NULL
);


CREATE TABLE transactions_details(
   id serial8 NOT NULL PRIMARY KEY,
   transaction_id integer NOT NULL 
       REFERENCES transactions (transaction_id)
       ON UPDATE CASCADE
       ON DELETE CASCADE
       DEFERRABLE INITIALLY DEFERRED,
   account_id integer NOT NULL
       REFERENCES accounts (account_id)
       ON UPDATE CASCADE
       ON DELETE RESTRICT
       NOT DEFERRABLE INITIALLY IMMEDIATE,
   amount decimal(19,6) NOT NULL,
   flag varchar(1) NOT NULL CHECK (flag IN ('C','D'))
);

注意:transaction_details 表沒有指定明確的借記/貸記賬戶,因為系統應該能夠在單筆交易中藉記/貸記多個賬戶。

此 DDL 創建以下要求:在 transactions_details 表上送出數據庫事務後,它必須為每個 借記和貸記相同的金額transaction_id,例如

INSERT INTO accounts VALUES (100, 'Accounts receivable');
INSERT INTO accounts VALUES (200, 'Revenue');

INSERT INTO transactions VALUES (1, CURRENT_DATE);

-- The following must succeed
BEGIN;
   INSERT INTO transactions_details VALUES (DEFAULT, 1, 100, '1000'::decimal, 'D');
   INSERT INTO transactions_details VALUES (DEFAULT, 1, 200, '1000'::decimal, 'C');
COMMIT;


-- But this must raise some error
BEGIN;
   INSERT INTO transactions_details VALUES (DEFAULT, 1, 100, '1000'::decimal, 'D');
   INSERT INTO transactions_details VALUES (DEFAULT, 1, 200, '500'::decimal, 'C');
COMMIT;

是否可以在 PostgreSQL 數據庫中實現這一點?無需指定額外的表來儲存觸發器狀態。

首先,這正是我在詢問對子集聚合建模約束時想到的問題?這當然是開始的地方。這個問題比這個更籠統,所以我在這裡的回答將有更多關於實際方法的資訊。

您可能不想在 PostgreSQL 中以聲明方式執行此操作。唯一可能的聲明式解決方案要麼破壞 1NF,要麼非常複雜,因此這意味著必須強制執行。

LedgerSMB 中,我們希望分兩個階段執行此強制執行(兩個階段都很嚴格)。

  1. 所有日記帳分錄都將通過儲存過程輸入。這些儲存過程將接受行項目列表作為數組並檢查總和是否等於 0。我們在數據庫中的模型是我們有一個單金額列,其中負數是藉方,正數是貸方(如果我是從頭開始,我會將正數作為藉方,將負數作為貸方,因為這更自然一些,但這裡的原因是模糊的)。借方和貸方在儲存中合併,並在表示層檢索時分離。這使得執行總計更容易。
  2. 我們將使用延遲約束觸發器,它將根據表上的系統欄位檢查送出。這意味著在給定交易中輸入的行必須平衡,但我們可以在行本身之外做到這一點。

引用自:https://dba.stackexchange.com/questions/39480