ホーム > データベーススペシャリスト試験 > 2009年
データベーススペシャリスト試験 2009年 午後1 問03
変更履歴を記録するテーブルに関する次の記述を読んで、設問1〜3に答えよ。
H銀行では,預金者へのサービス向上を図るために,顧客情報管理に使用している“顧客”テーブルの設計を見直すことになった。 そのため, システム部の G 部長の下にプロジェクトチームが組まれ, F さんが設計を担当することになった。
〔顧客情報管理の概要〕
顧客情報管理の主な業務内容は,次のとおりである。
(1) 営業店担当者は、顧客からの依頼によって電話番号などの顧客属性情報を変更する。変更した顧客属性情報は,依頼当日から適用される。 同一日に変更を取り消すことはない。
(2) 顧客ごとに設定した優遇レベルによって, ATM(現金自動預け払い機)の時間外利用手数料を割り引くなどのサービスを提供している。
(3) 優遇レベルは,新規登録時の預金額によって決定され, その後は預金残高などの利用状況に基づいて毎月末に決定される。 優遇レベルが変更となる場合は,月末日の夜間バッチ処理によって新たな優遇レベルが設定され, 翌月の1日から適用される。
〔顧客情報管理に使用される主なテーブルの構造〕
顧客情報管理に使用される主なテーブルの構造を図1に示す。 各テーブルの主な列の意味及び制約は, 表1に示すとおりである。


〔“顧客” テーブルの変更〕
1.“顧客” テーブルの構造の変更
Fさんは、顧客属性情報 (顧客名、支店番号、郵便番号、住所,電話番号,優遇レベル)の変更を履歴として記録するために, “顧客” テーブルの構造を図2のように変更した。 追加した列の意味及び制約は,表2に示すとおりである。


変更後の“顧客” テーブルには,顧客属性情報の変更履歴が表3のように記録される。
(1) 顧客コードA111111
① 2008年6月16日に新規の顧客コード A111111 が追加された。
② その日以降、顧客属性情報は変更されていない。
(2) 顧客コード B222222
① 2007年3月1日に電話番号が変更された。 変更連番が一つ前の行の適用終了日は,NULL から2007年2月28日に設定された。
② 2007年11月15日に当該顧客との取引がなくなり, 顧客コードが削除された。適用終了日に NULLの行がないことが, 削除されたことを示している。
(3) 顧客コード C333333
① 2009年1月15日に電話番号が変更された。
② 2009年2月1日に優遇レベルが変更された。

2.変更後の“顧客” テーブルへの照会
(1) ある顧客の現在日付の顧客属性情報を1行読み込むために,図 3 のようなSQL文を設計した。ここで,現在日付を表す予約語を CURRENT_DATE とする。

(2) ある顧客の属性情報について, 優遇レベルが変更された日を調べる(例えば,表4のような結果行を求める) ために,図4のようなSQL文を設計した。



〔“取引履歴”テーブルの集計処理〕
Fさんは,“顧客” テーブルの構造を変更したことによって,これまで“取引履歴”テーブルと結合して顧客単位に集計処理を行っていた SQL文を見直した。
例えば、2009年4月の支店・顧客別月間預入額を集計する SQL 文を図5に示すように設計した。そして、テスト用の“取引履歴”, “口座”, “顧客”の各テーブルにテストデータをロードし, SQL文の実行結果を検証した。 ここで,ISODATE ( )は,日付を表す文字列を DATE型に変換するユーザ定義関数とする。

〔変更後の“顧客” テーブルに関する指摘事項〕
G 部長は,F さんに対し、変更後の“顧客” テーブルに関して,次のように指摘した。
① 同一顧客の適用期間は、連続していなければならない。 すなわち、変更連番が 1以外の場合の適用開始日は、変更連番が一つ前の行の適用終了日と連続していなければならない(日にちが抜けたり,重なったりしてはならない)。 その制約条件を追加し,制約が守られているかどうかを検証する SQL文を設計すべきである。
② 優遇レベルを先日付で変更する処理について, 更に検討する必要がある。
③ 顧客属性情報の変更受付日を漏れなく記録したい” という顧客情報管理部門からの要望にこたえていない。
④ 図5の支店・顧客別月間預入額を集計する SQL文には,誤りがある。
設問1(1):変更後の“顧客” テーブルを照会する SQL文について(1)(2)に答えよ。
図3のSQL文中の(a), (b)に入れる適切な字句を答えよ。(a, bは順不同)
模範解答
a:・適用終了日=CURRENT_DATE
・適用終了日>=CURRENT_DATE
b:適用終了日 IS NULL
解説
1. 問題の整理とゴール
図3の SQL 文では「ある顧客の“現在日付に有効な”顧客属性情報を 1 行だけ取得」したい。
WHERE 句の骨格は下記の通りで、
WHERE 句の骨格は下記の通りで、
a
と b
に入る条件を決めるのが設問である。SELECT *
FROM 顧客
WHERE 顧客コード = :顧客コード -- ① 顧客を特定
AND 適用開始日 <= CURRENT_DATE -- ② 開始日は今日以前
AND ( a OR b ) -- ③ 終了日の扱い
③の部分で「今日が有効期間内であること」を判定したい。
2. 模範解答のキーワード・論点整理
3. なぜその解答になるのか
3.1 有効期間の定義
問題文より
“適用終了日が未定の場合は NULL が設定される。”
つまり有効期間は
適用開始日 ≦ 対象日 ≦ 適用終了日(ただし終了日が NULL なら上限なし)
3.2 WHERE 句の各条件
適用開始日 <= CURRENT_DATE
… 既に開始している行だけに絞る。(②)- 終了日の判定(③)
- 終了日がまだ来ていない、または今日そのもの →
適用終了日 >= CURRENT_DATE
- 終了日が未定(NULL) →
適用終了日 IS NULL
- 終了日がまだ来ていない、または今日そのもの →
どちらかが成り立てば今日も有効なので OR でつなぐ。
この「今日以前に開始し、今日以降まで有効」の行は一意に 1 行だけである設計だから、目的を達成できる。
この「今日以前に開始し、今日以降まで有効」の行は一意に 1 行だけである設計だから、目的を達成できる。
3.3 適用終了日 = CURRENT_DATE
でもよい理由
>= CURRENT_DATE
でも動くが、終了日が“今日そのもの”しか対象にしない = CURRENT_DATE
でも、「有効行を1行取得できる」ケースが多く、試験の出題意図としてどちらも正しいとみなしている。
4. 受験者が誤りやすいポイント
5. 試験対策まとめ
- 期間テーブル(開始日・終了日型)の基本形
開始日 <= 対象日 AND ( 終了日 IS NULL OR 終了日 >= 対象日 )
- NULL 判定は
IS NULL / IS NOT NULL
。= NULL
は誤り。 - OR で NULL と比較条件を組み合わせるのが定石。
- 等号と不等号の向きより「どの行が取れるか」を必ず日付例で確認する。
- 先日付(未来開始)のレコードは「開始日 > 今日」なので自然に除外されることを意識する。
このパターンは多くの過去問や実務でも頻出なので、丸暗記ではなく「期間ロジック」として定着させておきましょう。
設問1(2):変更後の“顧客” テーブルを照会する SQL文について(1)(2)に答えよ。
図4のSQL文中の(c), (d)に入れる適切な字句を答えよ。
模範解答
c:X.変更連番 + 1
d:X.優遇レベル
解説
小問の論点整理
図4のSQL文は,“顧客”テーブルを自己結合し,前回の優遇レベルと次回のレコードを比較して「優遇レベルが変更された日」を抽出する構造になっています。
ここで押さえるべきキーワード・論点は次のとおりです。
ここで押さえるべきキーワード・論点は次のとおりです。
- 変更連番
「変更連番は … 1から始まり1ずつ増加する整数が付与される。連番に抜けはない。」(表2より)
→ 前回レコードの次の連番(X.変更連番+1)と結合する。 - 優遇レベルの変化
変更連番が連続しているだけではなく,「優遇レベルが変更となる場合」だけを抽出する必要がある。 - 自己結合(エイリアスX,Y)
同一顧客について,Xが前回の履歴,Yが次回の履歴を表す。 - 適用開始日
Yの「適用開始日」が,優遇レベル変更後の実際の適用開始日となる。
解答の導出手順と根拠
図4では,次のようなWHERE句のうち,c,dに入る式を問うています(一部再掲)。
WHERE X.顧客コード = :顧客コード
AND X.顧客コード = Y.顧客コード
AND c = Y.変更連番
AND d <> Y.優遇レベル
- 「変更連番は … 1から始まり1ずつ増加する整数が付与される。連番に抜けはない。」
→ Yのレコードは,Xの次回履歴を指すので,
c= X.変更連番 + 1 - 「優遇レベルが変更となる場合は … 新たな優遇レベルが設定され,翌月の1日から適用される。」
→ Yレコードの優遇レベルと,Xレコードの優遇レベルが異なることを条件にするので,
d= X.優遇レベル
これにより,Xの次の連番でかつ優遇レベルが変わったYレコードの「Y.適用開始日」が,まさにレベル変更日となります。
正解
SQL WHERE句は以下のようになります。
...
AND X.変更連番 + 1 = Y.変更連番
AND X.優遇レベル <> Y.優遇レベル
...
受験者が誤りやすいポイント
- 「+1」を忘れて,単に
X.変更連番 = Y.変更連番
としてしまう <>
と=
を取り違えて「変更のない行」を抽出してしまう- エイリアスX,Yが逆になり,結合条件を逆転させる
試験対策として覚えておくべき知識
- 変更履歴を持つテーブルでは,自己結合を使って「前回レコード」と「次回レコード」を比較する
- 連番項目(シーケンス)に+1を適用することで隣接行を結びつける手法
- 変更検出には前回値と次回値の不一致(<>)を条件に用いる
これらの基本パターンは,実務でも「更新履歴から変更箇所を抽出する」際に頻出しますので,確実に理解しておきましょう。
設問2(1):〔変更後の“顧客” テーブルに関する指摘事項〕 ①〜③について,(1)〜(4)に答えよ。
指摘事項 ①に対応するために、適用終了日が NULL でも削除日付でもない行のうち, 適用期間が連続していない行を読み込むための SQL 文を設計したい。 次の SQL 文中の(e),(f)に入れる適切な字句を答えよ。
ここで,NEXT_DAY()は, 引数とした日付の翌日付を求めるユーザ定義関数とする。なお、(c)には設問1の(2)と同じ答えが入る。


模範解答
e:X.顧客コード
f:Y.適用開始日
解説
解答のキーワードと論点整理
- G部長の指摘①:
「変更連番が1以外の場合の適用開始日は、変更連番が一つ前の行の適用終了日と連続していなければならない」 - 連続性のチェック方法:
- 同一顧客の隣接する履歴レコードを探す(同じ顧客コードかつ変更連番が前後)
- 前の行の終了日の翌日(NEXT_DAY)と次の行の開始日が等しくないレコードを抽出
- SQL中の(e),(f):
- (e):同一顧客を結合する条件
- (f):連続性比較の右辺となる開始日
解答
――すなわち、該当部分を含む WHERE 句は次のようになります。
AND X.適用終了日 IS NOT NULL
AND EXISTS (
SELECT * FROM 顧客 Y
WHERE
X.変更連番 - 1 = Y.変更連番 -- (c)
AND X.顧客コード = Y.顧客コード -- (e)
AND NEXT_DAY(X.適用終了日) <> Y.適用開始日 -- (f)
)
なぜこの解答になるか
-
G部長の指摘①にある制約
「変更連番が1以外の場合の適用開始日は、変更連番が一つ前の行の適用終了日と連続していなければならない」
→ 連続しない(抜けや重なりがある)行を検出するには 前行の終了日の翌日 と 現在行の開始日 が等しいかをチェックします。 -
前行との結合条件
- 「同一顧客」のレコード同士を比較するために、XとYの 顧客コード を結合
- これが(e)=
X.顧客コード
-
日付連続性の比較
NEXT_DAY(X.適用終了日)
で前行の終了日の翌日を求め、これと現在行の開始日を比較- これが(f)=
Y.適用開始日
よくある誤りと注意点
- 「(e)に
Y.顧客コード
を入れる」
→ 自己結合で凡その習いとしてはX.顧客コード = Y.顧客コード
の形にするため、X.顧客コード
が左辺に来るべきです。 - 日付比較を
<
や>
だけで済ませる
→ 連続していない日を検出するには 翌日が一致しない (<>
) 条件が必要です。 NEXT_DAY
の引数や比較対象を取り違える
→ 引数には「前行の終了日(X)」を、比較先には「後行の開始日(Y)」を指定する点を押さえてください。
試験対策として覚えておくべきポイント
- 自己結合による履歴の前後比較
履歴テーブルで日付の前後関係や連続性を検証するときは、自己結合(同一テーブルを別名で結ぶ)を用いる。 - 日付の連続性チェック
前レコードの終了日+1日と次レコードの開始日が等しいかを比較することで、抜け・重複を検出できる。 - NULLチェック
適用終了日がNULL
(現在有効)や「削除日付」である行を対象外・対象内に分ける条件を明確に記述する。 - エイリアスの使い分け
自己結合時はテーブル名ではなくエイリアス(X, Y)で列を指定し、どちらの行を比較しているか明示する。
設問2(2):〔変更後の“顧客” テーブルに関する指摘事項〕 ①〜③について,(1)〜(4)に答えよ。
指摘事項②を確認するために、顧客コード C333333 の電話番号が 2009年5月25日に変更された場合を想定して, “顧客” テーブルに次の表のように変更連番 5 の行を追加した。 しかし、指摘事項 ① に対応していないので、図3のSQL文では,例えば, CURRENT_DATE が 2009年5月25日であるとき, 想定した結果を得られない。 どのような結果になるのか, 15字以内で述べよ。


模範解答
・結果行が複数行になる。
・SQL 文の実行が失敗する。
解説
論点整理
- 図3のSQL文は、以下のWHERE句で「現在日付に適用中」の行を抽出している。
WHERE 顧客コード = :顧客コード AND 適用開始日 <= CURRENT_DATE AND ( 適用終了日 IS NULL OR CURRENT_DATE <= 適用終了日 )
- 指摘事項①「同一顧客の適用期間は連続していなければならない」を守らず,変更連番3と変更連番5で期間が重複している。
- その結果,CURRENT_DATE が 2009-05-25 のときに両方の行が抽出条件を満たし,期待する「1行」ではなく「複数行」が返される(多くの環境でSQLエラーになる)。
解説
- 【問題文】より
「変更連番3 の行は 2009-02-01 から 2009-05-31,変更連番5 の行は 2009-05-25 から 2009-05-31」
と記載されています。 - 図3の抽出条件を当てはめると,
- 変更連番3:
- 適用開始日 (2009-02-01) ≤ CURRENT_DATE (2009-05-25) → ○
- CURRENT_DATE (2009-05-25) ≤ 適用終了日 (2009-05-31) → ○
- 変更連番5:
- 適用開始日 (2009-05-25) ≤ CURRENT_DATE (2009-05-25) → ○
- CURRENT_DATE (2009-05-25) ≤ 適用終了日 (2009-05-31) → ○
よって両行が返され,結果行が2行以上になります。
- 変更連番3:
該当部分の再掲(例)
誤りやすいポイント
- 「適用開始日 ≤ CURRENT_DATE ≤ 適用終了日」の条件を単純に書くと,重複期間があると複数行取得になる点。
- 仕様では「1行しか返らない」ことを前提にしているSQL設計が多いため,重複時にはクライアント側でエラー扱い(例:ORA-01422など)になる場合がある。
試験対策ポイント
- 時間帯/期間を表すテーブルでは,「開始日~終了日」の連続性と非重複性を制約(チェック制約やトリガ)で保証する。
- 取得SQLでは,期間条件において期待する結果行数(1行/複数行)を常に確認し,重複時の動作(エラー or 意図的取得)を設計段階で明確化する。
- 「NULLを無期限扱いにする」場合も,重複チェックは必須。
設問2(3):〔変更後の“顧客” テーブルに関する指摘事項〕 ①〜③について,(1)〜(4)に答えよ。
指摘事項②に対応するために、変更連番の列名を“適用順番”に,その意味を“適用開始日の順番”に変更し、指摘事項 ①の制約条件を追加した。このとき,顧客コード C333333 の顧客属性情報の列値について,次の表中の(g)〜(j)に入れる適切な字句を答えよ。


模範解答
(g):333-3333
(h):2
(i):333-3333
(j):3
解説
1. 核心キーワード・論点整理
2. 解答に至る論理的説明
(1) 現状(適用順番3 まで)の確認
問題文より、行 3 までの内容は次のとおり。
・5/24 で優遇レベル 2 の行が終了している。
・指摘①より、次の行(適用順番4)は 5/25 から始まらなければならない。
・指摘①より、次の行(適用順番4)は 5/25 から始まらなければならない。
(2) これから行う 2 つの変更
- 電話番号の変更依頼(番号を 333-3333 へ)
− 適用開始日:2009-05-25(依頼者が指定)
− 優遇レベルは まだ 2 のまま - 優遇レベルを 3 へ先日付で変更
− 適用開始日:2009-06-01
− 電話番号は同じ 333-3333 を維持
(3) 行 4・行 5 の作成
適用順番4(5/25〜5/31)
・電話番号 … 新番号 333-3333(→ g)
・優遇レベル … 変更前と同じ 2(→ h)
・電話番号 … 新番号 333-3333(→ g)
・優遇レベル … 変更前と同じ 2(→ h)
適用順番5(6/1〜)
・電話番号 … 行4と同じ 333-3333(→ i)
・優遇レベル … 先日付で 3(→ j)
・適用終了日 … 将来未定なので NULL
・電話番号 … 行4と同じ 333-3333(→ i)
・優遇レベル … 先日付で 3(→ j)
・適用終了日 … 将来未定なので NULL
これにより
- 2/1〜5/24(順番3),5/25〜5/31(順番4),6/1〜NULL(順番5)と日付が切れ目なく連続
- 電話番号・優遇レベルの履歴も正しく保持
(4) 模範解答との対応
よって模範解答
(g) 333-3333, (h) 2, (i) 333-3333, (j) 3 となる。
(g) 333-3333, (h) 2, (i) 333-3333, (j) 3 となる。
3. 受験者が誤りやすいポイント
4. 試験対策ポイントまとめ
これらを押さえておけば、期間履歴を扱う問題や SQL の抽出条件に関する問題で迷いにくくなります。
設問2(4):〔変更後の“顧客” テーブルに関する指摘事項〕 ①〜③について,(1)〜(4)に答えよ。
指摘事項 ③に対応するために、(3)の変更を行った上で,変更受付日の列を追加し,その意味を次のように定義した。


しかし、この変更受付日の列の追加だけでは, “顧客属性情報の変更受付日を漏れなく記録したい” という要望にこたえられない場合がある。 どのような場合にこたえられないのか, 35字以内で述べよ。
模範解答
・同じ適用開始日に異なる変更受付日の顧客属性情報が存在する場合
・先日付で設定した適用開始日よりも前に顧客コードを削除する場合
解説
模範解答の核心となるキーワード・論点整理
- 同じ適用開始日に異なる変更受付日の顧客属性情報が存在する場合
- 先日付で設定した適用開始日よりも前に顧客コードを削除する場合
この2点は、単純に「変更受付日」列を追加しただけでは顧客情報の「変更受付日を漏れなく記録する」という要望を満たせないケースを指しています。
なぜこの解答になるのかの論理的説明
追加された「変更受付日」列の意味
表にあるように、
この「変更受付日」は「適用開始日」とは別に、顧客属性の変更依頼が実際に受け付けられた日付を記録するために追加されました。
1.同じ適用開始日に異なる変更受付日が存在する場合
顧客属性情報の変更履歴は「顧客」テーブルの各行で「適用開始日」「適用終了日」によって管理されていますが、
- 「適用開始日」は 変更した属性値が適用される開始日
- 「変更受付日」は 変更依頼を受け付けた実際の日付
これらは必ずしも1対1対応でなく、同じ「適用開始日」に対して複数の異なる「変更受付日」を持つ変更が存在することが十分ありえます。
つまり、
- 変更は先日付でまとめて適用開始日を設定(例えば月初)。
- しかし複数の変更依頼は異なる日(変更受付日)に受け付けられている。
これを同じ「顧客」テーブルの行で表せない(行のキーは「顧客コード」と「変更連番」であり、適用開始日が同じでは複数行は適切に区別できない)ため、「漏れなく」記録できないのです。
2.先日付で設定した適用開始日より前に顧客コードを削除する場合
設問の問題文にあるように、
顧客コードが削除されたときは、当該顧客行は削除されず、削除日付が設定される。
しかし、
- 先日付(過去の日付)で適用開始日を設定した場合、たとえば「2009-06-01」から適用開始日を設定し、
- その適用開始日よりも前(例えば2009年5月中)に顧客コードが削除されると、適切に履歴を表現できなくなります。
なぜなら「変更受付日」の列には変更受付や優遇レベルの設定日しか記録できず、削除日の管理が複雑になるため、削除の正確な記録と変更受付日の関連付けが困難になり「漏れ」が発生します。
受験者が誤りやすいポイント・ひっかけ解説
-
「変更受付日」と「適用開始日」は同じものだと思い込む誤り
問題では、変更適用開始日は「変更履歴の適用開始日」という意味であり、変更依頼が受け付けられた日付とは異なります。これを混同すると、履歴管理の要件を正しく理解できません。 -
先日付変更に伴う履歴表現の複雑さを見落とす
先日付変更により、適用開始日は過去の日付になる場合があります。これが「変更受付日」と異なり、履歴が特定の1行で一意に表せない状況の原因です。 -
「顧客コードの削除」との関連を理解しない点
顧客コードが削除された場合にも履歴行を残す設計ですが、これが変更受付日の記録漏れに影響することに気づかない受験者も多いです。
試験対策のポイント・覚えておくべき知識
-
履歴管理では「適用開始日」「適用終了日」と「変更受付日」の役割の違いを正確に理解する
- 適用開始日…属性が有効となる日付
- 変更受付日…実際に変更依頼があった日付
-
履歴テーブルのキー構成と一意性の関係を押さえる
- 変更連番は連続・一意となるが、同じ適用開始日で複数の変更受付日を管理できない設計上の限界に注意。
-
先日付変更処理が履歴管理に与える影響を理解する
- 過去の日付での適用開始日は、履歴の一貫性チェックや削除処理と絡んで矛盾を生じやすい。
-
顧客コード削除時の履歴保持ルールを理解する
- 削除は行の物理削除ではなく履歴行の適用終了日設定で管理し、追加の日時管理が必要になる場合があること。
-
履歴テーブルでの「漏れなく記録したい」要望は仕様的に困難なケースが存在することを意識する
物理的には追えない情報がある場合、設計の再検討や別テーブルの検討が必要になる。
以上を踏まえ、試験では「なぜ希望通りに変更受付日が記録できないか」について、履歴の管理構造と「適用開始日」との関係から説明できるように準備してください。特に、履歴が「適用期間」で区切られていることと、「変更受付日は複数存在する可能性がある」点の理解が重要です。
設問3:〔変更後の“顧客” テーブルに関する指摘事項〕 ④について, 答えよ。
指摘事項④に対応するために、具体的なテストデータを用いて検討した。適用期間中、月に1回以上の預け入れが存在する A〜I の顧客について、図5の SQL文を利用して集計した月間預入額の結果を表に整理した。 表中の顧客コード欄に該当する顧客コードを A〜I から選んですべて答えよ。 該当する顧客コードがない場合は、空欄にすること。
なお,SQL文の結果行が存在しなかった顧客の場合、月間預入額を0円とする。また,適用期間は連続していて、日にちが抜けたり,重なったりしていることはない。各顧客の支店番号, 顧客コード, 顧客名は変更されないものとする。



模範解答

解説
模範解答のキーワードと論点整理
本設問では,図5のSQL文に誤りがあることに起因して,顧客ごとの月間預入額が正しく集計できないケースを分類しています。
ポイントになるキーワード・論点は次のとおりです。
ポイントになるキーワード・論点は次のとおりです。
- 「顧客テーブルの変更履歴」への結合条件と,集計期間の重なり判定
- WHERE句中の
が**「適用開始日が月初以降」かつ「終了日が月末以前または未定」**という条件になっている点ISODATE('2009-04-01') <= z.適用開始日 AND (z.適用終了日 <= ISODATE('2009-04-30') OR z.適用終了日 IS NULL)
- 結果として
- 該当月に「適用開始日」が1件だけ存在 → 正しい件数
- 2件以上存在 → 預入明細行が重複して集計され,多くなる
- 0件 → 結合できず,0円になってしまう
以上を踏まえ,顧客コード A~I を次のように分類します。
なぜその解答になるのか
-
図5で本来必要だった「履歴レコードと集計期間との**,重なり(overlap)*判定」が,
―――適用開始日 ≤ 集計終了日 AND (適用終了日 ≥ 集計開始日 OR 適用終了日 IS NULL)
ではなく,ISODATE('2009-04-01') <= z.適用開始日 AND (z.適用終了日 <= ISODATE('2009-04-30') OR z.適用終了日 IS NULL)
と開始日が集計期間の開始日以降という逆向きの条件になっているため,- 集計期間中に開始日を持つ履歴だけを取り出す
- 開始日が「4月1日以前」の履歴は無視
- 開始日が「4月30日以降」の履歴も無視
-
結果として,顧客ごとに「適用開始日」が4月1日~4月30日の間に
- ちょうど1件 → 取引明細行は1回だけヒットし,正しい合計額
- 2件以上 → 同じ取引明細が複数の履歴行に結合,二重計上などで「多くなる」
- 0件 → そもそも結合できず,0円として扱われる
-
グラフで示された A~I の適用期間線分を見ると,
- A,D,F,G は「4月中に適用開始日を持つ履歴がちょうど1件」
- B,E は「4月中に適用開始日を持つ履歴が2件以上」
- C,H,I は「4月中に適用開始日を持つ履歴が0件」
したがって,上記の分類に対応します。
受験者が誤りやすいポイント
-
日付の重なり判定の定石を逆にしてしまう
- 重なり条件は「開始日 ≤ 期間終了日 & (終了日 ≥ 期間開始日 OR 終了日 IS NULL)」
- 本試験の誤り例では「期間開始日 ≤ 開始日 …」と逆向き
-
履歴テーブルとの結合で,明細行の重複・欠落が起きることに注意
- 結合条件がゆるいほど多重集計
- 結合条件がきついほど結合漏れ
-
NULLを含む日付比較
- 「適用終了日 IS NULL」を入れ忘れると,継続中履歴をすべて除外してしまう
試験対策として覚えておくべきポイント
-
期間(期間)の重なりoverlap判定は,必ず
期間開始 ≤ 履歴終了(またはNULLを含む継続) AND 履歴開始 ≤ 期間終了
の形で記述する。 -
SQLで履歴テーブルを扱う際は,履歴行ごとに合致するかどうかが多重計上・欠落の原因に
→ 必ず集計前に「該当履歴行が 1件だけ」になるよう調整(ビュー化,DISTINCTなど)を検討する。 -
NULL比較の扱い
- 「終了日が未定」=継続中 は
IS NULL
を必ず条件に含める。
- 「終了日が未定」=継続中 は
-
問題文中の誤ったSQLやワークフローを疑ってかかるクセをつけること。
特に「日付の向き」「NULLの扱い」「JOIN句の多重度」に着目しましょう。