応用情報技術者 2012年 秋期 午後 問06
スーパーマーケットの販売管理システムに関する次の記述を読んで、設問1~5に答えよ。
スーパーマーケットを営むQ社では、3年前にポイント制度を導入した。希望する顧客には、会員になってもらい、ポイントカードを提供する。買物の際にポイントカードを提示すると、100円につき1ポイントを加算する。たまったポイントは1ポイントにつき1円の換算で、精算の際に利用できる。ポイントの有効期限は、最後にポイントカードを使用した日から2年間である。
Q社の販売管理システムでのポイント制度に関係する部分のE-R図を図1に示す。

E-R図に対応する関係データベースのテーブル構造を図2に示す。実線の下線は主キーを表す。

会員でない顧客が購入した場合は、テーブル“売上”の列“会員コード”にはNULLが設定される。会員になっても、一度も購入しない場合もあり得る。
商品は、いずれかの商品種別に分類されるが、商品が存在しない商品種別もあり得る。商品の単価は、頻繁に変更される。
〔ポイント制度の改良〕
最近、競合する他のスーパーマーケットでもポイント制度を導入し、そちらのポイント制度の方が魅力的との評判で、売上を伸ばしている。そこで、Q社では、ポイント制度を会員にとって、より魅力的なものに改良し、売上の増加を図ることにした。検討の結果、次の仕様を追加することにした。
(1) マイレージサービス
会員の購入累計額に応じて、精算時に加算するポイントを整数倍する。この倍率をマイレージ倍率といい、例えば、“購入累計額が50万円以上だと2倍、100万円以上だと3倍”といった具合にして決定する。
購入累計額は、その年の1月1日からの購入金額の合計とする。年初におけるマイレージ倍率の初期値は、前年の購入累計額から決定する。買物での精算の際に、その年の購入累計額が、現在のマイレージ倍率よりも大きくなる金額に達したら、マイレージ倍率を更新し、次回の精算からは、新しいマイレージ倍率を適用する。
(2) タイムサービ
特定の曜日、時間帯に、特定の商品種別の商品を購入すると、その商品の購入金額に対して付与するポイントを整数倍する。この倍率をタイムサービス倍率という。
例えば、“日曜日の午前中は日用品のポイントを5倍にする”などの指定が可能である。設定の見直しと変更は随時行われる。
これらの仕様を追加するために、現行データベースのテーブルに必要な列を追加するとともに、図3に示すテーブルを新たに追加した。

設問1:
図1中のa~cに入れる適切なリレーションシップを答え、E-R図を完成させよ。図1の表記ルールに従って解答すること。
模範解答
a:-○──○→
b:←○──●-
c:←○──●-
解説
解答の論理構成
-
a(「会員」と「売上」のリレーションシップ)
- “会員でない顧客が購入した場合は、テーブル“売上”の列“会員コード”にはNULLが設定される。”
- “会員になっても、一度も購入しない場合もあり得る。”
⇒ 売上側から見ると会員がNULLになることがあるのでオプショナル(○)。会員側から見ると売上が0件の場合もあるため同じくオプショナル(○)。また 1 会員が複数の売上を持つため “1対多” で多側(売上)に矢印。
結果: -○──○→
-
b(「売上明細」と「商品」のリレーションシップ)
- 売上明細の主キーに “商品コード” が含まれており NULL 不可→売上明細は必ず 1 商品に属するので商品側は必須(●)。
- “会員でない顧客…” のような制約は商品に対しては無く、“商品の単価は、頻繁に変更される。” だけで “必ず売れる” とは書かれていない。従って商品が 1 度も売れない(売上明細が 0 件)場合がある → 商品側から売上明細はオプショナル(○)。
- 1 商品が多くの売上明細に現れるため多側(売上明細)に矢印。
結果: ←○──●-
-
c(「商品」と「商品種別」のリレーションシップ)
- “商品は、いずれかの商品種別に分類されるが、商品が存在しない商品種別もあり得る。”
⇒ 商品側は必ず 1 種別に属するので商品種別側は必須(●)。
⇒ 商品種別側から見ると商品が 0 件でもよいのでオプショナル(○)。 - 1 商品種別に多数の商品が属するので多側(商品)に矢印。
結果: ←○──●-
- “商品は、いずれかの商品種別に分類されるが、商品が存在しない商品種別もあり得る。”
誤りやすいポイント
- “○” と “●” を逆に付けるミス
「NULL が入る可能性」がある側が “○”、必ず関連がある側が “●” です。 - 矢印(多側)を間違える
「1 つが複数を持つ」側が矢印で “多” になります。 - 商品種別のオプショナリティ
“商品が存在しない商品種別もあり得る。” の一文を見落とすと必須(●)にしてしまう誤答になります。
FAQ
Q: 売上に会員コードが NULL の場合、リレーションシップはどう表すのですか?
A: 売上→会員が「存在しないことがある」ので売上側に “○” を付けて 0‒1 関係を示します。
A: 売上→会員が「存在しないことがある」ので売上側に “○” を付けて 0‒1 関係を示します。
Q: 同じ商品が売れた回数はどこで分かりますか?
A: 「売上明細」で商品コードを集計すれば分かります。1 商品が多くの売上明細を持つことは b の “矢印” が示しています。
A: 「売上明細」で商品コードを集計すれば分かります。1 商品が多くの売上明細を持つことは b の “矢印” が示しています。
Q: 商品種別に属さない商品はありますか?
A: 問題文に “商品は、いずれかの商品種別に分類される” とあるので必ず 1 種別に属します。属さない商品は存在しません。
A: 問題文に “商品は、いずれかの商品種別に分類される” とあるので必ず 1 種別に属します。属さない商品は存在しません。
関連キーワード: E-Rモデル、カーディナリティ、オプショナリティ、主キー、NULL
設問2:
テーブル“売上明細”には、列“単価”がある。列“単価”をもたずに、列“商品コード”からテーブル“商品”の列“単価”を参照する方法も考えられるが、あえて列“単価”をもつ目的を25字以内で述べよ。
模範解答
売上が発生した時点の単価を記録するため
解説
解答の論理構成
- 問題文は、テーブル“売上明細”に列“単価”を持たせた理由を問うています。
- 同時に「商品の単価は、頻繁に変更される。」という制約が示されています。
- もし“売上明細”に“単価”を持たず、都度テーブル“商品”の“単価”を参照すると、過去に確定した売上が後日の値上げ・値下げの影響を受け、正しい売上実績が得られなくなります。
- そこで売上確定時の価格を“売上明細”側に保存し、履歴として固定化します。
- よって解答は「売上が発生した時点の単価を記録するため」となります。
誤りやすいポイント
- 正規化だけを優先し、「列が重複する=冗長」と短絡的に判断してしまう。履歴保持が目的の場合はあえて非正規化を選ぶことがあります。
- 「商品の単価は、頻繁に変更される。」の一文を見落とし、動的参照でも問題なしと誤解する。
- 「売上明細は毎回作成されるので常に正しい」と思い込み、後日の単価更新による過去データの改ざんを想定しない。
FAQ
Q: 単価履歴テーブルを別に持たせれば良いのでは?
A: もちろん別テーブルで履歴管理しても運用できますが、本問は設計理由を問うだけなので「売上時点の単価を明細側へ固定する」というシンプルな方式を採用しています。
A: もちろん別テーブルで履歴管理しても運用できますが、本問は設計理由を問うだけなので「売上時点の単価を明細側へ固定する」というシンプルな方式を採用しています。
Q: 列を重複させると更新コストが増えませんか?
A: “売上明細”の“単価”は確定後に更新しないため、重複による更新コストや整合性維持の負担は実質発生しません。
A: “売上明細”の“単価”は確定後に更新しないため、重複による更新コストや整合性維持の負担は実質発生しません。
Q: 単価が変更されてもポイント計算には影響しませんか?
A: 影響しません。ポイント計算は「精算時点の購入金額」で行われるので、売上確定時点の単価が記録されていれば問題ありません。
A: 影響しません。ポイント計算は「精算時点の購入金額」で行われるので、売上確定時点の単価が記録されていれば問題ありません。
関連キーワード: 非正規化、履歴管理、更新履歴、時系列データ、データ整合性
設問3:
〔ポイント制度の改良〕(1)に対応するために、テーブル“会員”に追加する必要がある全ての列を、本文又は図中の字句を用いて答えよ。
なお、精算時の処理時間が長くならないように考慮すること。
模範解答
購入累計額、マイレージ倍率
解説
解答の論理構成
-
追加仕様の目的
- 本文には「“会員の購入累計額に応じて、精算時に加算するポイントを整数倍する。この倍率をマイレージ倍率といい”」とあります。
- さらに「“購入累計額は、その年の1月1日からの購入金額の合計とする”」とあり、会員ごとに当年累計を即座に参照できる状態が求められます。
-
精算処理の高速化要件
- 設問の指示として「“精算時の処理時間が長くならないように考慮すること”」と明記されています。
- 精算のたびに当年分の売上を合算すると I/O が増え遅延要因になります。したがって“会員”テーブルに累積値と倍率を持たせ、トランザクション毎に更新するほうが有利です。
-
必要列の抽出
- 仕様で頻繁に参照・更新される値は
• 「購入累計額」…マイレージ倍率算定の基礎
• 「マイレージ倍率」…ポイント計算時に直接利用 - これらを“会員”テーブルに保持すると、精算時は単一行を読むだけで済みます。
- 仕様で頻繁に参照・更新される値は
-
他候補列の検討と除外
- 「前年購入累計額」は年初に一度だけ参照すればよく、別テーブルや履歴で十分。高速化の観点でも常時参照対象ではないため除外します。
-
結論
- したがって追加すべき列は「購入累計額」「マイレージ倍率」です。
誤りやすいポイント
- “購入累計額”を計算式で求めれば列不要と判断するケース
→ 精算頻度が高い店舗システムでは毎回集計は現実的でありません。 - 「前年購入累計額」を必須と誤解
→ 年初のみ利用なので都度計算・別管理で十分、常設列にすると冗長です。 - マイレージ倍率を固定マスタへ分離し“会員”に置かない誤り
→ 会員ごとに倍率が異なり随時更新されるため個別属性です。
FAQ
Q: 追加列を別テーブルに分けた場合との違いは?
A: 精算処理でのJOIN回数が増えレスポンスが落ちやすくなります。一対一関係で更新・参照が高頻度なら同一テーブルに持たせた方が高速です。
A: 精算処理でのJOIN回数が増えレスポンスが落ちやすくなります。一対一関係で更新・参照が高頻度なら同一テーブルに持たせた方が高速です。
Q: “購入累計額”は年が変わったらどう初期化する?
A: 年初バッチで“購入累計額”を0にリセットし、その時点の値を基に“マイレージ倍率”を再計算しておく設計が一般的です。
A: 年初バッチで“購入累計額”を0にリセットし、その時点の値を基に“マイレージ倍率”を再計算しておく設計が一般的です。
Q: マイレージ倍率は実数でも良い?
A: 仕様に「“整数倍”」とあるので整数型で実装するのが妥当です。
A: 仕様に「“整数倍”」とあるので整数型で実装するのが妥当です。
関連キーワード: 正規化、インデックス、トランザクション、集計、更新処理
設問4:
〔ポイント制度の改良〕(2)に対応するために、図3中のdに入れる列を、本文又は図中の字句を用いて答えよ。列が主キーの一部となる場合は、実線の下線を付けること。
模範解答
d:商品種別コード
解説
解答の論理構成
- 仕様の読解
- 本文ではタイムサービスについて、
「特定の曜日、時間帯に、特定の商品種別の商品を購入すると、その商品の購入金額に対して付与するポイントを整数倍する。」
と記述されています。ここから“曜日・時間帯・商品種別”の3軸で適用範囲を管理する必要が読み取れます。
- 本文ではタイムサービスについて、
「特定の曜日、時間帯に、特定の商品種別の商品を購入すると、その商品の購入金額に対して付与するポイントを整数倍する。」
- 既存テーブルとの対応付け
- 既存のマスタには「商品種別」を識別する列として「商品種別コード」が存在します(図2 “商品種別”テーブルの主キー)。
- 追加する「タイムサービス」テーブルは、どの“商品種別”に倍率を適用するかを示す外部キーが不可欠です。
- 主キー設計
- タイムサービスは「設定の見直しと変更は随時行われる」とあり、同じ曜日・時間帯でも商品種別が異なれば別レコードとして登録できる設計が妥当です。
- したがって主キーは「曜日」「時間帯」「商品種別コード」の組合せになります。
- 結論
- 上記よりdには主キーの一部として「商品種別コード」を入れるのが論理的帰着です。
誤りやすいポイント
- 「商品コード」と取り違える
商品単位ではなく“商品種別”単位で倍率を決める仕様なので、細かすぎる「商品コード」を入れると要件を外れます。 - 主キーの下線を忘れる
設問は「列が主キーの一部となる場合は、実線の下線を付けること」と指示しています。下線漏れは減点対象です。 - 曜日・時間帯だけで一意と誤認
同じ曜日・時間帯で複数の種別に異なる倍率を設定できるため、商品種別を主キーに含めないと一意性を保てません。
FAQ
Q: 商品種別名ではなくコードを使うのはなぜですか?
A: 文字列の名前より整数や短いコードの方が検索・結合が高速で、正規化の観点からも冗長性を排除できます。
A: 文字列の名前より整数や短いコードの方が検索・結合が高速で、正規化の観点からも冗長性を排除できます。
Q: 列「商品種別コード」に外部キー制約は必要ですか?
A: はい。「商品種別」テーブルの主キー「商品種別コード」を参照する外部キー制約を設けることで、整合性を確保できます。
A: はい。「商品種別」テーブルの主キー「商品種別コード」を参照する外部キー制約を設けることで、整合性を確保できます。
Q: 時間帯はどのように表現すべきでしょうか?
A: 典型的には“HH:MI-HH:MI”形式の文字列、または開始時刻・終了時刻の2列で実装します。設問は列名だけが焦点なので詳細実装は問いません。
A: 典型的には“HH:MI-HH:MI”形式の文字列、または開始時刻・終了時刻の2列で実装します。設問は列名だけが焦点なので詳細実装は問いません。
関連キーワード: 主キー設計、外部キー制約、コンポジットキー、正規化、ER図
設問5:
マーケティング部門から、“〔ポイント制度の改良〕(2)で導入するタイムサービス倍率と商品の販売数量との相関関係を分析したい”と要求された。この分析を効率よく行うには、どのテーブルにどのような列を追加する必要があるか。本文又は図中の字句を用いて答えよ。
模範解答
テーブル:売上明細
列:タイムサービス倍率
解説
解答の論理構成
- 要求の把握
- マーケティング部門は“〔ポイント制度の改良〕(2)…タイムサービス倍率と商品の販売数量との相関関係を分析したい”と述べています。つまり、
・どの商品が何個売れたか(数量)
・その時適用された“タイムサービス倍率”
を同時に取得できる明細レベルのデータが必要です。
- マーケティング部門は“〔ポイント制度の改良〕(2)…タイムサービス倍率と商品の販売数量との相関関係を分析したい”と述べています。つまり、
・どの商品が何個売れたか(数量)
- 既存テーブルの確認
- 数量を保持しているのは図2の“売上明細(…数量)”のみです。
- “売上”や“売上明細”にはタイムサービス倍率を保持する列がありません。
- 倍率をどこに持たせるか
- “売上”は伝票ヘッダなので、同一伝票内に倍率対象商品と非対象商品が混在すると正確な分析ができません。
- “商品”や“商品種別”に倍率を加えると、タイムサービス設定を変更した際に過去実績が上書きされ、履歴が失われます。
- よって、商品単位の取引実績を保持する“売上明細”に、取引時点の“タイムサービス倍率”を固定値として書き込むのが最適です。
- 列名の決定
- 追加済みのマスタ“タイムサービス(…タイムサービス倍率)”と同じ字句“タイムサービス倍率”を用いれば、業務用語とデータ項目が一致して誤解を防げます。
以上より
テーブル:売上明細
列:タイムサービス倍率
が妥当であると結論づけられます。
テーブル:売上明細
列:タイムサービス倍率
が妥当であると結論づけられます。
誤りやすいポイント
- 売上テーブルに列を追加してしまう
- 同一売上番号内で倍率対象外の商品も含まれるケースを見落とし、数量との紐付けが崩れる。
- 商品テーブルに列を追加してしまう
- タイムサービスは曜日・時間帯条件で頻繁に変わるため、マスタ側に持たせると過去の倍率が失われ、時点修正が不能になる。
- 列名を勝手に短縮・別名に変更
- 問題文は“タイムサービス倍率”と明示しているので、別表記にすると減点対象になる。
FAQ
Q: タイムサービス倍率が設定されない通常販売の場合、列の値はどうするのですか?
A: 通常販売では倍率が1倍です。NULL ではなく“1”を格納しておけば、集計式でそのまま掛け算でき便利です。
A: 通常販売では倍率が1倍です。NULL ではなく“1”を格納しておけば、集計式でそのまま掛け算でき便利です。
Q: “タイムサービス倍率”は数値型と文字列型のどちらで定義すべきでしょうか?
A: 倍率計算に使用するため数値型(整数型)で定義します。分析時にも集計・平均値計算が容易になります。
A: 倍率計算に使用するため数値型(整数型)で定義します。分析時にも集計・平均値計算が容易になります。
Q: 明細テーブルに倍率を入れると正規化違反になりませんか?
A: 取引時点の履歴情報であり、マスタの属性ではなく“事実”なので第3正規形を満たします。むしろ履歴を残すためには冗長ではなく必要な項目です。
A: 取引時点の履歴情報であり、マスタの属性ではなく“事実”なので第3正規形を満たします。むしろ履歴を残すためには冗長ではなく必要な項目です。
関連キーワード: 相関分析、履歴管理、正規化、データモデリング、集計関数


