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


テーブルの設計及び SQL の設計に関する次の記述を読んで, 設問1〜3に答えよ。

 健康食品をインターネット販売している E 社は,受注管理システムを開発することになり、Fさんがデータベースの設計を任された。  
〔受注管理システムの要求仕様〕 1.商品  (1) 商品は,単品商品と詰合せセット商品 (以下, セット商品という)に区分する。商品には,一意な商品番号を付与する。  (2) セット商品には、一つの化粧箱に複数個の単品商品を詰め合わせたものと、複数種類の単品商品を詰め合わせたものがある。 単品商品は,複数種類のセット商品に含まれる。 セット商品を構成する単品商品ごとの数量 (構成数)は,決まっている。
2.注文  (1) 顧客は、1回の注文 (以下, 注文単位という)で,一つ以上の単品商品と一つ以上のセット商品を組み合わせて注文できる。 注文単位には,注文全体で一意な注文番号を付与する。  (2) 顧客は、インターネットから商品一覧照会処理を呼び出し、 商品番号、商品名,商品説明,写真,販売単価を商品一覧画面に表示させる。 表示される順番は、商品全体で重複がないように、 商品企画担当者が決めた表示順に基づく。  (3) 顧客は,表示画面から全ての購入希望の商品を検索して商品ごとの注文数を入力した後、注文処理を呼び出す。  (4) 注文処理は, 顧客が注文した商品を在庫から引き当て,注文番号,注文日 商品番号,商品名,販売単価,注文数, 注文額合計及びお届け予定日の日付 ( 注文日の3日後)を確認画面に表示する。 セット商品が不足した場合,そのセット商品に必要な数の単品商品を在庫から引き当てる。 確認画面のお届け予定日には,通常のお届け予定日に単品商品を化粧箱に詰め合わせるのに必要な日数を加える。 単品商品が不足することはない。  (5) 顧客は,注文内容を確認し,商品の送付先住所,顧客名,連絡先電話番号及び支払に必要な情報を入力し、注文を確定する。  
〔テーブルの設計〕   Fさんが設計した関係 “商品” 及び “在庫” の関係スキーマを、 図1に示す。
データベーススペシャリスト試験(平成26年 午後I 問3 図1)
 Fさんは, 関係“商品” のテーブルの設計に当たり,次の二つの案を考えた。   案1 サブタイプをスーパタイプに統合し、一つの“商品” テーブルとする。   案2 サブタイプ別に “単品商品” テーブル及び “セット商品” テーブルとする。  案1の“商品” テーブルの構造を図2に 案2の“単品商品” テーブル及び“セット商品” テーブルの構造を図3に示す。
データベーススペシャリスト試験(平成26年 午後I 問3 図2)
データベーススペシャリスト試験(平成26年 午後I 問3 図3)
 Fさんは,関係 “在庫” については,一つの“在庫” テーブルを設計した。 “在庫” テーブルと, その他の主なテーブルの構造を, 図4に示す。図4のテーブルは, 全て案12に共通とする。 また, 主な列の意味を表1に示す。   データベーススペシャリスト試験(平成26年 午後I 問3 図4)
データベーススペシャリスト試験(平成26年 午後I 問3 表1)
 Fさんが案1の“商品” テーブルに定義した制約を表2に, 案2の“単品商品”テーブル及び“セット商品” テーブルに定義した制約を表3に示す。  受注管理システムに採用する予定の RDBMS の UNIQUE 制約は,ユニーク索引を用いて実現される。 ユニーク索引は,一つのテーブル内でキー列の一意性を保証するものであり,ユニーク索引を複数のテーブルにまたがって作成することはできない。
データベーススペシャリスト試験(平成26年 午後I 問3 表2)
データベーススペシャリスト試験(平成26年 午後I 問3 表3)
 表2に示した案1 での NOT NULL 制約は不十分なので,F さんは,図5に示すように案の“商品” テーブルに検査制約を追加した。 検査制約は,次の①〜⑥のいずれかの述語を組み合わせて指定する。  ① 社内原価 IS NOT NULL  ② 社内原価 IS NULL  ③ 化粧箱番号 IS NOT NULL  ④ 化粧箱番号 IS NULL  ⑤ 詰合せ日数 IS NOT NULL  ⑥ 詰合せ日数 IS NULL
データベーススペシャリスト試験(平成26年 午後I 問3 図5) 
〔SQL文の設計〕  Fさんが,案1 と案2のそれぞれについて設計した主な SQL文を表4 に示す。
データベーススペシャリスト試験(平成26年 午後I 問3 表4)
〔注文トランザクションの設計〕  Fさんは,注文トランザクションについて,次のように設計した。
(1) 注文単位を一つのトランザクションで処理し,最後に COMMIT 文を発行する。 (2) 注文に基づいて, “注文” テーブル及び “注文明細” テーブルに行を挿入する。 (3) 商品については,商品一覧画面に表示された順番に“在庫” テーブルの引当可能数を調べ,引当可能ならば注文数を減算した値で引当可能数を更新する。 (4) セット商品が在庫不足のとき, “在庫” テーブルの不足セット商品数に不足数を加算する。“セット商品構成” テーブルから、主キー順に当該セット商品を構成する単品商品の構成数を調べ, 必要数を計算する。 単品商品については, “在庫” テーブルの引当可能数には必要数を減算した値で,不足セット商品用引当済数には必要数を加算した値で更新する。 (5) トランザクションの ISOLATION レベルは, READ COMMITTED とする。

設問1(1)〔テーブルの設計〕について,(1)〜(4)に答えよ。

表2 中の(a)に入れる適切な字句を答えよ。また,UNIQUE 制約を定義する目的を、 要求仕様に関する本文中の字句を用いて30字以内で述べよ。
模範解答
a:表示順 目的:商品全体で重複がないように商品の表示順を決めるため、商品の表示順を商品全体で一意にするため
解説

キーワード/論点整理

  • UNIQUE 制約:指定列の値をテーブル内で重複させないための制約
  • 対象テーブル:「商品」
  • 候補列:NOT NULL 制約が設定されている「商品名」「商品説明」「写真」「販売単価」「表示順」「単品区分」のうち、ビジネス要件で一意性が求められるもの
  • 仕様文からの引用
    「表示される順番は、商品全体で重複がないように、商品企画担当者が決めた表示順に基づく。」(要求仕様2.(2))

解答の根拠

  1. 表2を見ると、「商品」テーブルには次のように UNIQUE 制約が定義されています。
    テーブル名制約列名
    商品UNIQUEa
  2. 仕様2.(2)には
    「表示される順番は、商品全体で重複がないように、商品企画担当者が決めた表示順に基づく。」
    とあるため、一意性を保証すべき列は「表示順」であることが明らかです。
  3. よって、表2中の(a)には 表示順 を入れます。
  4. UNIQUE 制約の目的は、上記の仕様文中の「商品全体で重複がないように」に対応させて表現します。
    例:「商品全体で重複がないように商品の表示順を一意にするため」

受験者が誤りやすいポイント

  • 商品番号との混同
    商品番号は PRIMARY KEY で既に一意性が保証されているため、UNIQUE 制約の対象にはならない点に注意。
  • 「単品区分」や「販売単価」ではないかと考えがち
    これらの列には一意性要件がなく、同一区分や同一単価の商品が複数あっても問題ない。

試験対策として覚えておくべきポイント

  1. ビジネス要件を表す仕様文から「どの列に一意性が必要か」を正確に抜き出す
  2. UNIQUE 制約は「重複禁止」が目的。仕様中に「重複がないように」とあれば、そこがキーになる。
  3. UNIQUE 制約はユニーク索引で実現されるため、同一テーブル内でのみ設定可能。
  4. PRIMARY KEY は元々 UNIQUE なので、別途 UNIQUE 制約を設定する必要はない。

設問1(2)〔テーブルの設計〕について,(1)〜(4)に答えよ。

表3 中のテーブルについては, UNIQUE 制約を定義し, ユニーク索引を作成しただけでは,(a)に関する要求仕様を満たせない。その理由を、本文中の字句を用いて40字以内で述べよ。
模範解答
・ユニーク索引は一つのテーブル内でキー列の一意性を保証するため ・ユニーク索引を複数のテーブルにまたがって定義することはできないため
解説

1. キーワード・論点整理

  • 要求仕様:「表示される順番は、商品全体で重複がないように、商品企画担当者が決めた表示順に基づく。」
  • 表3では、単品商品テーブルとセット商品テーブルそれぞれにUNIQUE制約を定義
  • RDBMSのUNIQUE制約はユニーク索引で実現される
  • 問題文:「ユニーク索引は,一つのテーブル内でキー列の一意性を保証するものであり,ユニーク索引を複数のテーブルにまたがって作成することはできない。」

2. 解答への論理的説明

  1. 要求仕様では,「表示順」を商品全体で重複しないようにする必要があります。
    「表示される順番は、商品全体で重複がないように…」(問題文)
  2. 案2では,単品商品セット商品の2つのテーブルに分かれており,
    それぞれのテーブル内で表示順UNIQUE指定しても,
    テーブルをまたいで一意性を担保できません。
  3. したがって,UNIQUE(=ユニーク索引)だけでは
    要求仕様の「商品全体で表示順を一意にする」という要件が満たせないのです。

3. 受験者が誤りやすいポイント

  • 「UNIQUE制約を2つ定義すれば重複防止できる」と考えやすいが,
    制約はあくまで「1テーブル内」で有効
  • 「CHECK制約」で実現できると誤解しやすいが,CHECKは値の妥当性検査であり,
    テーブルをまたいだ一意性保証には使えない
  • 要件の「商品全体」という文言を見落とし,
    単品/セット各テーブル内だけを見てしまう

4. 試験対策として覚えておくべきポイント

  • UNIQUE制約=ユニーク索引によって実現され,必ず単一テーブル内のキー列だけを一意化
  • 複数テーブルにまたがる一意性保証は,
    ビューでまとめてUNIQUE指定できない限り,業務ロジックやトリガで担保する
  • 要求仕様の「全体」「各単品」「セット時のみ」などの範囲を正確に読み取る
  • 制約の種類ごとに適用範囲(テーブル内/複数テーブル/行内)を整理しておく

設問1(3)〔テーブルの設計〕について,(1)〜(4)に答えよ。

次の表に示すように外部キーを定義したとすれば, “セット商品構成” テーブルについては案1の場合に, “在庫” テーブルについては案2の場合に,不都合が起きるおそれがある。 項番 2,3の (ア), (イ)に入れる不都合の内容を, 項番1に倣って,35字以内で述べよ。 データベーススペシャリスト試験(平成26年 午後I 問3 設問1-3)
模範解答
ア:・単品商品番号列にセット商品番号を設定できてしまう イ:・「在庫」テーブルに行を挿入できない。   ・異なるテーブルのキーを同じ外部キーに入力できない。   ・単品商品番号とセット商品番号を同じ外部キーに入力できない
解説

キーワード・論点整理

  • サブタイプ/スーパタイプの設計
    • 案1:単品商品とセット商品を「商品」1テーブルに統合
    • 案2:サブタイプごとに「単品商品」「セット商品」の2テーブルに分割
  • 外部キー制約(参照整合性)
    • 参照先テーブルの主キー(または UNIQUE 制約列)にしか設定できない
  • UNIQUE 制約の実装
    • 本試験で採用予定の RDBMS では,UNIQUE 制約は「ユニーク索引」を用いて実現
    • ユニーク索引は「1つのテーブル内」に限って作成可能で,複数テーブルにまたがっては作れない

設問2(ア)の解説

項番テーブル名外部キー不都合例
2セット商品構成単品商品番号案1の場合、単品商品番号列にセット商品番号を設定できてしまう

なぜこの不都合が起きるのか

  1. 案1では「単品商品」「セット商品」を区別せず,1つの 商品 テーブルにまとめている
    (問題文より)
    「案1 サブタイプをスーパタイプに統合し、一つの“商品”テーブルとする」
  2. セット商品構成テーブルの 単品商品番号 列に外部キー制約を設定すると,
    「商品」テーブルのレコードなら 型(単品/セット)を問わず 参照を許すことになる
  3. 結果として,
    • 本来は「単品商品」でなければならない 単品商品番号 列に
    • 「セット商品」の商品番号を設定できてしまう

受験者が誤りやすいポイント

  • 「単品商品番号列 ← 単品テーブル参照」だと思い込み,
    サブタイプ混在の影響を見落としやすい
  • 外部キー制約の参照先はテーブル全体をチェックすることを理解しておく

設問3(イ)の解説

項番テーブル名外部キー不都合例
3在庫商品番号案2の場合、「在庫」テーブルに行を挿入できない

なぜこの不都合が起きるのか

  1. 案2では 単品商品セット商品 を別テーブルに分割
    (問題文より)
    「案2 サブタイプ別に “単品商品” テーブル及び “セット商品” テーブルとする」
  2. しかし 在庫 テーブルの外部キーを設定できるのは 参照先が1つのテーブル のみ
    • RDBMS の UNIQUE 制約はユニーク索引で実現され,
    • ユニーク索引は「1つのテーブル内」でしか作れない
      (問題文より)
    「ユニーク索引は,一つのテーブル内で…複数のテーブルにまたがって作成することはできない」
  3. 結果として,在庫.商品番号
    • 単品商品のキーに参照させる or
    • セット商品のキーに参照させる
      のどちらか一方しか外部キー設定ができず,
      他方のレコードを挿入しようとすると参照整合性違反で登録できない

受験者が誤りやすいポイント

  • 「外部キーさえ貼れば両方参照できる」と誤解しがち
  • UNIQUE 制約=単に『一意』だけでなく『索引実装の制限』を伴う点を押さえる

試験対策ポイント

  1. サブタイプ設計の方式
    • 単一テーブル+タイプ識別カラム vs サブタイプごとに分割
    • 外部キーや CHECK 制約への影響を整理しておく
  2. 外部キーの参照先制限
    • 参照先テーブルは1つ、かつ参照キー列は主キーまたは UNIQUE 制約列
  3. UNIQUE 制約の実装
    • UNIQUE 制約は「ユニーク索引」で実現される
    • ユニーク索引はテーブルごとに完結し,テーブルをまたげない
  4. 参照整合性が担保できないケース
    • サブタイプ分割で『親テーブルなし』の場合
    • 同一外部キーでサブタイプ両方を参照したいとき
以上を理解し,サブタイプ設計と参照制約の関係を明確に区別できるようにしておきましょう。

設問1(4)〔テーブルの設計〕について,(1)〜(4)に答えよ。

図5 中の(b)〜(e)に入れる適切な述語を、 ①〜⑥から一つずつ選んで答えよ。(b,cは順不同、d, eは順不同)
模範解答
b:④ c:⑤ d:② e:③
解説

キーワード・論点整理

  • 単品区分(列名)
    • 値が 'Y' のとき「単品商品」を表し,'N' のとき「セット商品」を表す。
  • 表1 より主な列の意味
    列名意味
    社内原価単品商品の社内原価。セット商品の販売単価を決める際に必ず使用される。
    化粧箱番号セット商品に使用される化粧箱を一意に識別する番号。セット商品には必ず一つの化粧箱が使われ、同じ化粧箱番号が複数のセット商品で使用される。
    詰合せ日数単品商品をセット商品として化粧箱に詰め合わせるのに要する日数。未定の場合、NULLが設定される。
  • CHECK 制約の骨格(図5)
    CHECK(
      (単品区分 = 'Y' AND ① AND ▢b▢ AND ▢c▢)
      OR
      (単品区分 = 'N' AND ▢d▢ AND ▢e▢)
    )
    
  • 選択肢
    ① 社内原価 IS NOT NULL
    ② 社内原価 IS NULL
    ③ 化粧箱番号 IS NOT NULL
    ④ 化粧箱番号 IS NULL
    ⑤ 詰合せ日数 IS NOT NULL
    ⑥ 詰合せ日数 IS NULL
  • 目標
    • 単品商品('Y'):
      • 社内原価 → 必ず値を持つ ⇒ ①
      • 化粧箱番号 → 使わない ⇒ NULL でなければならない ⇒ ④
      • 詰合せ日数 → 単品が詰め合わせられるまでの日数は必須 ⇒ NOT NULL ⇒ ⑤
    • セット商品('N'):
      • 社内原価 → 値を持たない(個々の原価ではなく、構成商品から算出) ⇒ NULL ⇒ ②
      • 化粧箱番号 → 必ず箱を持つ ⇒ NOT NULL ⇒ ③

解答の根拠

  1. 「単品区分 = 'Y'」(単品商品)の要件
    • 表1「社内原価」:
      単品商品の社内原価。セット商品の販売単価を決める際に必ず使用される。
      単品商品には必ず設定されるべき ⇒ 社内原価 IS NOT NULL(①)
    • 表1「化粧箱番号」:
      セット商品に使用される化粧箱を一意に識別する番号。
      単品商品では化粧箱を利用しない ⇒ 化粧箱番号 IS NULL(④)
    • 表1「詰合せ日数」:
      単品商品をセット商品として化粧箱に詰め合わせるのに要する日数。未定の場合、NULLが設定される。
      単品商品がセット化される際の日数を必ず設定できるようにする ⇒ 詰合せ日数 IS NOT NULL(⑤)
  2. 「単品区分 = 'N'」(セット商品)の要件
    • 社内原価を直接持たず,単品の合計原価で算出 ⇒ 社内原価 IS NULL(②)
    • 化粧箱番号は必須 ⇒ 化粧箱番号 IS NOT NULL(③)
これを当てはめると,CHECK 制約は次のようになります。
CHECK(
  (単品区分 = 'Y'
   AND 社内原価     IS NOT NULL    -- ①
   AND 化粧箱番号   IS NULL        -- b=④
   AND 詰合せ日数   IS NOT NULL    -- c=⑤
  )
  OR
  (単品区分 = 'N'
   AND 社内原価     IS NULL        -- d=②
   AND 化粧箱番号   IS NOT NULL    -- e=③
  )
)
名称記号選択肢
b化粧箱番号 IS NULL
c詰合せ日数 IS NOT NULL
d社内原価 IS NULL
e化粧箱番号 IS NOT NULL

受験者が誤りやすいポイント

  • ④と⑥の混同:
    • 「化粧箱番号 IS NULL」(④)と「詰合せ日数 IS NULL」(⑥)を取り違えやすい。
  • 単品商品にも「詰合せ日数」が必須である点の見落とし:
    • 一見「セット商品だけケース日数が要る」と思いがちだが,実際には単品を詰め合わせるのに要する日数を常に把握するため,詰合せ日数 IS NOT NULL が単品側に必要。
  • OR 節の条件数が異なることへの違和感:
    • セット商品側には「詰合せ日数」のチェックがないが,仕様上はセット自体では日数を持たず,単品の詰め合わせ日数を合算して扱うため不要。

試験対策として覚えておくべきポイント

  1. スーパタイプ/サブタイプの属性制約
    • サブタイプごとに必須・不要の属性を CHECK 制約で分岐させるパターンを押さえる。
  2. NULL と NOT NULL の使い分け
    • 「このサブタイプでは使わない属性」⇒ IS NULL,「必ず値を入れる属性」⇒ IS NOT NULL
  3. 仕様文と表1の対応
    • 実際の業務要件(表1)を見て,「どの列に NULL を許容/不許容にすべきか」を論理的に判断する練習を重ねる。
  4. CHECK 制約の OR 組み合わせ
    • 複数のサブタイプを1つのテーブルで管理する場合,(区分 = … AND 条件群) OR (区分 = … AND 条件群) の典型パターンを理解する。

設問2(1)〔SQL文の設計〕 について,(1)〜(3)に答えよ。

SQL2 及び SQL3 の実行結果を SQL1 と同じにしたい。(f),(g)に入れる適切な字句を 1 語又は2語で答えよ。 結果行の並び順は異なってよい。
模範解答
f:LEFT OUTER g:INNER
解説

キーワードと論点整理

  1. SQL1(案1)
    • 単一の“商品”テーブルから必ず1行取得できる
    • 社内原価または化粧箱番号のいずれかが NULL になる
  2. SQL2(案2)
    • 注文明細 M を起点に 単品商品セット商品 のテーブルを結合
    • 全ての注文行を残しつつ、該当する方のテーブルから値を取得したい
  3. SQL3(案2)
    • 注文明細を単品用とセット用に分割し、個別に INNER JOIN
    • 最後に UNION ALL で結合
→ f:LEFT OUTER
→ g:INNER

なぜ f = LEFT OUTER なのか

背景

  • 【問題文】の SQL1 は
    SELECT M.商品番号, P.社内原価, P.化粧箱番号
    FROM 注文明細 M, 商品 P
    WHERE M.商品番号 = P.商品番号
      AND M.注文番号 = :hv
    
    と、必ず一つの“商品”テーブル P から対応行を取ってくる。
  • 案2 では 商品 を「単品商品」テーブルと「セット商品」テーブルに分割しているため、
    注文明細の行数(注文数)を漏れなく残しつつ、
    単品商品の場合は社内原価、セット商品の場合は化粧箱番号を取得しなければならない。

INNER JOIN の問題点

  • SELECT M.商品番号, T.社内原価, S.化粧箱番号
    FROM 注文明細 M
         JOIN 単品商品 T ON M.商品番号 = T.商品番号
         JOIN セット商品 S ON M.商品番号 = S.商品番号
    
  • これは「単品にもセットにも登録されている商品番号」を持つ行だけを返す
    → 注文のすべての行が消えてしまう(単品商品だけ/セット商品だけの行を漏らす)

LEFT OUTER JOIN での解決

  • SELECT M.商品番号, T.社内原価, S.化粧箱番号
    FROM 注文明細 M
         LEFT OUTER JOIN 単品商品 T
           ON M.商品番号 = T.商品番号
         LEFT OUTER JOIN セット商品 S
           ON M.商品番号 = S.商品番号
    WHERE M.注文番号 = :hv
    
  • LEFT OUTER JOIN は「左側(注文明細)の行を必ず残す」
  • 単品商品の場合:
    • T.社内原価 ⇒ 値あり
    • S.化粧箱番号 ⇒ NULL
  • セット商品の場合:
    • T.社内原価 ⇒ NULL
    • S.化粧箱番号 ⇒ 値あり
  • これにより SQL1 と同じ結果セットが得られる

なぜ g = INNER なのか

背景

  • SQL3 は注文明細を単品用・セット用に分割し、UNION ALL で合成する方式
  • 単品分:… FROM 注文明細 M JOIN 単品商品 T …
  • セット分:… FROM 注文明細 M JOIN セット商品 S …

INNER JOIN が適切な理由

  • 各 SELECT 節では「該当テーブルに必ず存在する行だけ」を抽出する
  • もし LEFT OUTER JOIN を使ってしまうと、
    • 単品分の SELECT でセット商品の注文明細まで含めてしまったり、
    • セット分の SELECT で単品商品の注文明細まで含めてしまったり
  • 余分な NULL 行や重複行が入る可能性がある
  • INNER JOIN によって「該当レコードがある注文明細だけ」を取り込む設計がシンプルかつ明確

受験者が誤りやすいポイント

ポイント誤りが起きる理由
JOIN の方向(LEFT/RIGHT)選択「どちらを固定して残すか」を逆に考えてしまう
OUTER JOIN と UNION ALL の混同UNION ALL で行を複製/分割する設計に OUTER JOIN を使ってしまう
NULL の扱いNULL の有無で列の見え方が変わることを理解していない

試験対策として覚えておくべきポイント

  1. JOIN の基本
    • INNER JOIN:両方に存在する行だけ
    • LEFT OUTER JOIN:左側の行は必ず残す
  2. UNION ALL vs UNION
    • UNION ALL:重複を排除せず全ての行を結合
    • UNION:重複行を排除
  3. サブタイプ設計と SQL
    • 一つのテーブルにまとめた場合は単純結合
    • 分割した場合は LEFT OUTER JOINUNION ALL のどちらかで元の形に戻す
  4. NULL の挙動
    • OUTER JOIN で補われる NULL 列値に注意
    • NULL と結合条件の評価結果を正しくイメージする
  5. 実行計画・性能
    • OUTER JOIN や UNION ALL はテーブルサイズやインデックス設計と合わせて検討
これらを踏まえて、SQL2 では f = LEFT OUTER、SQL3 では g = INNER という選択が正解となります。

設問2(2)〔SQL文の設計〕 について,(1)〜(3)に答えよ。

SQL4 及び SQL5 は, 指定した注文について, 注文されたセット商品を構成する単品商品の合計数を求める SQL 文である。 SQL4 及び SQL5 の実行結果が同じになるように,(h)に入れる適切な字句を答えよ。
模範解答
h:M.注文数*M.構成数
解説

1. キーワード・論点の整理

  • SQL4/SQL5 の目的
    「指定した注文について, 注文されたセット商品を構成する単品商品の合計数を求める SQL 文」である。
  • 主なテーブルとカラム
    テーブル名カラム意味
    注文明細 (M)注文数顧客がその商品を何個注文したか
    セット商品構成 (K)構成数セット商品1個あたりに含まれる単品商品の個数
    セット商品構成 (K)単品商品番号セット商品に含まれる単品商品の商品番号
  • 合計すべき数値
    1つのセット商品について
     「注文数」×「構成数」
    を単品商品ごとに集約(SUM)する。

2. 解答の理由 ── なぜ「M.注文数*K.構成数」か

  1. 問題文の説明
    「SQL4 及び SQL5 は, 指定した注文について, 注文されたセット商品を構成する単品商品の合計数を求める SQL 文である。」
  2. 必要な数値は
    • 注文明細 M の M.注文数
    • セット商品構成 K の K.構成数
  3. 要求仕様の引用
    「セット商品を構成する単品商品ごとの数量 (構成数) は, 決まっている。」
    すなわち、1セットあたりに含まれる単品商品の個数が「構成数」。
  4. SQL の構造
    SELECT K.単品商品番号,
           SUM(  <h>  )
    FROM 注文明細 M
      JOIN セット商品構成 K
        ON M.商品番号 = K.セット商品番号
    WHERE M.注文番号 = :hv
    GROUP BY K.単品商品番号;
    
    上記の <h> に入れるべきは
    「注文されたセット商品1個あたりの単品商品数」を表す式、すなわち
    M.注文数 * K.構成数
  5. したがって
    h:M.注文数*K.構成数

3. 受験者が陥りやすいポイント

  1. 誤ったテーブル・エイリアスを使う
    • K.構成数 であるべきところを「M.構成数」と書く
    • JOIN の対象テーブルを取り違える
  2. 集約関数の引数を誤解する
    • 「SUM(M.注文数)」や「SUM(K.構成数)」だけにすると、セット商品ごとの合計は求まるが、
      単一セットあたりの数量と注文数の掛け算が反映されない。
  3. 掛け算ではなく足し算を書く
    • 「M.注文数 + K.構成数」などの誤り

4. 試験対策として覚えておくべきポイント

  1. テーブル名/エイリアスの対応
    • 注文明細 → M
    • セット商品構成 → K
  2. 掛け算のタイミング
    • 単品件数は「注文数 × 構成数」で求める
  3. GROUP BY と SUM の基本
    • GROUP BY で単品商品番号ごとに集約
    • SUM の引数に「M.注文数*K.構成数」を指定
  4. 問題文の仕様確認
    • 「セット商品を構成する単品商品ごとの数量(構成数)は、決まっている」
    • 仕様中の用語(「構成数」「注文数」など)を正確に SQL に反映する
これらを意識しておけば、SQL4/SQL5 における空欄 "(h)" は迷わず
M.注文数*K.構成数
と答えられます。

設問2(3)〔SQL文の設計〕 について,(1)〜(3)に答えよ。

SQL4 及び SQL5 のアクセスパスは,次に示すネストループ結合である。  ① “注文明細” テーブルの主索引を用いて指定された注文番号の行を取り出し, 商品番号を調べる。  ② ①で調べた商品番号ごとに,案1では“商品” テーブル, 案 2 では “セット商品” テーブルの主索引を用いてアクセスする。  ③ “セット商品構成” テーブルの主索引を用いてアクセスする。   これらのアクセスパスでは, SQL4 の方が, “セット商品構成” テーブルの主索引をアクセスする頻度が多かった。 そのアクセス頻度を減らすために, SQL4 の WHERE 句に AND で追加すべき述語を一つ答えよ。
模範解答
P:単品区分='N'
解説

キーワード・論点整理

  • SQL4 のネストループ結合
    1. 注文明細(M)の主索引で注文番号を絞り込み
    2. 商品(P)の主索引で M.商品番号 を検索
    3. セット商品構成(K)の主索引で P.商品番号 をセット商品番号として検索
  • アクセス頻度が多い理由
    商品テーブル(P)には単品商品・セット商品の両方が入っており,SQL4 のままだと「単品商品」に対してもステップ③のセット商品構成テーブルへのアクセスが試みられる
  • 最適化のポイント
    セット商品構成テーブルを探す必要があるのは「セット商品」の場合のみなので,WHERE 句で絞り込む

解答の根拠

問題文より引用します。
“商品” テーブルの主な列の意味
・単品区分:単品商品とセット商品を識別する区分値。区分値は、単品商品では ‘Y’、セット商品では ‘N’ が設定される。
SQL4 の WHERE 句は次のとおりです。
SELECT K.単品商品番号, SUM(…) 
FROM 注文明細 M, 商品 P, セット商品構成 K 
WHERE 
  M.注文番号 = :hv 
  AND M.商品番号 = P.商品番号 
  AND P.商品番号 = K.セット商品番号 
GROUP BY K.単品商品番号
このままでは M に含まれる単品商品 に対しても「P.商品番号 = K.セット商品番号」の結合を試みるため,K の主索引を無駄に高頻度でアクセスしてしまいます。
セット商品構成テーブルは セット商品 に対応する行しか持たないので,P.単品区分='N' を追加してセット商品のみを対象に絞り込むことで,K テーブルへの不要なアクセスを削減できます。
 WHERE 
   M.注文番号 = :hv 
   AND M.商品番号 = P.商品番号 
+  AND P.単品区分 = 'N'        ← 追加すべき述語
   AND P.商品番号 = K.セット商品番号 

受験者が誤りやすいポイント

  • Y/N の向き
    「単品区分='Y'」と逆に覚えてしまうと,セット商品ではなく単品商品だけに絞り込んでしまい,逆効果になります。
  • どのテーブルのカラムか
    「注文明細」や「セット商品構成」のカラムではなく,「商品」テーブルの単品区分カラムである点を見落としやすいです。
  • 結合順序との混同
    WHERE 句での絞り込み(selection)は,ネストループ結合の前に行われる「結合条件の最適化」に相当します。結合後に絞るのではないことを理解してください。

試験対策として覚えておくべきポイント

  1. 結合前の選択条件(push‐down selection)
    ネストループ結合では,結合する前に必要な行だけを残すような WHERE 条件の追加でアクセス回数を大幅に削減できる。
  2. テーブル設計時の区分カラム
    サブタイプを統合した場合,区分カラム(単品区分など)を使って処理の有無を制御するパターンを押さえておく。
  3. SQL アクセスパスの理解
    主索引アクセス→ネストループ結合の流れをつかみ,どこでボトルネックが生じるかを論理的に判断する練習を積む。

設問3(1)〔注文トランザクションの設計〕 について(1),(2)に答えよ。

次の TR1〜TR4 のうち、いずれか二つの組合せのトランザクションを同時に実行したとき, デッドロックが起きるおそれがある。 次の表中の (ウ)〜(カ) に, デッドロックが起きない組合せには○を, 起きるおそれがある組合せには×を記入せよ。  TR1:単品商品2個を注文する。  TR2:単品商品1個とセット商品1個を注文する。  TR3:セット商品 1個を注文する。 TR4 セット商品 2個を注文する。 データベーススペシャリスト試験(平成26年 午後I 問3 設問3-1)
模範解答
ウ:× エ:× オ:〇 カ:×
解説

1. キーワード・論点の整理

  • 排他ロックの順序
    • 単品商品やセット商品を引き当てる際,まず「在庫」テーブルの行を商品一覧画面に表示された順番(=表示順)に沿ってロックし,更新する。
    • セット商品が不足した場合,さらに「セット商品構成」テーブルから構成する単品商品を主キー順(セット商品番号→単品商品番号)で取得し,対応する「在庫」テーブルの行をロックして更新する。
  • デッドロックの本質
    • 2 つのトランザクションが互いに相手が保持するロックを待つ状態(循環待ち)になるとデッドロックが発生する。
    • デッドロック回避の基本は,「全トランザクションで同じ順序でロックを取得する」こと。
  • 各 TR のロック順序イメージ
    • TR1:単品商品 A, B(2 種類の単品)を注文
      ⇒ 在庫(A) → 在庫(B)
    • TR2:単品商品 B, さらにセット商品 S(構成に A)を注文
      ⇒ 在庫( B ) → 在庫( S ) → (構成主キー順で)在庫( A )
    • TR3:セット商品 S(構成に A)を注文
      ⇒ 在庫( S ) → 在庫( A )
    • TR4:セット商品 S, T(2 種類のセット,各々構成に A,B など)を注文
      ⇒ 在庫( 小さい表示順のセット ) → … → 「セット商品構成」の主キー順で構成単品の在庫

2. なぜ解答がそうなるか

まず,問題文から引用します。
(3) 商品については, … “在庫” テーブルの引当可能数を調べ, … 更新する。
(4) セット商品が在庫不足のとき, … “セット商品構成” テーブルから、主キー順に当該セット商品を構成する単品商品の構成数を調べ,… 更新する。
つまり,すべての TR は
  1. 在庫テーブルの行を「表示順」
  2. セット商品の場合は構成単品を「セット商品構成」の主キー順 でロック
    という2段階の順序で行ロック(UPDATE)を取ります。
異なる TR が異なる順序で同一行をロックしようとすると,循環待ちが起きてデッドロックになります。

(ウ)TR1 と TR2 の組合せ

TR1TR2
在庫(A) → 在庫(B)在庫(B) → 在庫(S) → 在庫(A)
  • TR1 は最初に A をロックし,次に B をロック。
  • TR2 は最初に B をロックし,その後 S, さらに A をロック。
  • TR1 ⇨ B を取りにいったところで TR2 が先に B をロックしており待機。
  • 一方 TR2 ⇨ A を取りにいったところで TR1 が先に A をロックしており待機。
  • 相互に待ち合う=デッドロック
    → 答えは ×

(エ)TR1 と TR3 の組合せ

TR1TR3
在庫(A) → 在庫(B)在庫(S) → 在庫(A)
  • TR1:最初に A → 次に B
  • TR3:最初に S → 次に A
  • もし TR1 が A をロック後に B を取りに行く前に,TR3 が A をロックすると…
    • TR1 は B へ進まずに「A のロック解除」を待つ
    • TR3 は A をロック中なので B は不要だが,【コミット/ロールバック時までロック解除しない】
    • TR1 は先に B を取れないためコミットできず → TR3 も先に A を取れない
  • 循環待ちが起こるおそれ
    → 答えは ×

(オ)TR3 と TR3 の組合せ

同じ処理(セット S の注文)を2 本立てで同時に実行すると,ロック順序は両者とも
在庫(S) → 在庫(A)
であり,順序が完全に一致します。
したがって互いに同じ順序でロックを取得し,循環待ちにはならず,常に一方が先に進んで終了できます。
→ 答えは

(カ)TR3 と TR4 の組合せ

TR3TR4
在庫(S) → 在庫(A)在庫(S1) → 在庫(S2) → … → (構成の在庫)
  • TR3 の最初のロック対象は S(セットS)
  • TR4 も最初に表示順で最小のセット(例 S1)をロック
  • しかし TR3 次に「在庫(A)」を取りに行くタイミングと,TR4 が「構成在庫(A)」を取りに行くタイミングが入れ違う可能性
  • 両者とも S, A を取る順序は同じに見えますが,TR4 はさらに別のセットS2→その構成…もロックしに行くので,同じ資源 S2 を TR3 が取らないにも関わらず,ロック解除のタイミングがずれてデッドロックのおそれがある
    → 答えは ×

3. 受験者が誤りやすいポイント

  • 「TR1:単品商品2個を注文」は,同一商品2個ではなく異なる単品2種類を扱う点に注意。
  • デッドロックの有無は「どの行を,どの順序でロックするか」が鍵。
    → 「表示順」と「セット商品構成の主キー順」を常に確認する。
  • 同じ TR 同士(オ)はロック順序が全く同じなので安全、異なる TR 同士はロック対象の組み合わせや順序が変わり得るので要注意。

4. 試験対策のまとめ

  • デッドロック回避には一貫したロック取得順序が必須。
  • 複数テーブル/複数行を更新する処理では,必ず「どの列」(プライマリキーや表示順)でソートしてから行を取得・更新する実装規約を守る。
  • 問題文中の「…順番に調べ…」「…主キー順に調べ…」は,必ずそのままロック順序と捉える。
  • 同じコードを実行するトランザクション同士はロック順序がそろうのでデッドロックは起きない
  • 問題選択肢では,必ず資源の共通性(何を共有しているか)とロック取得順序の差異からデッドロックの可能性を論じること。

設問3(2)〔注文トランザクションの設計〕 について(1),(2)に答えよ。

(1)で起きるおそれがあるとしたデッドロックを防ぐためには,一つのトランザクションの中で“在庫” テーブルの行をどの列の順番で更新すればよいか。 列名を答えよ。
模範解答
商品番号
解説

キーポイント整理

  • 本問は,複数の同時トランザクションが「在庫」テーブルの複数行を更新する際に,更新対象行のロック取得順序が異なるとデッドロックが発生する可能性があることを押さえる問題です。
  • RDBMS の排他ロックは通常,プライマリキーやユニークインデックス順に取得されるため,同一テーブル内で更新順序を 同一のキー順(商品番号順など) にそろえることでデッドロックを回避できます。
  • 模範解答は「商品番号」です。

解説

1. トランザクションの処理フロー確認

問題文中の注文トランザクション設計((3)~(4))では,注文単位ごとに以下のように「在庫」テーブルを更新します。
  1. 注文された商品(単品・セットを問わず)について, 「引当可能数」 を減算して更新
  2. セット商品不足時は
    • 「不足セット商品数」を加算
    • セット構成単品について 「引当可能数」「不足セット商品用引当済数」 を更新
ここで,同一テーブルの異なる行を同時に更新しようとすると,複数トランザクション間でロックの取り合いが起こりえます。

2. デッドロックの発生メカニズム

たとえば,以下のような状況を考えます。
  • トランザクションA:商品番号10 → 商品番号20 の順で更新
  • トランザクションB:商品番号20 → 商品番号10 の順で更新
  1. A が商品番号10行に排他ロックを取得
  2. B が商品番号20行に排他ロックを取得
  3. A が商品番号20行のロックを待ち,B が商品番号10行のロックを待つ
この状態でお互い解除を待ち続け,デッドロックに陥ります。

3. 解決策:キーの昇順(商品番号順)で更新

デッドロックを防ぐには,すべてのトランザクションでロックを取得する行の順序を統一すればよいです。
RDBMS はプライマリキー/ユニークインデックス順にロックを取得するため,
 「在庫」テーブルの行更新は 商品番号の昇順(または降順でも一貫して同じ順序)にすれば,
必ず同じ順序で行ロックを取得し,デッドロックを回避できます。
以上より,更新する列の順番として指定すべきカラムは
商品番号
です。

受験者が誤りやすいポイント

  • 「引当可能数」→「不足セット商品数」→「不足セット商品用引当済数」の列順と混同しやすい
    → 問われているのは “列” ではなく “行” のロック順序を決めるキー列名(=商品番号)
  • SQL の CHECK 制約やサブタイプ設計との関連を深読みしすぎる
    → 本小問はあくまでトランザクションのロック順序に着目

試験対策としてのまとめ

  • 複数行更新を行うトランザクションでは,更新対象の行を必ず同じキー(プライマリキーなど)順でアクセスする
  • これにより,異なるトランザクション間でのロック取得順序を統一し,デッドロックを未然に防ぐ
  • RDBMS のロック動作(行ロック,インデックス順ロック取得)も基本的な知識として押さえておくことが重要です。
← 前の問題へ次の問題へ →

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