応用情報技術者 2011年 秋期 午後 問06
旅費交通費精算のシステム化に関する次の記述を読んで、設問1~4に答えよ。
K社は中堅の食品製造会社で、ここ数年急速に売上を伸ばしている。販売力強化のために営業社員も増員を続けているので、伝票によって手作業で行っている旅費交通費の精算処理をシステム化することにした。
システムの設計に当たり、図1に示す現行の申請書を参考にした。


〔旅費交通費精算に関する規定〕
K社における旅費交通費精算に関する規定の一部を次に示す。
・交通費及びホテルの費用は実費で請求する。
・タクシー、航空機及びホテルの費用の精算の際は、申請書に合わせて証憑を提出する。証憑とは、領収書や搭乗券など実際に利用したことを証明するものである。
・出張時は、出発日から帰着日までの各日に日当がつく。日当は、出張時の職位によって表1に従い請求する。
・旅費交通費の申請は、申請時の組織名で行う。
・旅費交通費の申請は、費用の発生日から1か月以内に行う。

〔旅費交通費精算システムのデータベース設計〕
設計中のE-R図を図2に、テーブル構造を表2に示す。データベース設計に関する仕様の一部を次に示す。
・申請書テーブルや申請明細テーブルにおける申請書番号は、申請書ごとに付与される一意の番号である。
・申請明細テーブルの明細行番号は、申請書内の明細順に振られる番号である。
・費用種別テーブルの内容を表3に示す。証憑フラグは、証憑を必要とする場合は‘Y’、不要な場合は‘N’である。
・組織の追加や名称の変更があった場合は、新たに組織コードを割り当てて組織テーブルに追加する。

〔証憑提出用の台紙の印刷〕
証憑を提出する際は、システムから台紙を印刷し、それに証憑を貼り付けて提出する。台紙には、申請書番号、組織名、氏名の他に、証憑を必要とする明細行番号、日付、費用種別名及び金額を印字する。
指定された申請書番号から、証憑を必要とする明細行を取り出すSQL文を図3に示す。ここで、図3のSQL文において“:申請書番号”は対象となる申請書番号を表す埋込み変数である。
〔組織ごとの旅費交通費集計〕
各組織における1か月間の旅費交通費の合計を集計しレポートを出力する。集計は、社員が申請時に所属していた組織を基準にして行う。レポートには、組織コード、組織名及びその月の旅費交通費(日当を含む)の合計を印字する。組織ごとのレポートに必要なデータを取り出すSQL文を図4に示す。ここで、図4のSQL文において“:指定月開始日”、“:指定月終了日”は、それぞれレポートの出力対象となる年月の開始日、終了日を表す埋込み変数である。レポートは組織コードの昇順に出力する。
模範解答
a:→
b:←
解説
解答の論理構成
-
関係を判断する手掛かり
- 問題文には「申請書テーブルや申請明細テーブルにおける申請書番号は、申請書ごとに付与される一意の番号である。」とあります。
- さらに「申請明細テーブルの明細行番号は、申請書内の明細順に振られる番号である。」とも明記されています。
- これらの記述から、1つの申請書に対して複数の申請明細がひも付く ― すなわち “1対多” であることが分かります。
-
図2の凡例の確認
- 問題文中の凡例では「→ : 1対多」と定義されています。
- よって、申請書(1) から 申請明細(多) への矢印は「→」になります。
- したがって a には「→」が入ります。
-
もう一つの関係の検討
- 申請明細には「費用種別コード」が格納されていますが、費用種別側には申請明細を特定する列は存在しません。
- この仕様は「1つの費用種別が多くの申請明細に使われ得る」関係、すなわち 費用種別(1) ↔ 申請明細(多) です。
- 矢印の方向は “1” 側から “多” 側へ向くため、費用種別 から 申請明細 へ「←」が入ります(申請明細が左、費用種別が右に配置されているため)。
- よって b には「←」が入ります。
-
結論
- a = →
- b = ←
誤りやすいポイント
- 矢印の 向き を逆にしてしまう
「1対多」の “多” 側に矢印が向くと覚えておくと混乱を防げます。 - 申請明細 と 費用種別 を 多対多 と誤認する
外部キー「費用種別コード」が 申請明細 側にあるため多対1関係です。 - 凡例の「─ : 1対1」を見落とし、すべてを矢印に置き換えてしまう
FAQ
Q: 申請書と社員の関係は図に描かれていないのですか?
A: 描かれています。問題文中では「組織→社員─職位」の右側にあり、社員コード が 申請書 に格納されることで1対多が表現されています。
A: 描かれています。問題文中では「組織→社員─職位」の右側にあり、社員コード が 申請書 に格納されることで1対多が表現されています。
Q: 「費用種別コード」が 申請明細 にあるのに、多対1ではなく1対多と説明するのはなぜ?
A: 関係の呼び方は “どちらを基準に見るか” で変わります。本問は 費用種別 を “1” 側、申請明細 を “多” 側として説明しています。
A: 関係の呼び方は “どちらを基準に見るか” で変わります。本問は 費用種別 を “1” 側、申請明細 を “多” 側として説明しています。
Q: 多対多(↔)はどこで必要になりますか?
A: 本問の設計では必要ありません。外部キーで直接参照しているため、仲介テーブルを用いる多対多は登場しません。
A: 本問の設計では必要ありません。外部キーで直接参照しているため、仲介テーブルを用いる多対多は登場しません。
関連キーワード: エンティティリレーションシップ、多重度、外部キー、正規化、データモデリング
(2)表2中の申請明細テーブルの主キーとなる列を全て答えよ。
模範解答
申請書番号、明細行番号
解説
解答の論理構成
- 主キーは「行を一意に識別できる列(または列の組合せ)」です。
- 【問題文】には、主キー候補の列について次の二つの制約が示されています。
- 「申請書テーブルや申請明細テーブルにおける申請書番号は、申請書ごとに付与される一意の番号である。」
- 「申請明細テーブルの明細行番号は、申請書内の明細順に振られる番号である。」
- 二つ目の制約より、明細行番号は同一の申請書番号内でのみ一意であり、別の申請書番号では重複し得ます。したがって、明細行番号単独ではテーブル全体を一意にできません。
- 一方、申請書番号は申請書単位で一意ですが、申請書内の行を区別できません。
- したがって、テーブル全体で重複が生じない最小の組合せは
「申請書番号」+「明細行番号」
となります。
誤りやすいポイント
- 「申請書番号は一意だから主キーはこれだけ」と早合点し、行番号の重複可能性を見落とす。
- 「明細行番号が連番だから一意」と考え、申請書番号のスコープを意識しない。
- 主キー列数を最小化しようとし過ぎて、複合キーが必要なケースを除外する。
FAQ
Q: 申請明細テーブルにサロゲートキー(例えばシステム採番のID)を追加してはいけないのですか?
A: 設計方針としてサロゲートキーを採用することは可能ですが、本問は「表2中の列のみで主キーを構成せよ」という前提です。したがって既存列の組合せを答えます。
A: 設計方針としてサロゲートキーを採用することは可能ですが、本問は「表2中の列のみで主キーを構成せよ」という前提です。したがって既存列の組合せを答えます。
Q: 「日付」や「費用種別コード」を主キーに含めても問題はありますか?
A: これらは重複を許す列で、行の一意性に寄与しません。最小限の列で一意になれば十分なので、含める必要も妥当性もありません。
A: これらは重複を許す列で、行の一意性に寄与しません。最小限の列で一意になれば十分なので、含める必要も妥当性もありません。
Q: 明細行番号を全申請書で一意にする方がシンプルでは?
A: 可能ですが、その場合は採番ロジックや整合性維持のコストが増します。業務上「申請書内で通し番号」が自然なケースでは、複合キーで管理する方が保守しやすい設計になります。
A: 可能ですが、その場合は採番ロジックや整合性維持のコストが増します。業務上「申請書内で通し番号」が自然なケースでは、複合キーで管理する方が保守しやすい設計になります。
関連キーワード: 主キー、複合キー、一意性制約、テーブル設計、E-R図
設問2:
問題文を見る模範解答
c:申請明細.費用種別コード = 費用種別.費用種別コード
d:費用種別.証憑フラグ = 'Y'
解説
解答の論理構成
-
結合対象の特定
- 台紙には「費用種別名」を印字します。費用種別名は表2で“費用種別”テーブルにあるので、SQLでは“申請明細”と“費用種別”を結合する必要があります。
- 両テーブルに共通して存在する主キーは【表2】の「費用種別コード」です。
以上より、ON 句には
申請明細.費用種別コード = 費用種別.費用種別コード
が入ります。これが c の解答です。
-
証憑が必要な明細の抽出
- 規定より「タクシー、航空機及びホテルの費用の精算の際は、申請書に合わせて証憑を提出する。」とあります。
- さらに仕様では「証憑フラグは、証憑を必要とする場合は‘Y’、不要な場合は‘N’である。」と明言されています。
- 台紙には「証憑を必要とする明細行」を印字するので、WHERE 句で“証憑フラグ”が‘Y’の行だけを残す必要があります。
よって d には
費用種別.証憑フラグ = 'Y'
が入ります。
-
申請書番号による限定
- 図3のSQLは「指定された申請書番号から」対象行を取得するものです。
- その条件は既に 申請明細.申請書番号 = :申請書番号 と書かれており、d とは独立しています。
したがって最終的な WHERE 句は
sql WHERE 申請明細.申請書番号 = :申請書番号 AND 費用種別.証憑フラグ = 'Y'
となり、証憑が必要な行のみが抽出できます。
誤りやすいポイント
- 結合条件を 費用種別名 で書いてしまう
→ 値は重複する可能性があるため不正確です。 - テーブル名を省略して 費用種別コード = 費用種別コード と記述
→ 問題指示で「テーブル名を省略せずに」とあります。 - 証憑フラグの判定を 'Y' = 費用種別.証憑フラグ のように左右を逆に書く
→ 可読性・記述統一の観点で減点対象になりやすいです。 - IN ('Y') や <> 'N' を使う
→ 解答欄は字句を問うので、シンプルな = 'Y' が模範解となります。
FAQ
Q: INNER JOIN を使う理由は何ですか?
A: 台紙に印字しない行を除外するのは WHERE 句で行い、費用種別名を取得する目的で結合します。外部結合は不要なので INNER JOIN が最適です。
A: 台紙に印字しない行を除外するのは WHERE 句で行い、費用種別名を取得する目的で結合します。外部結合は不要なので INNER JOIN が最適です。
Q: 費用種別.証憑フラグ ではなく 申請明細.証憑フラグ としては駄目ですか?
A: 申請明細テーブルには証憑フラグが存在しません。フラグ情報は費用種別テーブルに一元管理されているため、必ず 費用種別 テーブルを参照します。
A: 申請明細テーブルには証憑フラグが存在しません。フラグ情報は費用種別テーブルに一元管理されているため、必ず 費用種別 テーブルを参照します。
Q: フラグが 'Y' だけなら = 'Y' と IN ('Y') に違いはありますか?
A: 機能面の差はほぼありませんが、設問は「字句」を問うため、冗長な書き方は避け模範解答通りに書く方が安全です。
A: 機能面の差はほぼありませんが、設問は「字句」を問うため、冗長な書き方は避け模範解答通りに書く方が安全です。
関連キーワード: INNER JOIN, 結合条件、フラグ設計、WHERE句、データ抽出
設問3:
問題文を見る模範解答
e:SUM
f:BETWEEN
g:ORDER BY 申請書.組織コード
解説
解答の導き方
-
e(SELECT の集計関数)について
図4のSELECT句は「SELECT 申請書.組織コード,組織.組織名, [ e ](申請明細.金額) AS 組織交通費合計」となっています。また本文に「レポートには、組織コード、組織名及びその月の旅費交通費(日当を含む)の合計を印字する。」とあるため、明細の金額を組織ごとに合計する必要があります。合計を出すにはSQLの集計関数SUMを使うので、完全な式は SUM(申請明細.金額) となり、空欄には SUM が入ります。 -
f(WHERE の日付範囲指定)について
図4のWHERE句は「申請明細.日付 [ f ] :指定月開始日 AND :指定月終了日」となっています。ここは「指定月の開始日から終了日まで」を対象にするため、開始日と終了日の間を指定するBETWEEN句が適切です(BETWEEN は両端を含む)。書き換えると「申請明細.日付 BETWEEN :指定月開始日 AND :指定月終了日」となります。等価な表現として「申請明細.日付 >= :指定月開始日 AND 申請明細.日付 <= :指定月終了日」も可能です。 -
g(出力順序指定)について
図4の末尾は「GROUP BY 申請書.組織コード,組織.組織名 [ g ]」です。本文に「レポートは組織コードの昇順に出力する。」とあるので、出力順序指定は ORDER BY 申請書.組織コード とします。補足として、今回のFROM句とJOIN条件(申請書.組織コード = 組織.組織コード)により 申請書.組織コード と 組織.組織コード は同一の値になるため、SQLとしては ORDER BY 組織.組織コード と書いても動作します。しかし、GROUP BY に書かれている表記と一致させ、かつ問題の指示どおり列名をテーブル名付きで明示するために ORDER BY 申請書.組織コード を用いるのが適切です。
最終的に図4中の空欄は次のとおりです。
e:SUM
f:BETWEEN
g:ORDER BY 申請書.組織コード
e:SUM
f:BETWEEN
g:ORDER BY 申請書.組織コード
(完成例SQLの該当部分)
SELECT 申請書.組織コード, 組織.組織名, SUM(申請明細.金額) AS 組織交通費合計
...
WHERE 申請明細.日付 BETWEEN :指定月開始日 AND :指定月終了日
...
GROUP BY 申請書.組織コード, 組織.組織名
ORDER BY 申請書.組織コード
SELECT 申請書.組織コード, 組織.組織名, SUM(申請明細.金額) AS 組織交通費合計
...
WHERE 申請明細.日付 BETWEEN :指定月開始日 AND :指定月終了日
...
GROUP BY 申請書.組織コード, 組織.組織名
ORDER BY 申請書.組織コード
誤りやすいポイント
- 集計関数を忘れる/誤った関数を使う:合計を求めるところでCOUNTやMAXを入れてしまうミス。ここではSUMが正しい。
- GROUP BY の扱い:SELECTにある非集計列(申請書.組織コード,組織.組織名)はGROUP BYに含める必要がある(標準SQL)。この点を無視するとエラーや不正確な結果になる。
- 日付範囲指定の誤解:BETWEENは両端を含むことを忘れて開始・終了の扱いを誤る。日付が時刻を含む型の場合、終了日の扱いに注意する(時刻部分で漏れる)。
- ORDER BY の表記揺れ:ORDER BY 申請書.組織コード と ORDER BY 組織.組織コード は今回の結合条件下ではどちらも動作するが、混在させると可読性や保守性が落ちる。GROUP BY と同じ表記でテーブル名を明示する習慣をつけると安全です。
- テーブル名省略によるあいまいさ:複数テーブルに同名列がある場合は必ずテーブル名を付ける(問題は「列名は、テーブル名を省略せずに、“テーブル名.列名”と記述すること。」と指示しています)。
FAQ
Q: ORDER BY に ORDER BY 組織.組織コード と書いても減点されますか?
A: SQLとしてはJOIN条件で等価になっているため動作します。ただし設問の指示どおり列名はテーブル名付きで書くこと、また GROUP BY と同じ表記に揃えることが可読性と明確さの観点から望ましいです。したがって本問では ORDER BY 申請書.組織コード を正答として示します。
A: SQLとしてはJOIN条件で等価になっているため動作します。ただし設問の指示どおり列名はテーブル名付きで書くこと、また GROUP BY と同じ表記に揃えることが可読性と明確さの観点から望ましいです。したがって本問では ORDER BY 申請書.組織コード を正答として示します。
Q: BETWEEN は開始日と終了日を含みますか?
A: はい。SQLのBETWEENは両端を含む比較です。日付が日時型で時刻を持つ場合は終了日の時刻に注意してください(必要なら終了日をその日の最終時刻に設定するか、< 次の日の基準を使います)。
A: はい。SQLのBETWEENは両端を含む比較です。日付が日時型で時刻を持つ場合は終了日の時刻に注意してください(必要なら終了日をその日の最終時刻に設定するか、< 次の日の基準を使います)。
Q: eに SUM(金額) と書くべきですか、単に SUM でよいですか?
A: 図4の空欄位置は関数名の部分なので SUM が入りますが、完成したSQLでは SUM(申請明細.金額) のように列名をテーブル名付きで書くのが正しい書き方です。
A: 図4の空欄位置は関数名の部分なので SUM が入りますが、完成したSQLでは SUM(申請明細.金額) のように列名をテーブル名付きで書くのが正しい書き方です。
関連キーワード: 集計関数、GROUP BY、ORDER BY、BETWEEN句、日付範囲検索
設問4:
問題文を見るシステムの試行期間において、日当の金額が誤って入力されているケースが多く発見された。そこで、社員テーブルに含まれる職位コードを基に金額が自動入力されるように変更した。しかし、その後の検証で不具合が起こる場合があることが分かった。それはどのような場合か、30字以内で述べよ。
模範解答
社員の出張時の職位と申請時の職位が異なる場合
解説
解答の論理構成
- まず規定を確認します。問題文には
「“日当は、出張時の職位によって表1に従い請求する。”」
とあり、日当の金額は“出張時の職位”で決まると明示されています。 - ところが試行段階での改修では、
「“社員テーブルに含まれる職位コードを基に金額が自動入力される”」
仕様に変更しました。社員テーブルが保持する職位は“現在の職位”です。 - そのため、①出張期間中または出張後~申請前に昇進・降格があった場合、 ②社員テーブルが更新されてから旅費交通費を入力した場合、 自動計算される金額は“出張時”ではなく“申請時”の職位に基づいてしまいます。
- よって不具合が起こるのは
「社員の出張時の職位と申請時の職位が異なる場合」
となり、模範解答と一致します。
誤りやすいポイント
- 規定のキーワード「出張時」を見落として「現職位」で計算してしまう。
- 組織名の取扱い(申請時の組織名)と職位の取扱いを混同しやすい。
- 社員テーブルを“履歴なし”で設計した場合の影響を軽視しがち。
FAQ
Q: 社員テーブルに職位履歴を持たせれば不具合は解消できますか?
A: 履歴を保持し、出張日の職位を参照すれば解消できます。ただし出張期間が複数日にわたる場合は日毎に判定する必要があります。
A: 履歴を保持し、出張日の職位を参照すれば解消できます。ただし出張期間が複数日にわたる場合は日毎に判定する必要があります。
Q: 組織名は「申請時」を基準にしていますが、職位も同様に扱ってはダメですか?
A: 組織名は規定に「申請時の組織名で行う」とある一方、日当は「出張時の職位」と別の基準が定められているため、同一に扱うと規定違反になります。
A: 組織名は規定に「申請時の組織名で行う」とある一方、日当は「出張時の職位」と別の基準が定められているため、同一に扱うと規定違反になります。
Q: 自動入力後に金額を手修正できるようにすればよいのでは?
A: 手修正は人為的ミスを再度招く可能性があり、根本対策にはなりません。出張時点の職位取得ロジックを組み込む方が確実です。
A: 手修正は人為的ミスを再度招く可能性があり、根本対策にはなりません。出張時点の職位取得ロジックを組み込む方が確実です。
関連キーワード: ビジネスルール、データ整合性、マスタ参照、履歴管理、システム設計







