データベーススペシャリスト 2015年 午前2 問02
問題文
図のデータモデルは会計取引の仕訳を表現している。“移動”がリンクする“勘定”の残高を増やす場合は金額の符号を正に、減らす場合は負にすることで、貸借平均の原理を表現する。このモデルに基づき、“勘定”表、“会計取引”表、“移動”表を定義した。勘定科目“現金”の2015年4月30日における残高を導出するためのSQL文はどれか。ここで、モデルの表記にはUMLを用い、表中の実線の下線は主キーを表す。
また、“会計取引”表には今期分のデータだけが保持される。

選択肢
ア:
SELECT SUM(金額) AS 残高 FROM 勘定, 移動, 会計取引
WHERE 勘定.勘定科目 = 移動.勘定科目 AND
会計取引.取引番号 = 移動.取引番号 AND
勘定.勘定科目 = '現金' AND
取引日 <= '2015-04-30'
イ:
SELECT 期首残高 + SUM(金額) AS 残高 FROM 勘定, 移動, 会計取引
WHERE 勘定.勘定科目 = 移動.勘定科目 AND
会計取引.取引番号 = 移動.取引番号 AND
勘定.勘定科目 = '現金' AND
取引日 <= '2015-04-30'
GROUP BY 勘定.勘定科目, 期首残高
(正解)ウ:
SELECT 残高 FROM 勘定, 移動, 会計取引
WHERE 勘定.勘定科目 = '現金' AND
取引日 <= '2015-04-30'
エ:
SELECT 残高 FROM 勘定, 移動, 会計取引
WHERE 勘定.勘定科目 = 移動.勘定科目 AND
勘定.勘定科目 = '現金' AND
取引日 <= '2015-04-30'
🔒 解説は解答すると表示されます
勘定残高の導出【午前2解説】
正解の理由
選択肢イは、勘定表に格納された期首残高に、指定日までの当期中の移動(取引の金額)の合計を加えるという残高の定義を正しくSQLで表現しています。スキーマでは勘定の属性が (勘定科目, 期首残高) と定義されており、「残高」という列は存在しません。したがって求める残高は
を算出する必要があり、これを実現しているのがイのSQLです。さらに、集約関数 SUM を使っているため、非集約の列である期首残高を SELECT に含めるには GROUP BY が必要であり、イは GROUP BY を正しく指定しています。取引日での絞り込み(取引日 <= '2015-04-30')およびテーブルの結合条件も適切です。
解法ステップ
- 何を求めるかを確認:2015-04-30 時点の「現金」の残高=期首残高 + 当期の該当期間までの移動金額合計。
- 使用する表とキーを確認:
- 勘定(勘定科目, 期首残高)
- 移動(勘定科目, 取引番号, 金額)
- 会計取引(取引番号, 取引日)
結合キーは 勘定.勘定科目 = 移動.勘定科目、移動.取引番号 = 会計取引.取引番号。
- 日付条件を WHERE に入れて「2015-04-30 までの移動」を制限する(取引日 <= '2015-04-30')。
- 移動の金額を SUM() で合計し、期首残高と加算する。集計を行うため非集約列は GROUP BY に含める。
- もし当該勘定に移動がない場合を考えるなら NULL を 0 に変換(COALESCE 等)する。
選択肢別の誤答解説
-
ア
問題点:SELECT で SUM(金額) のみを返しており、勘定表の期首残高を考慮していません。したがって求める残高(期首残高 + 当期増減)にならない点が誤りです。なお、集約だけを返すため GROUP BY は必須ではありませんが、それでも期首残高を加えていないため不正解です。 -
ウ
問題点:SELECT 残高 としているが、図のリレーションスキーマでは勘定の属性は (勘定科目, 期首残高) であり「残高」列は存在しません(スキーマ不整合により参照不能)。さらに移動や会計取引との結合条件(移動.取引番号 = 会計取引.取引番号 等)が欠けており、正しい集合操作・集計を行えていません。以上によりこのSQLは無効または誤った結果を返します。 -
エ
問題点:ウと同様に SELECT 残高 で存在しない列を参照しています。加えて、会計取引と移動テーブルの間の結合条件(会計取引.取引番号 = 移動.取引番号)が欠落しているため、取引日のフィルタが正しい移動行に適用されず、重複や誤った集計になり得ます。したがって誤りです。
(重要)スキーマにない列を参照する問題点は致命的です:図の定義に従うと「残高」列は存在せず、残高は計算して導出するものです。
よくある誤解
- 「勘定表に '残高' 列がある」と考えるミス:図のスキーマが (勘定科目, 期首残高) なら、現在残高は計算結果であり列参照では得られません。
- 集約関数と非集約列の混在:SUM(金額) と 期首残高 を同時に SELECT する場合、期首残高を GROUP BY に入れ忘れると文法エラーまたは誤結果になることがある(RDBMS による許容差異に依存)。
- 会計取引と移動の結合忘れ:移動の取引番号と会計取引を結ばないと、取引日の条件が正しく移動に適用されず誤集計になる。
補足コラム
明示的な JOIN と NULL 対策を含めた実用的な SQL 例(推奨スタイル):
SELECT g.勘定科目,
g.期首残高 + COALESCE(SUM(m.金額), 0) AS 残高
FROM 勘定 AS g
LEFT JOIN 移動 AS m
ON g.勘定科目 = m.勘定科目
LEFT JOIN 会計取引 AS t
ON m.取引番号 = t.取引番号 AND t.取引日 <= '2015-04-30'
WHERE g.勘定科目 = '現金'
GROUP BY g.勘定科目, g.期首残高;
ポイント:
- LEFT JOIN を使うことで移動がない勘定でも期首残高を返せる(SUM が NULL になる場合を COALESCE で 0 に)。
- 会計取引の取引日条件を JOIN の ON に入れると、LEFT JOIN の「存在しない移動を残す」性質を保ちながら日付制約を適用できます。
- 集計の代わりにサブクエリを使えば GROUP BY を回避できます(単一勘定を取り出す場合は有用)。
FAQ
Q. なぜ GROUP BY に期首残高を入れる必要がある?
A. SELECT に集約結果(SUM)と非集約列(期首残高)を同時に出す場合、非集約列ごとに結果をまとめる必要があるためです。代替として期首残高をサブクエリで参照すれば GROUP BY を回避できます。
A. SELECT に集約結果(SUM)と非集約列(期首残高)を同時に出す場合、非集約列ごとに結果をまとめる必要があるためです。代替として期首残高をサブクエリで参照すれば GROUP BY を回避できます。
Q. 当該勘定に移動が一切ない場合は?
A. SUM は NULL を返す場合があるので COALESCE(SUM(...),0) のようにして 0 に置き換えるのが一般的です。
A. SUM は NULL を返す場合があるので COALESCE(SUM(...),0) のようにして 0 に置き換えるのが一般的です。
Q. 日付条件はどの表にかけるべきか?
A. 取引日の条件は会計取引表の取引日カラムに適用します。JOIN の ON に入れるか WHERE に入れるかで LEFT JOIN の動作が変わるため注意が必要です(LEFT JOIN のまま WHERE に書くと NULL の行が除外される)。
A. 取引日の条件は会計取引表の取引日カラムに適用します。JOIN の ON に入れるか WHERE に入れるかで LEFT JOIN の動作が変わるため注意が必要です(LEFT JOIN のまま WHERE に書くと NULL の行が除外される)。
関連キーワード: SQL、JOIN、集約関数、GROUP BY、COALESCE、リレーショナルスキーマ、勘定科目、仕訳、トランザクションデータ、日付フィルタリング

\ せっかくなら /
データベーススペシャリストを
クイズ形式で学習しませんか?
クイズ画面へ遷移する→
すぐに利用可能!

