応用情報技術者 2010年 秋期 午後 問06
販売管理システムに関する次の記述を読んで、設問1~4に答えよ。
L社は、焼酎を製造販売する酒造会社である。L社では顧客である小売店との取引管理に販売管理システム(以下、本システムという)を利用している。
〔請求締め業務〕
請求額は、前月度の請求額、今月度(前月21日から今月20日まで)の入金額及び今月度の買上額を基に算出する。請求額がマイナスの場合は、預り金が発生していることを示す。本システムによる請求書発行処理は毎月25日20時に実行され、顧客ごとに請求書が発行される。請求書の例を図1に示す。


〔入金消込み業務〕
担当者は顧客からの入金を確認する都度、本システムによって、支払がされていない請求にこの入金を割り当てて入金消込み処理を行う。
本システムでは、1回の請求に対して複数回に分けて入金することが可能であり、複数の請求に対する支払を1回の入金で行うことも可能である。入金で余りが発生した場合は、次回の請求締め業務で精算する。また、入金は本システムが付与する入金番号によって一意に特定できる。
〔本システムのE-R図〕
本システムのE-R図を図2に示す。請求レコードは、請求締め業務の中で作成される。“請求”エンティティの“消込額”は、ある請求に対して、入金によって消し込まれた総額である。また、“入金”エンティティの“消込額”は、ある入金に対して請求への消込みに充てた総額である。
本システムでは、E-R図のエンティティ名を表名、属性名を列名にして、適切なデータ型で表定義した関係データベースによって、データを管理する。例として、請求テーブルを作成するCREATE文を図3に示す。
〔入金消込み処理〕
本システムの入金消込み処理では、1回の入金に対して、図4の流れ図に従い、古い請求から順に消込みを行う。請求への消込みは、入金額が請求への消込みにすべて充てられるか、又は、支払が残っている請求がなくなるまで繰り返す。
設問1:
問題文を見る模範解答
a:←
b:←
c:顧客番号
d:請求書番号
解説
解答の導き方
結論(先に示す)
[a]:←
[b]:←
[c]:顧客番号(顧客の主キー → 図では実線下線)
[d]:請求書番号(請求の主キーだが、入金消込側では請求を参照する外部キー → 図では破線下線)
[a]:←
[b]:←
[c]:顧客番号(顧客の主キー → 図では実線下線)
[d]:請求書番号(請求の主キーだが、入金消込側では請求を参照する外部キー → 図では破線下線)
以下、図中の記述を根拠に段階的に導きます。
- [c] の決定(顧客番号)
- 図3のCREATE文に「FOREIGN KEY ( 顧客番号 ) REFERENCES 顧客 ( [ c ] )」とあるため、請求テーブルの顧客番号が顧客テーブルのどの属性を参照するかを問うていることが分かります。
- 図2の顧客エンティティには「顧客番号(主キー、実線下線)」があるので、参照先の属性 [c] は「顧客番号」です。
- したがって [c] = 顧客番号。顧客側では主キー(実線下線)として表し、参照している側(例:入金や請求)では外部キー(破線下線)として扱います。
- [d] の決定(請求書番号)
- 図4の処理に「pay.消込額 ← y, pay.入金番号 ← credit.入金番号, pay.[d] ← bill.請求書番号(1)」とあるため、入金消込テーブルの属性 [d] が請求の請求書番号を受け取ることが明示されています。
- 図2の請求エンティティには「請求書番号(主キー、実線下線)」があるため、入金消込の [d] は請求の主キーである「請求書番号」を参照する外部キーです。
- したがって [d] = 請求書番号。請求エンティティ側では主キー(実線下線)、入金消込エンティティ側では外部キー(破線下線)として表します。
- [a] の決定(売上明細と商品間の関係向き)
- 図2に「売上明細 … 商品番号(外部キー、破線下線)」とあり、同じく「商品 … 商品番号(主キー、実線下線)」と示されています。
- 外部キーが売上明細側にあることは「1つの商品に対して複数の売上明細がある(商品:1、売上明細:多)」を意味します。
- E-R図で「売上明細 ――→ 商品」となっている箇所は、向きが逆であるため修正が必要です。正しくは商品から売上明細へ向かう矢印、つまり図中の空欄 [a] に「←」を入れて「売上明細 ← 商品」と表します。
- よって [a] = ←(商品が1、売上明細が多であることを表す向き)。
- [b] の決定(請求と顧客の関係向き)
- 図2の請求エンティティに「顧客番号(外部キー、破線下線)」があることから、請求は顧客を参照しています。外部キーが請求側にあるということは「1人の顧客に対して複数の請求がある(顧客:1、請求:多)」です。
- E-R図の表記「請求 ――←― [ b ] ―→ 顧客」は、中央の記号に適切な向きを入れて「顧客 ――→ 請求」を表す必要があります。問題の表記に合わせると [b] に「←」を入れることで、左側(請求)は多、右側(顧客)は1を示します。
- よって [b] = ←(顧客が1、請求が多であることを表す向き)。
以上により、図2・図4中の空欄は結論の通りになります。
誤りやすいポイント
- 矢印の向きを逆にする(どちらが1でどちらが多かは「どちらに外部キーがあるか」で判定する)。
- 外部キー=参照先の主キーであることを見落とし、[c]や[d]を誤答する。図3のFOREIGN KEY句と図4の代入文は必ず確認すること。
- [d]を入金消込の主キーだと誤解する(入金消込の[d]は外部キー。入金消込の一意性は別に定義する)。
- 「関係名」と「矢印の向き」を取り違える(今回の[a],[b]は向き=1対多の向きを問う箇所)。
FAQ
Q: なぜ矢印の向きは外部キーのある側が「多」になるのですか?
A: 関係をリレーショナルに実装するとき、外部キーを持つ側の各レコードが参照先の1レコードに紐づくため外部キーを持つ側が「多」になります。例えば請求テーブルに顧客番号(外部キー)があると「1顧客:多請求」です。
A: 関係をリレーショナルに実装するとき、外部キーを持つ側の各レコードが参照先の1レコードに紐づくため外部キーを持つ側が「多」になります。例えば請求テーブルに顧客番号(外部キー)があると「1顧客:多請求」です。
Q: [d] は入金消込の主キーになりますか?
A: 図では入金消込の[d]は破線下線で外部キーを示しています。入金消込テーブルの一意性(主キー)を設計するなら、入金番号と請求書番号の複合主キーなどを用いることが考えられますが、図示されている [d] 自体は請求の主キーを参照する外部キーです。
A: 図では入金消込の[d]は破線下線で外部キーを示しています。入金消込テーブルの一意性(主キー)を設計するなら、入金番号と請求書番号の複合主キーなどを用いることが考えられますが、図示されている [d] 自体は請求の主キーを参照する外部キーです。
Q: E-R図の記号(実線下線/破線下線)はどこに引くべきですか?
A: エンティティでの主キーは実線下線、外部キーは破線下線で表示します。今回、顧客側の顧客番号は主キー(実線下線)、請求側の顧客番号は外部キー(破線下線)、請求の請求書番号は主キー(実線下線)、入金消込側の該当列は外部キー(破線下線)です。
A: エンティティでの主キーは実線下線、外部キーは破線下線で表示します。今回、顧客側の顧客番号は主キー(実線下線)、請求側の顧客番号は外部キー(破線下線)、請求の請求書番号は主キー(実線下線)、入金消込側の該当列は外部キー(破線下線)です。
関連キーワード: E-R図、主キー、外部キー、1対多、参照整合性
設問2:
問題文を見る模範解答
e:請求書番号
f:PRIMARY KEY
g:顧客番号
解説
解答の導き方
-
e(CREATE文の最初の欄名)について
図3の該当行は "e CHAR(5)," の形で列名を定義する場所です。図2の請求エンティティには「請求書番号(主キー、実線下線)」と示されています。したがって列名として入るべきは請求エンティティの主キーである「請求書番号」です。
結論:e = 請求書番号 -
f(CREATE文中の制約指定)について
図3では次の行が "f ( e )," となっており、これはテーブルレベルで主キーなどの制約を定義する文法です。図2で「請求書番号」が主キーであることが明示されているので、この位置には主キーを宣言するキーワード「PRIMARY KEY」が入ります。これにより "PRIMARY KEY ( 請求書番号 )" という形になります。
結論:f = PRIMARY KEY -
g(FOREIGN KEY の参照列)について
図3の最後の行は "FOREIGN KEY ( 顧客番号 ) REFERENCES 顧客 ( g )" となっており、参照先テーブル顧客のどの列を参照するかを指定する箇所です。図2の顧客エンティティには「顧客番号(主キー、実線下線)」とあるため、参照すべき列は「顧客番号」です。
結論:g = 顧客番号
完成形(該当箇所を埋めたCREATE文の該当部分)は次のようになります。
CREATE TABLE 請求
(
請求書番号 CHAR(5), 顧客番号 CHAR(5), 請求日 CHAR(8), 計上年月 CHAR(6), 請求額 NUMERIC(10), 買上額 NUMERIC(10), 消込額 NUMERIC(10), PRIMARY KEY ( 請求書番号 ), FOREIGN KEY ( 顧客番号 ) REFERENCES 顧客 ( 顧客番号 )
)
CREATE TABLE 請求
(
請求書番号 CHAR(5), 顧客番号 CHAR(5), 請求日 CHAR(8), 計上年月 CHAR(6), 請求額 NUMERIC(10), 買上額 NUMERIC(10), 消込額 NUMERIC(10), PRIMARY KEY ( 請求書番号 ), FOREIGN KEY ( 顧客番号 ) REFERENCES 顧客 ( 顧客番号 )
)
最終的な解答
e:請求書番号
f:PRIMARY KEY
g:顧客番号
e:請求書番号
f:PRIMARY KEY
g:顧客番号
誤りやすいポイント
-
請求書番号と顧客番号を取り違える
図2の請求エンティティには両方並んでいるため、「どちらが主キーか」を下線や(主キー)の表示で確実に確認してください。主キーは「請求書番号」です。 -
PRIMARY KEY の書き方を混同する
SQLでは列定義内に「請求書番号 CHAR(5) PRIMARY KEY」と書く方法とテーブル末尾で「PRIMARY KEY ( 請求書番号 )」と書く方法が両方あります。図3のテンプレートはテーブルレベルの制約を書かせる形なので、その形式で埋めるのが期待解答となります。 -
REFERENCES の参照列名を省略してしまう
「FOREIGN KEY ( 顧客番号 ) REFERENCES 顧客」と列名を省略する記述を許すDB実装はありますが、出題者の期待や移植性を考えると "REFERENCES 顧客 ( 顧客番号 )" と参照列を明示するのが無難です。 -
カンマや括弧の位置を誤ると文法エラーになる
CREATE文では行末のカンマや括弧の対応を間違いやすいので、1行ずつ構文が閉じているか確認してください。
FAQ
Q: REFERENCES 顧客 のように参照先列を省略してもよいですか?
A: 実装によっては省略を受け付け、参照先テーブルの主キーを暗黙に参照する場合があります。ただし試験問題や移植性の観点からは REFERENCES 顧客 ( 顧客番号 ) と参照列を明示するのが安全です。
A: 実装によっては省略を受け付け、参照先テーブルの主キーを暗黙に参照する場合があります。ただし試験問題や移植性の観点からは REFERENCES 顧客 ( 顧客番号 ) と参照列を明示するのが安全です。
Q: PRIMARY KEY を列定義として書く(請求書番号 CHAR(5) PRIMARY KEY)とダメですか?
A: 文法上は有効で、等価な意味になります。しかし図3のテンプレートはテーブルレベルの制約を書かせる形式のため、設問の空欄にはテーブルレベルのキーワード(PRIMARY KEY)を入れるのが期待答です。
A: 文法上は有効で、等価な意味になります。しかし図3のテンプレートはテーブルレベルの制約を書かせる形式のため、設問の空欄にはテーブルレベルのキーワード(PRIMARY KEY)を入れるのが期待答です。
Q: UNIQUE と PRIMARY KEY は置き換えられますか?
A: UNIQUE は一意性を保証しますが、PRIMARY KEY は一意性に加え主キーという論理表現(NULL不可を含むことが一般的)を示します。図2で「主キー」と明示されている場合は PRIMARY KEY を使ってください。
A: UNIQUE は一意性を保証しますが、PRIMARY KEY は一意性に加え主キーという論理表現(NULL不可を含むことが一般的)を示します。図2で「主キー」と明示されている場合は PRIMARY KEY を使ってください。
関連キーワード: E-R図、主キー、外部キー、CREATE TABLE、テーブル制約
設問3:
問題文を見る模範解答
h:bill.消込額+x
i:credit.入金額
解説
解答の導き方
-
前提の確認(図4の定義・処理)
- 図4の注に「xは入金の消込可能な残額を示す」、「yは請求の消し込まれていない残額を示す」とあるので、 はその時点で入金からまだ割り当てられていない残額、 は当該請求に対してまだ支払われていない残額であることが分かります。
- 図4の処理5に「y ← bill.買上額 – bill.消込額」とあるので、 は該当請求の「買上額」からこれまでに消込まれた合計を差し引いた額であることが明確です。
-
条件分岐の意味(x > yの場合とそうでない場合)
- 左分岐(x > yのとき)は入金の残額 がその請求の未消込額 を超えているので、その請求を全額消し込む処理を行います(bill.消込額 をbill.買上額 にする、credit.消込額 にyを加える、xをx - yにする、等)。
- 右分岐(x > y が成り立たない、すなわち )は入金の残額 がその請求の未消込額 以下であり、入金が尽きる(その入金分だけを当該請求に充てる)処理を行います。図4の右分岐の最後で「pay.消込額 ← x」として入金消込テーブルに割当額が記録される点に注目します。
-
右分岐(部分消込)の各代入が表す意味と式の導出
- 当該請求に今回割り当てる金額は明示的に「pay.消込額 ← x」としているため、請求側の消込合計も今回の割当分だけ増える必要があります。したがって請求テーブルの消込額は既存の値に今回の割当額 を加える操作であり、 h = bill.消込額 + xが正しいことになります。
- 入金側(credit.消込額)は「入金に対して請求へ消し込んだ総額」を保持する属性です。ループのこれまでの繰返しで既に加算された金額の合計を とすると、入金の総額はcredit.入金額 であり、残額は です。部分消込で残額 を全て使うと、入金に対して消し込んだ総額は になります。したがって入金テーブル側は入金が尽きたことを明示する式として i = credit.入金額 を代入するのが自然で簡潔です。
- 補足(等価性の説明):同じ結果を得る式として credit.消込額 ← credit.消込額 + x も成り立ちます。なぜならループ前の credit.消込額 を とすれば だからです。両者は等価であり、どちらを用いても最終値は一致します。
-
結論(設問の答え)
- h:bill.消込額+x
- i:credit.入金額
誤りやすいポイント
-
bill.消込額 ← x としてしまう誤り
既存の消込合計を上書きしてしまい、これまでの消込分を失うため誤りです。部分消込では既存値に今回割当額を加える必要があります。 -
bill.消込額 ← bill.買上額 としてしまう誤り
これはその請求を全額消し込む操作であり、(部分消込)の場合は不適切です。等号の場合()は結果的に同じになりますが、条件分岐の意図を踏まえると一般にbill.消込額 + xが正しい処理です。 -
credit.消込額 の扱いに関する誤解
「credit.消込額 ← credit.消込額 + x とすると二重計上になる」と誤認する受験者がいますが、既に加算済みの値を とすると は入金総額 credit.入金額 と一致します。よって credit.消込額 ← credit.消込額 + x も正しく、credit.消込額 ← credit.入金額 と等価です。どちらを使うかは実装上の書き方の違いにすぎません。 -
請求の残額を求める際に属性を取り違える誤り
図4は明確にyをbill.買上額 – bill.消込額 と定義しています。請求テーブルに請求額と買上額の両方が存在する点に惑わされ、誤って別の属性を使うと計算が狂います。 -
条件の等号処理(x = y)への理解不足
図4は判定を「x > y」としているため、等号は右分岐(部分消込側)に入ります。等号の扱いを誤るとループの分岐や更新順序に齟齬が生じるので注意してください(ただし更新の中身が等価なら結果は同じです)。
FAQ
Q: 右分岐でbill.消込額 にbill.買上額 を代入しても問題ないですか?
A: 一般には問題です。bill.買上額 を代入するとその請求が全額消込済みと扱われますが、右分岐は入金が尽きる()ケースで、 のときは請求は未だ残高があるため誤りになります。 の特殊ケースでは結果は同一になりますが、汎用的にはbill.消込額 + xを用いて部分加算する方が正しいです。
A: 一般には問題です。bill.買上額 を代入するとその請求が全額消込済みと扱われますが、右分岐は入金が尽きる()ケースで、 のときは請求は未だ残高があるため誤りになります。 の特殊ケースでは結果は同一になりますが、汎用的にはbill.消込額 + xを用いて部分加算する方が正しいです。
Q: credit.消込額 ← credit.入金額 の代わりに credit.消込額 ← credit.消込額 + x を書いてはいけませんか?
A: 書いて問題ありません。ループ前のcredit.消込額 を とすれば であり、 となるため両者は等価です。前者は「入金を使い切った」ことを明示的に示す書き方、後者は「これまでの合計に今回の割当を加える」書き方です。
A: 書いて問題ありません。ループ前のcredit.消込額 を とすれば であり、 となるため両者は等価です。前者は「入金を使い切った」ことを明示的に示す書き方、後者は「これまでの合計に今回の割当を加える」書き方です。
Q: 判定を「x >= y」に変えてもよいですか?
A: 判定を変えると分岐の実行側が変わりますが、左右の更新処理を適切に調整すれば結果は同じになります。ただし設問の図は「x > y」と定めているので、試験問題に答える際は図の条件に従い、その条件下で適切な更新式を示すべきです。
A: 判定を変えると分岐の実行側が変わりますが、左右の更新処理を適切に調整すれば結果は同じになります。ただし設問の図は「x > y」と定めているので、試験問題に答える際は図の条件に従い、その条件下で適切な更新式を示すべきです。
関連キーワード: 関係データベース、E-R図、トランザクション、更新処理、整合性制約
設問4:
問題文を見る今月度の請求締め業務が終了すると、顧客の中には預り金が発生している場合がある。今月度の末日時点で預り金の発生している顧客の顧客番号と預り金額の一覧を求めるためのSQL文を図5に示す。図5中のj〜lに入れる適切な字句を答え、SELECT文を完成させよ(kとlは順不同)。
なお、ホスト変数として“:今月度末日”が定義されているものとする。


模範解答
j:SUM(入金額-消込額)
k:入金日 <= :今月度末日
l:入金額 > 消込額
解説
解答の論理構成
-
預り金とは
- 【問題文】では「請求額がマイナスの場合は、預り金が発生していることを示す」と説明しています。マイナスになる原因は、入金額がまだ請求へ全額消し込まれていない“余り”があるためです。
- “余り”は【問題文】の“入金”エンティティにある「入金額」と「消込額」の差で表現されます。
-
不要消込額の算出式
- 1レコード当たりの預り金額=「入金額−消込額」。
- これを顧客単位で集計するため、SELECT 句には「SUM(入金額-消込額)」を置きます。
- これが図5の j に該当します。
-
対象期間の限定
- 今月度の末日時点での残高を求めるので、日付条件が必要です。
- ホスト変数「:今月度末日」が示す日付までに登録された入金だけを集計するため、WHERE 句に「入金日 <= :今月度末日」を入れます。
- これが図5の k または l のいずれかになります。
-
余りが存在するレコードの限定
- まだ預り金として残っている入金だけを対象にするには「入金額 > 消込額」でフィルタリングします。
- これが残る1つの WHERE 条件にあたり、図5の k または l となります。
-
GROUP BY
- 集計単位は顧客番号ごと。既に「GROUP BY 顧客番号」が記載されているため、SELECT 句と整合が取れます。
-
まとめ
- 上記を反映すると、図5の空欄は次のように埋まります。
sql
SELECT 顧客番号,
SUM(入金額-消込額)
FROM 入金
WHERE 入金日 <= :今月度末日
AND 入金額 > 消込額
GROUP BY 顧客番号;
誤りやすいポイント
- 「SUM(入金額-消込額)」ではなく「SUM(入金額) - SUM(消込額)」と書く
→ 数式自体は正しくても、GROUP BY との組合せで NULL を生みにくくシンプルな前者が典型解です。 - 日付条件を「< :今月度末日」や「BETWEEN」で書き、末日を含めない
→ 問題文は「今月度の末日時点」と明記しているため“=”を含める必要があります。 - 「入金額 >= 消込額」としてしまう
→ 入金額と消込額が完全に一致しているレコード(差額0円)は預り金ではありません。
FAQ
Q: 「消込額」は請求テーブルにもありますが、なぜ入金テーブルだけを参照するのですか?
A: 預り金の源泉は“入金の余り”なので、「入金額−消込額」が正しく残高を示せます。請求側の「消込額」は支払済み総額を示すもので、本問の趣旨と異なります。
A: 預り金の源泉は“入金の余り”なので、「入金額−消込額」が正しく残高を示せます。請求側の「消込額」は支払済み総額を示すもので、本問の趣旨と異なります。
Q: SUM の中で差を取るとパフォーマンスが悪化しませんか?
A: 差分計算は行単位で実行されます。適切にインデックスを張れば集約処理のオーバーヘッドはごく小さく、式展開より可読性重視で問題ありません。
A: 差分計算は行単位で実行されます。適切にインデックスを張れば集約処理のオーバーヘッドはごく小さく、式展開より可読性重視で問題ありません。
Q: 日付の比較に文字列型 CHAR(8) を使うのは安全ですか?
A: 西暦表記のYYYYMMDD形式なら、文字列比較でも日付順と辞書順が一致します。内部を DATE 型に変更すればさらに安全ですが、本試験では定義どおり CHAR(8) を前提にしています。
A: 西暦表記のYYYYMMDD形式なら、文字列比較でも日付順と辞書順が一致します。内部を DATE 型に変更すればさらに安全ですが、本試験では定義どおり CHAR(8) を前提にしています。
関連キーワード: 集約関数、外部キー、消込処理、残高計算、条件抽出







