複式簿記のテーブル設計:仕訳ヘッダ・明細、勘定科目マスタ、貸借一致
確認日 2026-10-31(調べ方)・制度は変わることがあります。個別の判断は公式の資料と専門家に確かめてください。
複式簿記のデータは、仕訳ヘッダ、仕訳明細、勘定科目マスタの3つのテーブルが基本です。1つの取引を1つのヘッダで表し、借方と貸方の各行を明細で持ちます。明細の借方合計と貸方合計は、伝票ごとに必ず一致させます。
このページでは、その土台の設計を説明します。法令が帳簿に求める項目と、編集部の設計の例は分けて書きます。テーブル名と列名は説明用で、特定の製品の構造を示すものではありません。
法令が帳簿に求めていること
法人税法施行規則は、青色申告法人について次のように定めています。
- 取引を複式簿記の原則に従い、整然と明瞭に記録する(第53条)
- 仕訳帳と総勘定元帳などを備える(第54条)
- 仕訳帳には、発生順に取引の年月日、内容、勘定科目、金額を書く(第55条第1項)
- 総勘定元帳には、勘定ごとに記載の年月日、相手方勘定科目、金額を書く(第55条第2項)
別表二十四は、売掛金や売上などの項目ごとの記載事項を定めています。たとえば売掛金は、相手方別に年月日、品名、数量、単価、金額などです。これらはテーブルの形を決めたものではありません。どの項目を持てるかの確認項目として読みます。
上の仕訳帳と総勘定元帳は、システムではテーブルごとに別々に持つ必要はありません。多くの設計では、仕訳明細を発生順に出せば仕訳帳、科目別に出せば総勘定元帳になります。
仕訳ヘッダと仕訳明細
なぜ分けるかは、1つの例で分かります。消費税つきの売上は、借方1行、貸方2行です。
1つの取引が3行になる
| 借方 | 金額 | 貸方 | 金額 |
|---|---|---|---|
| 売掛金 | 110,000 | 売上 | 100,000 |
| 仮受消費税 | 10,000 |
journal_lines| id | journal_id | line_no | side | account_code | amount |
|---|---|---|---|---|---|
| L-1 | J-1 | 1 | D | 1130 | 110,000 |
| L-2 | J-1 | 2 | C | 4100 | 100,000 |
| L-3 | J-1 | 3 | C | 2150 | 10,000 |
全体の形は次のとおりです。
複式簿記の基本のテーブル
journal_headers
- id PK
- ledger_id FK
- journal_no
- entry_date
- description
- source_type
- source_id
- reversal_of FK
- created_by
- created_at
journal_lines
- id PK
- journal_id FK
- line_no
- side
- account_code FK
- sub_account_code
- department_code
- partner_id
- tax_code
- amount
accounts
- code PK
- name
- category
- normal_side
- requires_sub
- valid_from
- valid_to
- journal_headers 1 — N journal_lines
- accounts 1 — N journal_lines
列を置く場所の考え方は次のとおりです。
| 場所 | 列 | 持つ理由 |
|---|---|---|
| ヘッダ | entry_date | 計上日。帳簿の年月日 |
| ヘッダ | created_at | 入力日時。計上日とは別に自動で付ける |
| ヘッダ | description | 取引の内容 |
| ヘッダ | source_type・source_id | 元の業務データまでたどる |
| ヘッダ | reversal_of | 訂正の相手を特定する |
| 明細 | account_code・sub_account_code | 勘定科目と補助科目 |
| 明細 | department_code・partner_id | 部門別の損益、取引先別の残高 |
| 明細 | tax_code | 消費税の区分。科目だけでは決まらない |
| 明細 | amount | 金額。整数か固定小数点で持つ |
計上日と入力日を分けるのは、月次の締めのためです。reversal_of は赤伝のためです。どの業務イベントで仕訳を作るかは仕訳連携で扱います。
金額の持ち方は3通りあります。
| 形 | 例 | 長所 | 短所 |
|---|---|---|---|
| side+正の金額 | side=‘D’, amount=110000 | 帳簿の見た目に近い | 残高の計算で符号の変換が要る |
| 借方列・貸方列 | debit=110000, credit=0 | 帳票に出しやすい | 両方に値が入らない制約が要る |
| 符号つきの1列 | amount=110000 または -110000 | 集計が SUM だけで済む | 借方を正にする決まりの周知が要る。マイナス伝票と区別しにくい |
このサイトの例では side と正の金額で書きます。マイナス伝票を許すなら、amount の正の制約は外します。
勘定科目マスタ
勘定科目マスタは、集計の軸です。分類(category)で貸借対照表と損益計算書に分かれ、残高の側(normal_side)で残高の増える向きが決まります。
accounts| code | name | category | normal_side | requires_sub |
|---|---|---|---|---|
| 1110 | 普通預金 | asset | D | 銀行口座 |
| 1130 | 売掛金 | asset | D | 取引先 |
| 2150 | 仮受消費税 | liability | C | NULL |
| 3100 | 資本金 | equity | C | NULL |
| 4100 | 売上 | revenue | C | NULL |
| 5100 | 売上原価 | expense | D | NULL |
設計で押さえる点です。
- コードは体系を決める。桁で分類を表す形が一般的です。ただし、コードの体系はあとから変えにくいので、経理と最初に決めます
- 補助科目を分ける。売掛金の取引先別、預金の口座別のように、科目の下の内訳です。必須かどうかを
requires_subで検査します - 科目を物理削除しない。過去の仕訳が参照しています。
valid_toで使えなくします - 名称の変更は履歴を持つ。国税庁の一問一答の問18は、単価などのマスターデータは期中に改定されるので、取引記録に関連するものを全部保存する必要があるとしています。課税期間の終わりの時点だけでは足りません
- 税区分は別のマスタにする。同じ科目でも税率や課税区分が分かれるためです。消費税の端数処理も見てください
貸借一致のチェック
伝票の借方と貸方の合計が一致することは、このテーブルの不変条件です。1行ずつの INSERT の途中では一致していないので、CHECK 制約では書けません。トランザクションの終わりに検査します。PostgreSQL の例です。
CREATE FUNCTION assert_journal_balanced() RETURNS trigger AS $$
DECLARE diff numeric;
BEGIN
SELECT SUM(CASE side WHEN 'D' THEN amount ELSE -amount END)
INTO diff
FROM journal_lines
WHERE journal_id = NEW.journal_id;
IF diff <> 0 THEN
RAISE EXCEPTION '伝票 % の貸借が一致しません(差額 %)', NEW.journal_id, diff;
END IF;
RETURN NULL;
END $$ LANGUAGE plpgsql;
CREATE CONSTRAINT TRIGGER trg_journal_balanced
AFTER INSERT ON journal_lines
DEFERRABLE INITIALLY DEFERRED
FOR EACH ROW EXECUTE FUNCTION assert_journal_balanced();
この検査は、確定の段階でも通します。
| 段階 | 検査 | 失敗したとき |
|---|---|---|
| 入力画面 | 借方と貸方の合計を表示し、差があれば登録を止める | 利用者が直す |
| 連携の取り込み | 伝票ごとに合計を比べる | 保留、または拒否 |
| DB | トランザクションの終わりにトリガーで検査 | ロールバック |
| 月次の締め | 全伝票と試算表の合計を確認 | 締めを止めて調査 |
複数通貨を扱うなら、外貨の金額と円換算の金額の両方を持ち、貸借の一致は記帳通貨で見ます。円換算の端数で差が出たときの調整の扱いは、経理と決めます。
試算表は、明細の集計で作れます。
SELECT a.code, a.name,
SUM(CASE l.side WHEN 'D' THEN l.amount ELSE 0 END) AS debit_total,
SUM(CASE l.side WHEN 'C' THEN l.amount ELSE 0 END) AS credit_total
FROM journal_lines l
JOIN journal_headers h ON h.id = l.journal_id
JOIN accounts a ON a.code = l.account_code
WHERE h.entry_date BETWEEN '2026-10-01' AND '2026-10-31'
GROUP BY a.code, a.name
ORDER BY a.code;
この例は当月の発生額です。残高まで出すなら、前月までの繰越を足します。
件数が増えて集計が遅くなったら、月次の残高テーブル(期間、科目、補助、部門ごとの増減)を持ちます。残高テーブルは計算の結果にすぎないので、明細の集計と一致することを定期的に検査します。
訂正と履歴
確定した仕訳は、行を書き換えず、取り消しの仕訳を足して直す設計がよく使われます。理由と法令の範囲は赤伝の記事で説明しています。
電子帳簿保存法の優良な電子帳簿では、訂正削除の事実と内容を確認できること、通常の期間を過ぎた入力を確認できることなどが要件です(電帳規則第5条)。ヘッダの reversal_of と created_at は、この要件の検討にも関わる列です。自社がどの要件を目指すかは、経理に確認します。
帳簿は保存の期間も長くなります。法人税法施行規則第59条は起算日から7年の保存を定めています。パーティションで古い期間を分けるなど、データが増え続ける前提で設計します。
判断の練習
会計システムの設計と連携の図解記事
よくある質問
- 仕訳テーブルはなぜヘッダと明細に分けるのですか?
- 1つの取引が3行以上になることがあるからです。伝票全体の情報をヘッダに、借方と貸方の各行を明細に置きます。貸借の一致も伝票単位で確かめます。
- 借方と貸方は別の列にすべきですか?
- どれでも作れます。side と正の金額で持つ形、借方列と貸方列の形、符号つきの1列の形があります。集計のしやすさと、マイナス伝票を許すかで決めます。
- 貸借一致のチェックはアプリと DB のどちらで行いますか?
- 両方が安全です。入力時にアプリで検査し、DB ではトランザクションの終わりに伝票単位で検査する形が考えられます。
- 残高は毎回集計しますか?
- 件数が少ないうちは集計で足ります。多くなったら月次の残高テーブルを持ちます。その場合も明細の集計と一致するかを定期的に検査します。
出典