戦国IT - 情報処理技術者試験の過去問対策サイト
ブログお知らせお問い合わせ料金プラン

応用情報技術者 2020年 秋期 午後 問06


宿泊施設の予約を行うシステムに関する次の記述を読んで、設問1~3に答えよ。

   U社は、旅館や民宿などの宿泊施設の宿泊予約を行うWebシステム(以下、予約システムという)を開発している。予約システムの主な要件を図1に示す。
応用情報技術者試験(令和2年度 秋期 午後 問06 図01)
〔データベースの設計〕  予約システムを開発するに当たり、データベースの設計を行った。データベースのE-R図を図2に示す。
 このデータベースでは、E-R図のエンティティ名を表名にし、属性名を列名にして、適切なデータ型で表定義した関係データベースによって、データを管理する。部屋IDは、全施設を通して一意な値である。また、予約ID、予約明細IDは、レコードを挿入した順に値が大きくなる。   〔部屋の予約の流れ〕  部屋の予約は、部屋の空き状況の確認と、予約確定の二つの処理から成る。部屋を予約する際には、希望した施設、部屋の種別、チェックイン日付、チェックアウト日付、部屋数について、空き状況の照会を行う。照会の結果、部屋に空きがあった場合は、予約手続の画面を表示する。部屋に空きがなかった場合は、部屋が空いていない旨を画面に表示し、空き部屋照会のための条件入力の画面に戻って条件を変更するよう促す。  部屋の空き状況の確認を行うためのSQL文を図3に示す。予約する部屋の施設ID、部屋種別ID、チェックイン日付、チェックアウト日付及び部屋数は、埋込み変数“:施設ID”、“:部屋種別ID”、“:チェックイン日付”、“:チェックアウト日付”及び“:部屋数”に設定されている。
〔部屋の空き状況の確認の処理〕  予約システムは、図3のSQL文の検索結果として、レコードが返された場合に予約可能であると判定し、予約手続の画面を表示する。レコードが返されなかった場合は、部屋が空いていない旨を画面に表示する。空き状況確認の処理の流れを図4に示す。
応用情報技術者試験(令和2年度 秋期 午後 問06 図04)
〔予約確定の処理〕  予約手続の画面が表示された後、利用者は予約の確定の操作を行うことで部屋の予約を確定させる。予約の確定の処理では、予約のレコードを挿入した後、各宿泊日について、予約明細に必要な部屋数分のレコードを挿入する。  予約手続の画面が表示されてから、利用者が予約の確定の操作を行うまでの間に、他の利用者が先に予約を確定してしまうこともある。そこで、予約確定の処理では、レコードの挿入の前に図3のSQL文を再度実行し、まだ予約可能な状態であるかを確認してから挿入を行う。予約確定の処理の流れを図5に示す。
応用情報技術者試験(令和2年度 秋期 午後 問06 図05)
〔不具合の報告と対応〕  予約システムのテスト中に、同じ宿泊日の同じ部屋について、予約明細のレコードが重複して挿入されてしまう不具合が報告された。報告された事象について確認すると、別々の利用者が同じ時刻に予約確定の操作を行った際に発生していた。  そこで、今後同じ宿泊日の同じ部屋の予約が重複して入らないようにするために、予約明細テーブルのe列とf列の複合キーに対して制約を追加することにした。このような制約のことを、gという。  gを追加するためには、既に重複して挿入されてしまったレコードを削除する必要がある。削除に当たっては、同じ宿泊日の同じ部屋の予約が重複した予約明細のレコードについて、最初に挿入された予約のレコードと、それに紐づく予約明細のレコードを残し、それ以外の予約明細、予約のレコードを削除することにした。  予約明細について、削除するレコードを抽出するSQL文を図6に示す。図6で得られた該当の予約明細のレコードを削除するとともに、それらに紐づく予約のレコードを削除してから、テストの作業を再開することにした。  予約明細テーブルへの制約の追加後、当該の不具合について再度テストを行ったところ、追加した制約によって、重複が発生しなくなったことが確認できた。

設問1:

問題文を見る
図2中のa、bに入れる適切なエンティティ間の関連及び属性名を答え、E-R図を完成させよ。 なお、エンティティ間の関連及び属性名の表記は、図2の凡例及び注記に倣うこと。

模範解答

a:→ b:施設ID

解説

解答の導き方

  1. [a] の決定
    図中の説明に「予約の確定の処理では、予約のレコードを挿入した後、各宿泊日について、予約明細に必要な部屋数分のレコードを挿入する」という記述があります。これは一つの予約(予約)が複数の予約明細(予約明細のレコード)を持つことを意味します。E-R図の凡例に「矢印 —→ :1対多」とあるため、予約から予約明細への関連は1対多です。よって図2中の空欄 [a] には1対多を示す矢印を入れます。
    最終的に [a] = → です。
  2. [b] の決定
    図2に「施設 —→ 部屋(1対多)」とあり、部屋エンティティの属性欄に空欄 [b] が存在します。リレーショナルデータベースで1対多の関連を実装する基本ルールは「多側の表に一側の主キーを外部キーとして持たせる」ことです。したがって、部屋表(多側)には施設側の主キーである施設IDを属性として持たせる必要があります。問題文にも属性一覧に「施設ID」が存在することを示す文脈があるため、[b] に入る属性名は 施設IDです。
    最終的に [b] = 施設IDです。
まとめ(解答)
  • [a]:→
  • [b]:施設ID

誤りやすいポイント

  • 予約と予約明細の関係を逆に考える
    「予約明細が多数の予約を持つ」と解釈しやすいが、本文の「各宿泊日について、予約明細に必要な部屋数分のレコードを挿入する」を読むと一つの予約に対して複数の予約明細が入るため、方向は予約→予約明細(1対多)である。
  • 部屋IDが全体で一意だから施設IDは不要と誤解する
    部屋IDが全施設で一意であっても、E-R上の「施設 —→ 部屋(1対多)」を関係データベースで実装する際には多側の表(部屋)に一側の主キー(施設ID)を外部キーとして持たせるのが標準であり、参照整合性やクエリの明確化のために施設IDを属性として置くのが適切である。
  • 表記ルール・凡例の読み落とし
    図2の凡例で「矢印 —→ :1対多」と示されている点を見落とし、別の記号や用語で埋めてしまうことがある。
  • 属性名の混同
    部屋種別IDや部屋番号など別の属性名を[b]に入れてしまう。空欄[b]は施設との関連を表す位置にあるため、施設IDが適切である。

FAQ

Q: 部屋IDが全施設を通して一意であれば、部屋表に施設IDを入れるのは冗長ではないですか?
A: 実務的には部屋IDがどの施設の部屋かを一意に示す設計(例えば部屋IDに施設コードを含める)になっている場合もあり得ますが、E-Rの「施設 —→ 部屋(1対多)」という関連を関係モデルで表現する標準的手法は多側(部屋)に一側(施設)の主キーを外部キーとして持たせることです。外部キーとして施設IDを置くことで参照整合性制約を設定でき、問い合わせや結合の明確性・性能上の利点も得られます。したがって設問の空欄には施設IDを入れるのが正しい実装表現です。
Q: 空欄[a]には矢印(→)と書くべきか、文字で「1対多」と書くべきか迷います。どちらが正しいですか?
A: 図2の表記ルールに従うことが指示されています。凡例で「矢印 —→ :1対多」と示されているため、矢印記号で1対多を表すのが図2の様式に一致します。解答欄の様式に合わせて矢印(→)を用いてください。
Q: 予約明細にはどの外部キーが必要ですか?
A: 予約明細の属性に「予約ID」と「部屋ID」があります。これらはそれぞれ予約テーブルと部屋テーブルへの外部キーになり、どの予約に属する明細か、どの部屋の明細かを示します。

関連キーワード: 外部キー、参照整合性、1対多(カーディナリティ)、主キー、リレーショナル実装

解説を読んでも分からないところは、AIに質問できます。 この問題の本文と解説をふまえて答えます。

この設問をAIに質問する

クイズモードで開きます(AIへの質問は無料の会員登録で使えます)

図3中のc、dに入れる適切な字句を答えよ。

模範解答

c:NOT EXISTS d:HAVING COUNT(*)

解説

解答の論理構成

  1. 部屋の空きを判定する要件
    • 本文に「部屋を予約する際には、…チェックイン日付、チェックアウト日付、部屋数について、空き状況の照会を行う。」とあります。
    • また「図3のSQL文の検索結果として、レコードが返された場合に予約可能であると判定」とあり、返るレコードは “空いている部屋種別” を示す必要があります。
  2. c の導出 ―― 既存予約と重複しない部屋を抽出
    • 図3のSQLでは部屋表を外側に置き、「予約明細」表をサブクエリで参照しています。
    • 重複がある部屋は除外するために、サブクエリに該当レコードが“存在しない”ことを条件にします。
    • SQLで存在しないことを表す代表的な述語は NOT EXISTS です。
    • よって c には NOT EXISTS が入ります。
  3. d の導出 ―― 希望部屋数を満たすグループのみ返却
    • 外側の SELECT では「施設ID, 部屋種別ID, COUNT(*)」を取得し、その直後に「GROUP BY 施設ID, 部屋種別ID」が置かれています。
    • グループ化の結果に対して行数(=空いている部屋数)が “:部屋数” 以上かどうかを判定する必要があります。
    • 集計後の行数に条件を付けるには HAVING 句を使います。
    • したがって d に入るのは HAVING COUNT(*) です。
  4. 以上より
    • c:NOT EXISTS
    • d:HAVING COUNT(*)

誤りやすいポイント

  • サブクエリを NOT IN で書こうとしてNULLを含むケースを見落とす。NOT EXISTS を使うとNULL問題を回避できます。
  • HAVING を WHERE に置き換えてしまう。WHERE はグループ化前に評価されるため、COUNT(*) などの集計結果を直接使えません。
  • HAVING COUNT() >= :部屋数 の COUNT() を別名で受け取り、その別名を HAVING で参照しようとしてエラーになるケース。集計関数そのものを HAVING 句に書く方が安全です。

FAQ

Q: NOT IN と NOT EXISTS のどちらを使っても良いですか?
A: NULLを含む可能性がある列を比較すると NOT IN は全行を除外してしまう危険があります。本設問では安全策として NOT EXISTS を採用します。
Q: HAVING を使わず WHERE COUNT(*) と書くとどうなりますか?
A: WHERE 句では集計関数を直接扱えないため SQL エラーになります。集計結果に条件を付ける場合は必ず HAVING を使用してください。
Q: COUNT() ではなく COUNT(部屋ID) にしても良いですか?
A: 主キーである 部屋IDはNULLになり得ないので結果は同じですが、可読性と汎用性を考慮し全行を数える COUNT(
) が一般的です。

関連キーワード: NOT EXISTS, HAVING句、集計関数、サブクエリ、NULL比較

解説を読んでも分からないところは、AIに質問できます。 この問題の本文と解説をふまえて答えます。

この設問をAIに質問する

クイズモードで開きます(AIへの質問は無料の会員登録で使えます)

設問3:〔不具合の報告と対応〕について、(1)〜(3)に答えよ。

問題文を見る
(1)本文中のe、fに入れる適切な列名を答えよ(eとfは順不同)。

模範解答

e:宿泊日 f:部屋ID

解説

解答の論理構成

  • 【問題文】に「同じ宿泊日の同じ部屋について、予約明細のレコードが重複して挿入されてしまう不具合が報告された」とあります。
    └ 重複の判定条件は “同じ宿泊日” かつ “同じ部屋” であることが明示されています。
  • 同じ箇所で「予約明細テーブルのe列とf列の複合キーに対して制約を追加することにした」と記述されています。
    └ つまり、重複防止用のユニーク制約(複合キー)を掛ける対象列がeとfです。
  • 予約明細テーブルに存在し、かつ重複判定で使われる列は “宿泊日” と “部屋ID” の二つしかありません。
    └ “予約ID” や “予約明細ID” は予約ごと・明細ごとの識別子であり、同一部屋・同一宿泊日の重複を検知できません。
  • 以上より、e と f には
    ・宿泊日
    ・部屋ID
    を設定すれば、同一部屋・同一宿泊日に同じレコードが二度入ることをユニーク制約で防止できます。

誤りやすいポイント

  • 予約IDや予約明細IDをキーに含めてしまう
    → これらはそもそも重複してはいけない主キー属性であり、今回の「部屋×宿泊日」の重複を防げません。
  • チェックイン日付/チェックアウト日付を選んでしまう
    → 予約明細は宿泊日ごとに1レコードを持つ設計なので、期間情報ではなく “宿泊日” が必要です。
  • キーの順序を気にし過ぎる
    → SQLレベルのユニーク制約では複合キー内の列順は一意性判定に影響せず、部屋ID→宿泊日でも宿泊日→部屋IDでも同じ効果です。

FAQ

Q: 予約確定時の排他制御は不要になりますか?
A: ユニーク制約で重複挿入は防げますが、業務的な「必要室数の確保」は依然として同時実行制御(再チェック+コミット)が必要です。
Q: 複合キーと主キーの違いは?
A: 主キーはテーブルの行を一意に識別する列(群)でNULL不許可。複合キーに付けるユニーク制約は「重複禁止」を保証するだけで、主キーとは別に設定できます。
Q: 後からユニーク制約を追加する際の注意点は?
A: 既存データに重複があると制約追加に失敗するため、問題文のようにまず重複行を抽出・削除してから ALTER TABLE … ADD CONSTRAINT を行います。

関連キーワード: ユニーク制約、複合キー、排他制御、トランザクション

解説を読んでも分からないところは、AIに質問できます。 この問題の本文と解説をふまえて答えます。

この設問をAIに質問する

クイズモードで開きます(AIへの質問は無料の会員登録で使えます)

設問3:〔不具合の報告と対応〕について、(1)〜(3)に答えよ。

問題文を見る
(2)本文中のgに入れる適切な字句を答えよ。

模範解答

g:UNIQUE制約

解説

解答の論理構成

  1. まず問題文中に
    “予約明細テーブルのe列とf列の複合キーに対して制約を追加することにした。このような制約のことを、gという。”
    と明記されています。
  2. 目的は “同じ宿泊日の同じ部屋について、予約明細のレコードが重複して挿入されてしまう不具合” を防ぐことです。
  3. すなわち “e列とf列” (=部屋IDと宿泊日) の組み合わせがテーブル内で重複しないようにする必要があります。
  4. RDBで列または列集合の重複を禁止する制約は “UNIQUE制約” で、主キー以外の列にも設定できます。
  5. よって “g” に入る適切な語句は “UNIQUE制約” となります。

誤りやすいポイント

  • 主キーと混同する
    UNIQUE制約は重複禁止ですがNULLを許容でき、主キーとは異なるという点を忘れがちです。
  • CHECK制約との取り違え
    CHECK は値の範囲や論理式を検証するだけで、行間の重複は検出できません。
  • インデックスと制約の違い
    UNIQUEインデックスと結果的に同じ動作になるDBもありますが、問題では “制約” と明言されているため UNIQUE制約と答える必要があります。

FAQ

Q: 部屋IDと宿泊日を主キーにすれば良いのでは?
A: 主キーには既に “予約明細ID” が設定されているため重複防止だけを目的に主キーを変更すると設計全体に影響します。そこで既存の主キーはそのままに、重複禁止のための UNIQUE制約を追加するのが妥当です。
Q: UNIQUE制約を追加する前に重複行を削除しないといけないのはなぜ?
A: 既に重複が存在する状態で UNIQUE制約を張ると整合性が取れずエラーになるため、先に重複行を削除しておく必要があります。
Q: UNIQUE制約と一緒に排他ロックを使うべき?
A: 挿入競合をトランザクション制御で防御する方法もありますが、制約でDBレベルの整合性を担保しておけばアプリ側でロックを細かく制御しなくても重複は発生しません。

関連キーワード: UNIQUE制約、重複禁止、複合キー、データベース制約、整合性保持

解説を読んでも分からないところは、AIに質問できます。 この問題の本文と解説をふまえて答えます。

この設問をAIに質問する

クイズモードで開きます(AIへの質問は無料の会員登録で使えます)

設問3:〔不具合の報告と対応〕について、(1)〜(3)に答えよ。

問題文を見る
(3)図6中のh〜jに入れる適切な字句を答えよ(iとjは順不同)。

模範解答

h:MIN(t2.予約ID) i:t1.部屋ID = t2.部屋ID j:t1.宿泊日 = t2.宿泊日

解説

解答の論理構成

  1. 目的の整理
    不具合修正では、 「同じ宿泊日の同じ部屋の予約明細のレコードについて、最初に挿入された予約のレコードと、それに紐づく予約明細のレコードを残し、それ以外の予約明細、予約のレコードを削除する」
    ことが求められています。
  2. “最初に挿入された” かどうかの判定軸
    問題文には「予約ID、予約明細IDは、レコードを挿入した順に値が大きくなる。」とあります。
    したがって、同一の部屋・宿泊日で最小の 予約IDが “最初の予約” になります。
  3. 取得したいレコード
    ・外側のt1は “削除候補” を示します。
    ・内側の副問い合わせt2は “同じ部屋・同じ宿泊日の中で最小(=先頭)の予約ID” を返します。
    ・t1.予約ID > (SELECT …) という比較で、先頭レコードより後に挿入された重複分だけを抽出します。
  4. 字句の対応
    (1) h は、同じグループ内で最小の 予約IDを取得する集約関数 ― MIN(t2.予約ID)
    (2) i と j は “同じ部屋” と “同じ宿泊日” を示す等価条件
    ・t1.部屋ID = t2.部屋ID
    ・t1.宿泊日 = t2.宿泊日
    順不同なのでi・jいずれに置いても成立します。
  5. 結論
    h:MIN(t2.予約ID)
    i:t1.部屋ID = t2.部屋ID
    j:t1.宿泊日 = t2.宿泊日

誤りやすいポイント

  • “最初に挿入” を 予約明細IDで比較してしまう
    → 要件では “予約IDで判断する” と明示されています。
  • 集約関数を MIN(*) や MIN(予約明細ID) にしてしまう
    → 副問い合わせは先頭の予約を探すので、対象列は必ず 予約IDです。
  • 等価条件を >= や > に書き換えてしまう
    → グループ化のキーは完全一致でなければ同一レコードとみなせません。

FAQ

Q: MIN ではなく MAX を使ってはいけないのですか?
A: 先に挿入されたレコードを残し、それ以外を削除するため “最小” の 予約IDを求める必要があります。MAX にすると最後に挿入された予約が残ってしまいます。
Q: 副問い合わせのt2を EXISTS で書き換えることはできますか?
A: 重複行を1行だけ残す要件上、MIN(t2.予約ID) のような集約が必要です。EXISTS 単独では “最小値” を取得できないため、本問の目的を満たせません。
Q: 宿泊日 と 部屋IDのどちらをキーにすべきか迷います。
A: 不具合の原因は「同じ宿泊日の同じ部屋」に対して重複が入ることです。したがって両方を等価条件に含めて重複グループを正しく特定します。

関連キーワード: 集約関数、サブクエリ、複合一意制約、データ整合性、重複排除

解説を読んでも分からないところは、AIに質問できます。 この問題の本文と解説をふまえて答えます。

この設問をAIに質問する

クイズモードで開きます(AIへの質問は無料の会員登録で使えます)

戦国ITクイズ機能

\ せっかくなら /

応用情報技術者を
クイズ形式で学習しませんか?

クイズ画面へ遷移する→

すぐに利用可能!

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

このサイトについてブログプライバシーポリシー利用規約特商法表記開発者について