データベーススペシャリスト試験 2009年 午後103


変更履歴を記録するテーブルに関する次の記述を読んで、設問1〜3に答えよ。

 H銀行では,預金者へのサービス向上を図るために,顧客情報管理に使用している“顧客”テーブルの設計を見直すことになった。 そのため, システム部の G 部長の下にプロジェクトチームが組まれ, F さんが設計を担当することになった。  
〔顧客情報管理の概要〕  顧客情報管理の主な業務内容は,次のとおりである。
(1) 営業店担当者は、顧客からの依頼によって電話番号などの顧客属性情報を変更する。変更した顧客属性情報は,依頼当日から適用される。 同一日に変更を取り消すことはない。 (2) 顧客ごとに設定した優遇レベルによって, ATM(現金自動預け払い機)の時間外利用手数料を割り引くなどのサービスを提供している。 (3) 優遇レベルは,新規登録時の預金額によって決定され, その後は預金残高などの利用状況に基づいて毎月末に決定される。 優遇レベルが変更となる場合は,月末日の夜間バッチ処理によって新たな優遇レベルが設定され, 翌月の1日から適用される。  
〔顧客情報管理に使用される主なテーブルの構造〕  顧客情報管理に使用される主なテーブルの構造を図1に示す。 各テーブルの主な列の意味及び制約は, 表1に示すとおりである。
データベーススペシャリスト試験(平成21年 午後I 問3 図1)
データベーススペシャリスト試験(平成21年 午後I 問3 表1)
〔“顧客” テーブルの変更〕  1.“顧客” テーブルの構造の変更   Fさんは、顧客属性情報 (顧客名、支店番号、郵便番号、住所,電話番号,優遇レベル)の変更を履歴として記録するために, “顧客” テーブルの構造を図2のように変更した。 追加した列の意味及び制約は,表2に示すとおりである。
データベーススペシャリスト試験(平成21年 午後I 問3 図2)
データベーススペシャリスト試験(平成21年 午後I 問3 表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日に優遇レベルが変更された。
データベーススペシャリスト試験(平成21年 午後I 問3 表3)
 2.変更後の“顧客” テーブルへの照会   (1) ある顧客の現在日付の顧客属性情報を1行読み込むために,図 3 のようなSQL文を設計した。ここで,現在日付を表す予約語を CURRENT_DATE とする。
データベーススペシャリスト試験(平成21年 午後I 問3 図3)
  (2) ある顧客の属性情報について, 優遇レベルが変更された日を調べる(例えば,表4のような結果行を求める) ために,図4のようなSQL文を設計した。
データベーススペシャリスト試験(平成21年 午後I 問3 表4)
データベーススペシャリスト試験(平成21年 午後I 問3 図4)    3.顧客属性情報を先日付で変更する処理   現在、月末日の夜間バッチ処理によって優遇レベルを設定しているが, 新規顧客の増加に伴い,処理時間に余裕がなくなった。 そこでH銀行では,毎月20日時点の預金残高などに基づいて優遇レベルを決め、 優遇レベルが変更となる場合は, 20日から月末日までのいずれかの日の夜間バッチ処理によって新たな優遇レベルを設定し、先日付となる翌月の1日から適用することにした。 例えば, 2009年5月20日に顧客コード C333333 の優遇レベルを2から3に先日付で変更する場合, 表 5 のように変更連番4の行を追加することにした。   また,優遇レベル以外の顧客属性情報の変更についても、顧客からの変更依頼を受け付けた日(以下,変更受付日という)ではなく、変更の適用を開始すべき指定日を適用開始日列に設定することにした。 しかし、顧客情報管理部門からは,“顧客属性情報の変更受付日を漏れなく記録したい” という要望が寄せられている。
データベーススペシャリスト試験(平成21年 午後I 問3 表5)
〔“取引履歴”テーブルの集計処理〕  Fさんは,“顧客” テーブルの構造を変更したことによって,これまで“取引履歴”テーブルと結合して顧客単位に集計処理を行っていた SQL文を見直した。  例えば、2009年4月の支店・顧客別月間預入額を集計する SQL 文を図5に示すように設計した。そして、テスト用の“取引履歴”, “口座”, “顧客”の各テーブルにテストデータをロードし, SQL文の実行結果を検証した。 ここで,ISODATE ( )は,日付を表す文字列を DATE型に変換するユーザ定義関数とする。
データベーススペシャリスト試験(平成21年 午後I 問3 図5)
〔変更後の“顧客” テーブルに関する指摘事項〕  G 部長は,F さんに対し、変更後の“顧客” テーブルに関して,次のように指摘した。
 ① 同一顧客の適用期間は、連続していなければならない。 すなわち、変更連番が 1以外の場合の適用開始日は、変更連番が一つ前の行の適用終了日と連続していなければならない(日にちが抜けたり,重なったりしてはならない)。 その制約条件を追加し,制約が守られているかどうかを検証する SQL文を設計すべきである。  ② 優遇レベルを先日付で変更する処理について, 更に検討する必要がある。  ③ 顧客属性情報の変更受付日を漏れなく記録したい” という顧客情報管理部門からの要望にこたえていない。  ④ 図5の支店・顧客別月間預入額を集計する SQL文には,誤りがある。

変更履歴を記録するテーブルに関する次の記述を読んで、設問1〜3に答えよ。

設問1変更後の“顧客” テーブルを照会する SQL文について(1)(2)に答えよ。

(1)図3のSQL文中の(a), (b)に入れる適切な字句を答えよ。(a, bは順不同)

模範解答

a:・適用終了日=CURRENT_DATE   ・適用終了日>=CURRENT_DATE b:適用終了日 IS NULL

解説

解答の論理構成

  1. 現在有効な行の定義
    【問題文】表2 に「適用終了日 … 終了日が未定の場合は、NULL が設定される」とある。よって “現在有効” とは
    ・適用開始日 ≦ CURRENT_DATE
    ・適用終了日 ≧ CURRENT_DATE または NULL
    である。
  2. SQL の読み替え
    図3 の WHERE 句は
    適用開始日 <= CURRENT_DATE
    AND ( (a) OR (b) )
    これを上記定義に合わせると
    • (a):適用終了日 が CURRENT_DATE 以降を示す条件
    • (b):適用終了日 が NULL を示す条件
  3. (a) の書き方
    当日を含めるには「適用終了日=CURRENT_DATE」または「適用終了日>=CURRENT_DATE」のいずれでも論理的に同値。
  4. (b) の書き方
    NULL 比較は演算子でなく「IS NULL」を用いる必要がある。

誤りやすいポイント

  • NULL を大小比較してしまい「適用終了日 >= CURRENT_DATE」を書いたまま (b) を省略する。
  • 「適用終了日 > CURRENT_DATE」として当日ちょうど終了する行を落としてしまう。
  • 「適用終了日 = NULL」と書くなど、NULL 判定の文法ミス。

FAQ

Q: 「適用終了日>=CURRENT_DATE」と「適用終了日=CURRENT_DATE」はどちらが正しいですか?
A: 当日まで有効ならどちらでも論理的に正しいため、問題では両方を正解扱いとしています。
Q: NULL を含めて比較できる演算子はありますか?
A: ANSI SQL では NULL は3値論理の “UNKNOWN” になるため、比較演算子ではなく「IS NULL/IS NOT NULL」で判定します。
Q: なぜ (a) と (b) を OR で結ぶ必要があるのですか?
A: “終了日が当日以降” と “終了日が未定” は互いに排他的で、どちらかを満たす行を取得する必要があるためです。

関連キーワード: 期間管理, NULL判定, WHERE句, 日付関数, 3値論理

設問1変更後の“顧客” テーブルを照会する SQL文について(1)(2)に答えよ。

(2)図4のSQL文中の(c), (d)に入れる適切な字句を答えよ。

模範解答

c:X.変更連番 + 1 d:X.優遇レベル

解説

解答の論理構成

  1. 目的確認
    図4の SQL 文は「優遇レベルが変更された日を調べる」ものです。したがって直前行と優遇レベルが異なる行だけを抽出する必要があります。
  2. 自己結合のキー
    where 句に
    AND (c) = Y.変更連番
    とあるため、Y 側が「X 側の次の連番」であることを示す式を入れます。履歴テーブルは表2で「変更連番…1ずつ増加する整数が付与される。連番に抜けはない。」と定義されているので、一意に次行を示すのは「X.変更連番 + 1」です。
  3. 優遇レベル差異の判定
    同一行を結んだだけでは優遇レベルが変わったか分かりません。問題文には「優遇レベルが変更された日を調べる(例えば、表4のような結果行を求める)」と書かれています。そこで (d) に優遇レベルの不一致条件を置きます。X と Y は隣接行なので、異なるときだけ抽出すればよく、式は「X.優遇レベル」と「Y.優遇レベル」を比較します。where 句では Y.優遇レベル と比較するため (d) には「X.優遇レベル」が入ります。
  4. 以上より
    c: X.変更連番 + 1
    d: X.優遇レベル

誤りやすいポイント

  • 変更連番のずらしかたを「−1」としてしまう
    X が最新行、Y が前行と誤解すると逆になります。where 句の (c) = Y.変更連番 の向きを確認しましょう。
  • 優遇レベル比較で「=」を使い抽出できない
    変更を検出するので不一致条件 (≠) が必要です。
  • 変更連番に「NULL 存在可能」と勘違い
    表2に「連番に抜けはない」と明記されています。NULL は入りません。

FAQ

Q: 変更連番が飛ぶ可能性はまったくありませんか?
A: 表2の定義で「1から始まり1ずつ増加する整数が付与される。連番に抜けはない。」と規定されているため、論理的に飛びは起こりません。
Q: 最新の優遇レベルだけ取得したい場合はどうすればよいですか?
A: 顧客コードごとに MAX(変更連番) をサブクエリやウィンドウ関数で求め、その行を抽出する方法が一般的です。
Q: テーブル分割(履歴テーブルと現行テーブル)にしない利点は?
A: 1つのテーブルで履歴と現行を管理すれば、更新・参照ロジックを共通化できる反面、パフォーマンスや制約管理は自己結合で解決する必要があります。

関連キーワード: 自己結合, 更新履歴管理, 差分抽出

設問2〔変更後の“顧客” テーブルに関する指摘事項〕 ①〜③について,(1)〜(4)に答えよ。

(1)指摘事項 ①に対応するために、適用終了日が NULL でも削除日付でもない行のうち, 適用期間が連続していない行を読み込むための SQL 文を設計したい。 次の SQL 文中の(e),(f)に入れる適切な字句を答えよ。  ここで,NEXT_DAY()は, 引数とした日付の翌日付を求めるユーザ定義関数とする。なお、(c)には設問1の(2)と同じ答えが入る。 データベーススペシャリスト試験(平成21年 午後I 問3 設問2-1)

模範解答

e:X.顧客コード f:Y.適用開始日

解説

解答の論理構成

  1. 不連続期間検出の要件
    “同一顧客の適用期間は、連続していなければならない。” と指摘されています。さらに「変更連番が一つ前の行の適用終了日と連続していなければならない(日にちが抜けたり、重なったりしてはならない)。」とあります。
  2. 主問い合わせ X の対象行
    WHERE 句の最初で
    AND ( X.適用終了日 IS NOT NULL … とあるため、適用終了日が存在する行 (終了済み行) を X として取り出しています。
  3. 副問い合わせ Y との結合条件
    “同一顧客” を突き合わせる必要があるため、(e) には「X.顧客コード = Y.顧客コード」を置くのが自然です。
  4. “連番が一つ前の行” の参照
    (c) に入るのは設問1(2)と同じ式、すなわち「X.変更連番 − 1」です。これにより Y は X の1つ前の連番行に限定されます。
  5. 連続性チェックの日付
    NEXT_DAY(X.適用終了日) と比較すべきは “一つ前の行(Y) の適用開始日” です。よって (f) は Y.適用開始日 になります。
  6. 以上より
    (e) :X.顧客コード
    (f) :Y.適用開始日

誤りやすいポイント

  • 主問い合わせと副問い合わせを逆に考え、(e) に Y.顧客コード を書いてしまう。
  • 連続性の判定を X.適用開始日 と比較してしまい、同一行を比べてしまう。
  • “適用終了日 IS NOT NULL” を見落とし、削除済み行や現用行まで対象に含めてしまう。

FAQ

Q: “NEXT_DAY(X.適用終了日)” を使う理由は何ですか?
A: 指定要件で「変更連番が一つ前の行の適用終了日と連続していなければならない」とあります。終了日の翌日が開始日であれば連続と判定できるため、翌日を求める NEXT_DAY 関数が用意されています。
Q: なぜ外部結合ではなく EXISTS を使うのですか?
A: 不連続である行だけを抽出したいので、対応する前行が存在し、かつ日付が一致しないケースを探す EXISTS 句がシンプルに記述できます。外部結合で NULL チェックを行うより可読性が高く、集合の絞り込みにも適しています。
Q: 副問い合わせは “変更連番 + 1” でも良いですか?
A: 今回の主問い合わせ X は適用終了日を持つ行(過去行)です。副問い合わせ Y で参照したいのはそのすぐ後の「現行または未来行」ではなく “一つ前の行” なので、X.変更連番 − 1 が正解です。

関連キーワード: スローチェンジディメンション, サブクエリ, 日付整合性, 連続期間チェック

設問2〔変更後の“顧客” テーブルに関する指摘事項〕 ①〜③について,(1)〜(4)に答えよ。

(2)指摘事項②を確認するために、顧客コード C333333 の電話番号が 2009年5月25日に変更された場合を想定して, “顧客” テーブルに次の表のように変更連番 5 の行を追加した。 しかし、指摘事項 ① に対応していないので、図3のSQL文では,例えば, CURRENT_DATE が 2009年5月25日であるとき, 想定した結果を得られない。 どのような結果になるのか, 15字以内で述べよ。 データベーススペシャリスト試験(平成21年 午後I 問3 設問2-2)

模範解答

・結果行が複数行になる。 ・SQL 文の実行が失敗する。

解説

解答の論理構成

  1. 【問題文】では指摘事項①として
    “同一顧客の適用期間は、連続していなければならない。” と明記。
  2. しかし先日付変更のテストで追加した行(変更連番 5)は
    適用開始日 = '2009-05-25'/適用終了日 = '2009-05-31'
    既存の変更連番 3適用終了日 = '2009-05-31')と期間が重複。
  3. 図3 の検索条件
    • 適用開始日 <= CURRENT_DATE
    • (a) OR (b) = “適用終了日 IS NULL または 適用終了日 >= CURRENT_DATE
      を両行が同時に満たすため、検索結果は2行。
  4. したがって「結果行が複数行になる。」が答え。

誤りやすいポイント

  • “NULL 行が1つだけ”という前提を崩して考え直さないまま、結果件数を1行と決めつける。
  • 適用終了日 IS NULL の行しかヒットしないと誤解し、重複期間の存在を見落とす。
  • “制約違反→SQL エラー”と早合点し、実行自体は成功してしまう点を失念。

FAQ

Q: 制約違反なら DBMS が自動で INSERT を拒否しませんか?
A: 本問題の制約①は論理仕様であり、まだ DB 制約として実装していない設定です。よって INSERT 自体は成功し、検索結果に影響が出ます。
Q: 図3(a)(b) は具体的に何ですか?
A: 典型的には (a) 適用終了日 IS NULL(b) 適用終了日 >= CURRENT_DATE の組合せが使われます。両方 OR なので期間重複があれば複数行抽出されます。
Q: この問題を防ぐにはどうすれば良いですか?
A: CHECK 制約やトリガで “前行の 適用終了日 = 新行の適用開始日 - 1” を保証し、物理的に重複挿入をブロックします。

関連キーワード: 時間属性データ, 履歴管理, NULL 判定, 制約違反, 抽出条件

設問2〔変更後の“顧客” テーブルに関する指摘事項〕 ①〜③について,(1)〜(4)に答えよ。

(3)指摘事項②に対応するために、変更連番の列名を“適用順番”に,その意味を“適用開始日の順番”に変更し、指摘事項 ①の制約条件を追加した。このとき,顧客コード C333333 の顧客属性情報の列値について,次の表中の(g)〜(j)に入れる適切な字句を答えよ。 データベーススペシャリスト試験(平成21年 午後I 問3 設問2-3)

模範解答

(g):333-3333 (h):2 (i):333-3333 (j):3

解説

解答の論理構成

  1. 制約の確認
    • 指摘事項①より「適用開始日は、適用順番が一つ前の行の適用終了日の翌日でなければならない」
    • 指摘事項③より「変更受付日を漏れなく記録したい」
  2. イベントの整理
    • “2009-05-24” までは電話番号 “333-2222”・優遇レベル “2”
    • “2009-05-25” に電話番号変更を受付(優遇レベルはまだ “2”)
    • “2009-06-01” から優遇レベル “3” を適用
  3. 行の割付
    • 3 行目が “2009-02-01” ~ “2009-05-24” レベル “2” で確定
    • 4 行目は受付日 “2009-05-25” を起点に電話番号 “333-3333”・優遇レベル “2”・適用終了日 “2009-05-31”
    • 5 行目は先日付 “2009-06-01” 開始、電話番号 “333-3333”・優遇レベル “3”・適用終了日 NULL
  4. 値の確定
    よって
    (g) = “333-3333” (h) = “2” (i) = “333-3333” (j) = “3”

誤りやすいポイント

  • 先日付処理を 1 行で済ませようとして期間が重複/欠落する
  • 電話番号変更と優遇レベル変更を同じ行で更新し、受付日が記録できなくなる
  • 適用終了日 NULL の行は必ず 1 行だけという暗黙ルールを忘れる

FAQ

Q: 適用終了日が NULL の行は常に最新行ですか?
A: はい。同一顧客に対し適用終了日が NULL の行は 1 行のみで、最新の属性値を保持します。
Q: 先日付の優遇レベルを更新する際、適用開始日はいつに設定すれば良いですか?
A: 実運用で開始させたい日(例では “2009-06-01”)。受付日と異なる場合は受付日から開始日-1 日までを別行で管理し、期間を連続させます。

関連キーワード: 履歴管理, 適用開始日, 先日付更新, NULL終端行, 連続期間制約

設問2〔変更後の“顧客” テーブルに関する指摘事項〕 ①〜③について,(1)〜(4)に答えよ。

(4) 指摘事項 ③に対応するために、(3)の変更を行った上で,変更受付日の列を追加し,その意味を次のように定義した。 データベーススペシャリスト試験(平成21年 午後I 問3 設問2-4)
 しかし、この変更受付日の列の追加だけでは, “顧客属性情報の変更受付日を漏れなく記録したい” という要望にこたえられない場合がある。 どのような場合にこたえられないのか, 35字以内で述べよ。

模範解答

・同じ適用開始日に異なる変更受付日の顧客属性情報が存在する場合 ・先日付で設定した適用開始日よりも前に顧客コードを削除する場合

解説

解答の論理構成

  1. 【問題文】では“顧客”テーブルに対し「当該顧客の属性情報(優遇レベル以外)の変更依頼を受け付けた日付、又は優遇レベルを設定した日付」を格納するために“変更受付日”列を追加したと記述されています。
  2. しかし“変更受付日”は列であり、1 行につき 1 つの値しか保持できません。
  3. 業務上は、同じ“適用開始日”でも「名称変更」と「住所変更」など複数件の依頼を別日に受け付けることがあります。この場合、後に入力した値が前の受付日を上書きし、前回受付日が失われます。
  4. さらに【問題文】で説明されている先日付処理では「“適用開始日”が翌月1日、受付日は当月20日」となりますが、その後“顧客コード”が当月25日に削除されると、削除を示す新行を追加するだけで、20 日の受付日を持つ行が存在しない状態となります。
  5. よって「受付日が漏れなく記録されないケース」が発生します。

誤りやすいポイント

  • 「列を追加=全要件を満たす」と短絡的に考える。イベントの多重発生に列追加だけでは対応できません。
  • 「削除日は NULL でなく実日付を格納するので問題ない」と思い込み、削除用に新行を作るロジックと先日付の関係を見落とす。
  • 受付日と適用開始日の違いを混同し、「いつ受け付けた変更か」が履歴で消える可能性に気付かない。

FAQ

Q: 列ではなく別テーブルに“変更受付履歴”を作ると何が改善されますか?
A: 受付日がイベント単位で無制限に保持でき、同一“適用開始日”に複数受付日があっても漏れなく記録できます。
Q: 先日付で登録後に削除が決まった場合、どのように対処すべきですか?
A: 削除行とは別に「受付日=先日付登録日、適用開始日=翌月1日、適用終了日=削除日-1」の行を追加し、受付日情報を残します。
Q: “変更連番”を受付イベントごとに増やせば良いのでは?
A: “変更連番”は適用期間の順序を示すため、受付イベントごとに増やすと適用期間が重複して業務ロジックが破綻します。

関連キーワード: 先日付処理, 履歴テーブル設計, 実体‐イベント分離, データ保持要件, 行追記方式

設問3〔変更後の“顧客” テーブルに関する指摘事項〕 ④について, 答えよ。

 指摘事項④に対応するために、具体的なテストデータを用いて検討した。適用期間中、月に1回以上の預け入れが存在する A〜I の顧客について、図5の SQL文を利用して集計した月間預入額の結果を表に整理した。 表中の顧客コード欄に該当する顧客コードを A〜I から選んですべて答えよ。 該当する顧客コードがない場合は、空欄にすること。  なお,SQL文の結果行が存在しなかった顧客の場合、月間預入額を0円とする。また,適用期間は連続していて、日にちが抜けたり,重なったりしていることはない。各顧客の支店番号, 顧客コード, 顧客名は変更されないものとする。 データベーススペシャリスト試験(平成21年 午後I 問3 設問3(図))
データベーススペシャリスト試験(平成21年 午後I 問3 設問3(表))

模範解答

データベーススペシャリスト試験(平成21年 午後I 問3 設問3解答)

解説

解答の論理構成

  1. 【問題文】図5 SQL
    AND ISODATE('2009-04-01')<= Z.適用開始日
    AND ( Z.適用終了日<=ISODATE('2009-04-30') OR Z.適用終了日 IS NULL )
    
    を引用すると,履歴行が「4月1日以降に開始し,4月30日以前に終了(又は継続)」でなければ結合対象にならないことが分かる。
  2. 顧客別タイムラインの判定
    • A・D・F・G:該当月に条件を満たす履歴行が“ちょうど1行”存在。SUM は正しく算出。
    • B・E:4月中に条件を満たす履歴行が“2行”存在。取引1件が2行に重複結合し,正しい額より多くなる。
    • C・H・I:条件を満たす履歴行が“0行”。取引は存在しても結合できず 0円となる。
    • 「正しい月間預入額よりも少なくなるが、0円ではない。」に該当するパターンは図のタイムラインには現れないため空欄。
  3. したがって表の空欄には
    • A、D、F、G
    • B、E
    • C、H、I
      をそれぞれ記入する。

誤りやすいポイント

  • “終了日≦月末” の不等号方向を逆に読み,4月30日を超える行が除外されることに気付かない。
  • 取引日と顧客履歴の日付を結合条件で突き合わせていないため,重複・漏れが起きることを見落とす。
  • 「0円=取引が無い」と早合点し,履歴行未該当でも取引があるケースを想定できない。

FAQ

Q: なぜ B・E だけが過大計上になるのですか?
A: 4月1日以降開始・4月30日以前終了の履歴行が2本あり,どちらも SQL の条件を満たすため,1件の預け入れが2本の履歴行に重複結合して二重計上されるからです。
Q: 終了日が NULL の行は必ず集計対象になりますか?
A: いいえ。“開始日が4月1日以降” という前段の条件も同時に満たす必要があります。開始日が3月以前なら NULL でも除外されます。
Q: 「少なくなるが0円ではない」行が出ないのはなぜ?
A: 図のタイムラインでは「条件を満たす履歴行が1本だけ」か「0本」のどちらかしか存在しないためです。複数行が存在して重複を排除した結果一部だけ計上されるケースが作られていません。

関連キーワード: 履歴型テーブル, 等価結合, 範囲条件, 多重計上, NULL処理
← 前の問題へ次の問題へ →

©︎2025 情報処理技術者試験対策アプリ