応用情報技術者 2009年 春期 午後 問06
注文管理システムの設計と実装に関する次の記述を読んで、設問1〜3に答えよ。
S社は、園芸用品の製造及び販売を行う中堅企業である。顧客である農家やホームセンターから電話やファックスで注文を受け、注文管理システム(以下、現行システムという)で管理している。現行システムの機能概要を表1に、E-R図を図1に示す。


〔新注文管理システムについて〕
近年、家庭菜園やガーデニングの流行などによって、園芸用品の個人需要が高まってきた。そこで、販売力強化と顧客満足度向上を目的に、次の機能強化を行った新注文管理システム(以下、新システムという)を開発することになった。
(1) セット商品の導入
目的別に複数の商品を組み合わせたセット商品を導入する。さらに、単品で商品を購入しようとしている顧客に、その商品が含まれているセット商品を案内することによって、セット商品を購入するように誘導し、顧客単価の向上を図る。
セット商品も、通常の商品と一緒に商品エンティティに登録する。両者を区別するために商品エンティティに属性“セットフラグ”を追加し、通常の商品の場合は“0”を、セット商品の場合は“1”を設定する。そして、セット商品エンティティを追加し、セットに含まれる商品の商品番号とその数量を管理する。
(2) 新モデルお知らせ機能の追加
毎年新しいモデル(以下、新モデルという)が出る商品では、その履歴を管理し、顧客が古いモデルの商品を発注しようとした場合に、アドバイスする機能を追加する。具体的には、図2のような注文確認画面を設け、担当社員が注文内容を確認するとともに、備考欄のような表示で、新モデルがあることを知らせることができる。
さらに、注文明細一覧の各行末にある“詳細情報”ボタンから、各商品の詳細な情報を照会することができ、新モデルに関する情報もそこから照会できる。

なお、注文内容の確認時点では、まだ注文が確定していないので、確定した注文との区別がつくように、注文エンティティに属性“仮登録フラグ”を追加する。このフラグが“1”の場合は確認中の注文、“0”の場合は確定した注文と定義する。
新システムのE-R図を図3に示す。図3中のa~cには、図1中のa~cと同一のものが入る。

現行システム及び新システムでは、E-R図のエンティティを表名、属性を列名にして、適切なデータ型で表定義した関係データベースによって、データを管理する。
設問1:
図1中のa〜cに入れる適切な属性名及びエンティティ間の関連を答え、図を完成させよ。図1の凡例に従うこと。属性名は表1又は図1から選び、必要に応じて下線を付けること。
模範解答
a:顧客番号
b:↓
c:販売単価
解説
解答の論理構成
-
注文エンティティに入る [a] を確定
- 問題文は「注文を受けると、在庫数量を確認した上で、注文日、顧客番号、担当社員番号、商品番号と数量及び販売単価を登録する。」と述べています。
- 注文エンティティには注文日と担当社員番号が既に示されているため、残る“顧客を識別する列”が必要です。
- よって [a] は「顧客番号」と分かります。
-
注文と注文明細との関連 [b] を確定
- 上記引用から「商品番号と数量及び販売単価を登録する」作業は品目ごとに繰り返されるため、注文1件に対し注文明細が複数存在します。
- したがって関連は「注文(1)→ 注文明細(多)」で、図中では注文から注文明細へ向かう矢印(下向き)が入ります。
-
注文明細エンティティに入る [c] を確定
- 同じ引用文に「販売単価」を登録すると明記されています。
- 数量は既に存在しているので、不足しているのは「販売単価」です。
以上より、
[a] 顧客番号(下線付き外部キー)、
[b] 注文1‐n注文明細(矢印は注文→注文明細)、
[c] 販売単価
が解答となります。
[a] 顧客番号(下線付き外部キー)、
[b] 注文1‐n注文明細(矢印は注文→注文明細)、
[c] 販売単価
が解答となります。
誤りやすいポイント
- 注文エンティティに「顧客番号」が無いと、顧客と注文のリレーションが列ではなく関連線だけで表現されていると誤解しやすい。
- 注文と注文明細の cardinality を n‐m と考えてしまうミス。数量・単価を持つのは注文明細側なので1‐nである点に注意。
- 「標準単価」と「販売単価」の混同。前者は商品マスタに持つ参考単価、後者は実際の取引単価であり注文明細に格納する。
FAQ
Q: 顧客番号は顧客エンティティの主キーですが、注文エンティティでは外部キーになりますか?
A: はい。顧客エンティティの主キーを参照しているため注文エンティティでは外部キーであり、下線の書式は破線下線になります。
A: はい。顧客エンティティの主キーを参照しているため注文エンティティでは外部キーであり、下線の書式は破線下線になります。
Q: 販売単価は商品エンティティに持たせても良いのでは?
A: 商品ごとに標準単価は存在しますが、注文時には値引きなどで変動するため、トランザクション系の注文明細で保持するのが正しい設計です。
A: 商品ごとに標準単価は存在しますが、注文時には値引きなどで変動するため、トランザクション系の注文明細で保持するのが正しい設計です。
Q: 注文と注文明細の関連線に“多対多”を描くのはなぜ誤りですか?
A: 注文番号と注文明細番号を合成主キーにした注文明細が多側を一意に識別できるため、多対多にはなりません。
A: 注文番号と注文明細番号を合成主キーにした注文明細が多側を一意に識別できるため、多対多にはなりません。
関連キーワード: 外部キー, リレーションシップ, トランザクション設計, 正規化, E-R図
設問2:
本文中の“(1) セット商品の導入”で記述されているセット商品を導入するためには、現行システムの出荷指示機能を修正する必要がある。新システムにおいて、指定された注文番号の出荷指示を出力するSQL文を図4に示す。図4中のd〜fに入れる適切な句又は式を答えよ。ここで、“:注文番号”は、指定された注文番号を格納するホスト変数である。


模範解答
d:SUM(TempTbl.小計)
e:UNION ALL
f:商品.商品番号 = セット商品.セット商品番号
又は
注文明細.商品番号 = セット商品.セット商品番号
解説
解答の論理構成
-
出荷指示書では、単品で注文された商品と“セット商品”に含まれる子商品を合算して数量を出力する必要があります。問題文には
「セット商品も、通常の商品と一緒に商品エンティティに登録する。…セット商品エンティティを追加し、セットに含まれる商品の商品番号とその数量を管理する。」
とあるため、2種類の数量を集計した上で商品番号ごとにまとめる処理が必須です。 -
図4の内側サブクエリは2本の SELECT で構成されています。
・1本目:商品.セットフラグ = '0' ― 通常商品(単品)の数量を取得
・2本目:商品.セットフラグ = '1' ― セット商品を選び、セット商品.数量 * 注文明細.数量 で子商品の数量を求める
両者を1つの仮テーブル TempTbl にまとめるため、[e] には重複排除のない結合句 UNION ALL が最適です。UNION では暗黙の重複チェックが入るため、同一商品が複数行ある場合に性能が低下する恐れがあります。 -
外側クエリでは GROUP BY TempTbl.商品番号 が指定されているので、選択リストの集計列は「商品番号ごとに数量を合計する関数」でなければなりません。したがって [d] には SUM(TempTbl.小計) を置き、列名を省略しないようにします。
-
セット商品の子商品数を計算する2本目の SELECT では、セットそのものを示す セット商品番号 と、注文明細で入力された 商品番号(=セット商品そのもの)が一致しなければなりません。図3のエンティティ定義に
「セット商品(エンティティ)‐ セット商品番号 (PK・FK → 商品.商品番号)」
とあるため、[f] は
商品.商品番号 = セット商品.セット商品番号
(または同義の 注文明細.商品番号 = セット商品.セット商品番号)
となります。
以上より、[d]〜[f] は次のとおりです。
・[d] SUM(TempTbl.小計)
・[e] UNION ALL
・[f] 商品.商品番号 = セット商品.セット商品番号 (又は 注文明細.商品番号 = セット商品.セット商品番号)
・[d] SUM(TempTbl.小計)
・[e] UNION ALL
・[f] 商品.商品番号 = セット商品.セット商品番号 (又は 注文明細.商品番号 = セット商品.セット商品番号)
誤りやすいポイント
- [e] を UNION と書いてしまい、重複排除を行った結果数量が減ってしまう。
- [d] で COUNT や SUM(小計) と書き、エイリアス TempTbl を忘れて構文エラーになる。
- [f] で 子商品番号 を結合キーにしてしまい、セット商品自身が取り込めない。
- 内側2本の SELECT に同じ列名を付け忘れ、外側クエリの GROUP BY で列が一致せずエラーになる。
FAQ
Q: なぜ UNION ALL でなければならないのですか?
A: 数量を扱うため、同一商品が複数行あれば行数ぶん数量を合算する必要があります。UNION だと重複行が除外され、数量が過少計上される恐れがあります。
A: 数量を扱うため、同一商品が複数行あれば行数ぶん数量を合算する必要があります。UNION だと重複行が除外され、数量が過少計上される恐れがあります。
Q: [f] の結合条件は2通り示されていますが、どちらを選ぶべきでしょうか?
A: 両方とも論理的に同じ(商品 と 注文明細 の 商品番号 が同一)なので、SQL の記述スタイルに合わせてどちらを使用しても正しいです。
A: 両方とも論理的に同じ(商品 と 注文明細 の 商品番号 が同一)なので、SQL の記述スタイルに合わせてどちらを使用しても正しいです。
Q: セット商品の子商品を求める式 セット商品.数量 * 注文明細.数量 の意味は?
A: 注文明細には「セット商品を何セット購入したか」の数量が入っています。子商品数は「1セットに含まれる個数」×「セットの購入数」で計算します。
A: 注文明細には「セット商品を何セット購入したか」の数量が入っています。子商品数は「1セットに含まれる個数」×「セットの購入数」で計算します。
関連キーワード: 集計関数, 外部結合, サブクエリ, 正規化
設問3:
図2中の注文明細一覧を出力するために作成した図5のSQL文を実行したところ、同じ注文明細番号の行が複数出力されてしまった。どのような場合にこの問題が発生するのか、25字以内で述べよ。また、その解決策として、(あ)~(う)のいずれかの場所に符句を追加する必要がある。その場所に追加する字句を答えよ。ここで、“:注文番号”は、指定された注文番号を格納するホスト変数である。図5中のcは、図1中のcと同一のものが入る。


模範解答
場合:一つの商品に複数の新モデルが存在する場合
場所:(あ)
字句:DISTINCT
解説
解答の論理構成
- 新機能として「毎年新しいモデル(以下、新モデルという)が出る商品では、その履歴を管理し」と明記されている。履歴は「旧モデル1 → 新モデルA」「旧モデル1 → 新モデルB」のように“一つの旧商品”に対して“複数行”になる場合がある。
- 図5の SQL は
• 注文明細 ←→ 新商品モデル を LEFT OUTER JOIN で結合し
• 旧商品番号=明細の商品番号 という条件だけで行を合わせている。 - 旧商品が複数の新モデルを持つと、同じ注文明細行が新モデルの行数だけ複製される重複結果となり、注文明細番号の重複が発生する。
- 重複排除には、主キー列である「注文明細.注文明細番号」を対象に DISTINCT を付与するのが最もシンプルかつ確実。
- SELECT 句の直後((あ)の位置)に DISTINCT を追加すれば、同一注文明細番号を1行に統合できる。
誤りやすいポイント
- 「GROUP BY でまとめる」と短絡し、集計列の追加や演算列修正の手間を見落とす。
- WHERE 新商品モデル.新商品番号 IS NULL と条件を変えて外れ値だけを除こうとして、必要な新モデル情報まで欠落させる。
- LEFT OUTER JOIN を INNER JOIN に変えてしまい、新モデルを持たない旧商品が表示されなくなる。
FAQ
Q: DISTINCT ではなく GROUP BY 注文明細.注文明細番号 でも良いですか?
A: 集計関数を全列に適用するか、列数を絞る追加作業が必要になるため、出力仕様が変わるリスクがあります。問題の意図は重複排除のみなので DISTINCT が最適です。
A: 集計関数を全列に適用するか、列数を絞る追加作業が必要になるため、出力仕様が変わるリスクがあります。問題の意図は重複排除のみなので DISTINCT が最適です。
Q: 新モデルが無い商品はどう扱われますか?
A: LEFT OUTER JOIN を用いているので、新モデルが存在しない場合でも行は欠落せず、備考欄は空文字となります。
A: LEFT OUTER JOIN を用いているので、新モデルが存在しない場合でも行は欠落せず、備考欄は空文字となります。
Q: インデックスの追加でパフォーマンス改善は必要ですか?
A: 本問は重複行排除がテーマです。パフォーマンス調整は別途、旧商品番号 列へのインデックスなど運用設計フェーズで検討します。
A: 本問は重複行排除がテーマです。パフォーマンス調整は別途、旧商品番号 列へのインデックスなど運用設計フェーズで検討します。
関連キーワード: 外部結合, 重複行, DISTINCT, 主キー, データ正規化


