基本情報技術者 2018年 春期 午後 問03
小学生を対象とした、ある子供会の名簿を管理する関係データベースに関する次の記述を読んで、設問1〜4に答えよ。
D子供会は、小学校に入学するときに入会を受け付け、小学校を卒業したら退会する。D子供会では、会員名簿を管理するためのデータベースを構築して、会の運営に活用している。
このたび、児童のイベントへの参加実績を記録するために、活動表とイベント表を追加した。
データベースの表構成とデータ格納例を図1に示す。下線付きの項目は、主キーを表す。

設問1:
問題文を見る 6年生を対象に実施するイベントの案内を配布するために、6年生の保護者の氏名と住所を抽出する。ここで、同一の保護者は重複して抽出しない。また、同じ住所に氏名が同じ保護者は、複数人いないものとする。正しいSQL文を、解答群の中から選べ。
解答群
ア:SELECT DISTINCT 保護者表.保護者氏名, 保護者表.住所
FROM 保護者表
WHERE 保護者表.保護者番号 NOT IN
(SELECT 児童表.保護者番号 FROM 児童表 WHERE 児童表.学年 = 6)
イ:SELECT DISTINCT 保護者表.保護者氏名, 保護者表.住所
FROM 保護者表, 児童表
WHERE 児童表.学年 = 6
GROUP BY 保護者表.保護者氏名, 保護者表.住所
ウ:SELECT DISTINCT 保護者表.保護者氏名, 保護者表.住所
FROM 保護者表, 児童表
WHERE 保護者表.保護者番号 = 児童表.保護者番号 AND 児童表.学年 = 6
エ:SELECT 保護者表.保護者氏名, 保護者表.住所
FROM 保護者表, 児童表
WHERE 保護者表.保護者番号 = 児童表.保護者番号
GROUP BY 保護者表.保護者氏名, 保護者表.住所 HAVING 児童表.学年 = 6
模範解答
ウ
解説
解答の導き方
求めるのは、6年生の児童に対応する保護者の氏名と住所です。保護者の情報は保護者表にあり、児童の学年は児童表にあります。そのため、2つの表を保護者番号で結び付け、学年が6の児童に絞り込む必要があります。
保護者表の保護者番号と児童表の保護者番号が同じ行どうしを対応させる処理を、表結合(複数の表を共通の項目で結び付けること)といいます。選択肢ウには、両方の表を保護者番号で結び付ける条件と、「児童表.学年 = 6」という条件があります。これで、6年生の保護者だけを取り出せます。
ただし、同じ保護者に6年生の児童が複数いる場合、その保護者の氏名と住所が複数回表示される可能性があります。そこで、選択肢ウはSELECTの後にDISTINCTを指定しています。DISTINCTは、出力する項目の組合せが同じ行を1行にまとめます。設問には「同じ住所に氏名が同じ保護者は、複数人いない」とあるため、氏名と住所の組合せを重複しないようにすれば、同一の保護者を重複して抽出せずに済みます。
このように、必要な保護者を選ぶ条件と、重複を除く指定の両方がそろっているのは選択肢ウです。
ほかの選択肢も確認します。
- アは、保護者番号が「6年生の児童の保護者番号に含まれない」保護者を選んでいます。必要なのは6年生の保護者なので、条件が逆です。
- イは、保護者表と児童表を並べていますが、保護者番号が同じ行どうしを結び付ける条件がありません。そのため、6年生の児童に関係のない保護者まで対象になる可能性があります。
- エは、保護者番号で表を結び付けていますが、学年の条件をWHEREではなくHAVINGに置いています。WHEREはグループ化する前の行を絞り込む条件で、HAVINGはGROUP BYでグループ化した後のグループを絞り込む条件です。ここでは、児童の学年を先に絞り込む必要があります。また、エでは学年をグループ化の項目にも集計の対象にもしていないため、HAVINGの条件として適切ではありません。
誤りやすいポイント
- 氏名と住所を出力するだけでは、同じ保護者が複数の児童の分だけ表示されることがあります。重複を防ぐには、出力項目に対するDISTINCTが必要です。
- 2つの表をFROMに並べただけでは、保護者と児童の対応は決まりません。保護者番号が一致するという条件も必要です。
- WHEREとHAVINGは役割が異なります。個々の児童の学年で絞る場合はWHEREを使います。HAVINGは、集計やグループ化をした後にグループを絞る場合に使います。
- NOT INは「含まれないもの」を選ぶ指定です。この問題では、6年生の保護者を選ぶので、アの条件は目的と反対です。
FAQ
Q: DISTINCTは、どの項目の重複を取り除きますか?
A: SELECTで指定した項目の組合せが同じ行を取り除きます。この問題では保護者氏名と住所の両方が同じ行が重複扱いになります。
A: SELECTで指定した項目の組合せが同じ行を取り除きます。この問題では保護者氏名と住所の両方が同じ行が重複扱いになります。
Q: 保護者番号で表を結び付けるのはなぜですか?
A: 児童表にある保護者番号を使って、その児童の保護者情報が保護者表のどの行にあるかを特定するためです。
A: 児童表にある保護者番号を使って、その児童の保護者情報が保護者表のどの行にあるかを特定するためです。
Q: GROUP BYとDISTINCTは同じ働きですか?
A: どちらも結果の重複をなくす用途で使われることがありますが、GROUP BYは行をグループにまとめる指定です。集計と組み合わせることもできます。重複を取り除く目的だけなら、DISTINCTで指定できます。
A: どちらも結果の重複をなくす用途で使われることがありますが、GROUP BYは行をグループにまとめる指定です。集計と組み合わせることもできます。重複を取り除く目的だけなら、DISTINCTで指定できます。
関連キーワード: SQL、表結合、WHERE句、DISTINCT、GROUP BY、HAVING句
設問2:
問題文を見る イベント番号が18001のイベントに参加した児童のうち、1年生である児童の保護者の保護者番号と氏名を抽出する。ここで、同一の保護者は重複して抽出しない。次のSQL文のに入れる正しい答えを、解答群の中から選べ。
SELECT DISTINCT 保護者表.保護者番号, 保護者表.保護者氏名
a
aに関する解答群
ア:FROM 児童表, 保護者表, イベント表
WHERE 児童表.学年 = 1 AND
イベント表.イベント番号 = 18001
イ:FROM 児童表, 保護者表, イベント表
WHERE 児童表.保護者番号 = 保護者表.保護者番号 AND
児童表.学年 = 1 AND
イベント表.イベント番号 = 18001
ウ:FROM 児童表, 活動表, 保護者表
WHERE 児童表.児童番号 = 活動表.児童番号 AND
児童表.保護者番号 = 保護者表.保護者番号 AND
活動表.イベント番号 = 18001
GROUP BY 児童表.児童氏名 HAVING 児童表.学年 = 1
エ:FROM 児童表, 活動表, 保護者表
WHERE 児童表.児童番号 = 活動表.児童番号 AND
児童表.保護者番号 = 保護者表.保護者番号 AND
児童表.学年 = 1 AND
活動表.イベント番号 = 18001
模範解答
a:エ
解説
解答の導き方
求めるのは、イベント番号が18001のイベントに参加した児童のうち、学年が1である児童の保護者です。結果には保護者番号と保護者氏名を出し、同じ保護者は1回だけ表示します。
SQL(Structured Query Language:関係データベースを操作するための言語)では、必要な表を指定し、表どうしを番号で対応付け、条件に合う行を選びます。
-
参加した児童を見つけます。
図1の活動表には、児童番号とイベント番号が記録されています。つまり、活動表のイベント番号が18001である行から、そのイベントに参加した児童を特定できます。児童表とは児童番号で対応付けます。このため、次の条件が必要です。- 児童表.児童番号 = 活動表.児童番号
- 活動表.イベント番号 = 18001
イベント表にはイベント名や開催日がありますが、児童が参加したかどうかは活動表に記録されています。今回はイベント名や開催日を取り出さないため、イベント表を使う必要はありません。 -
学年が1の児童に絞ります。
児童表の学年を使い、児童表.学年 = 1を条件にします。このように、条件に合う行を選ぶのがWHERE句です。 -
児童の保護者を特定します。
児童表の保護者番号と保護者表の保護者番号を対応付けます。- 児童表.保護者番号 = 保護者表.保護者番号
これで、条件に合う児童の保護者を保護者表から探せます。複数の表を、同じ番号などを使って対応付けることを表の結合といいます。 -
同じ保護者を重複して表示しないようにします。
児童表では、児童ごとに保護者番号が記録されています。そのため、同じ保護者の児童が複数人参加していると、保護者の情報が複数回得られることがあります。SELECT DISTINCTは、指定した保護者番号と保護者氏名の組合せが重複したときに、1回だけ表示する指定です。
これらの条件をすべて満たすのは、児童表・活動表・保護者表を使い、児童番号と保護者番号をそれぞれ対応付けたうえで、学年とイベント番号を条件にするエです。
誤りやすいポイント
-
イベント表を使えば参加児童が分かると思うこと
イベント表にはイベント名や開催日はありますが、児童の参加記録はありません。参加児童を見つけるには、児童番号とイベント番号を持つ活動表が必要です。 -
同じイベント番号の行があれば、その児童が参加したと判断すること
イベント番号だけでは、児童とイベントの関係が分かりません。児童表と活動表を児童番号で対応付ける必要があります。 -
保護者番号を児童表と保護者表で対応付け忘れること
この条件がないと、児童と関係のない保護者の行まで組み合わされるおそれがあります。 -
GROUP BYとHAVINGを使えば重複を取り除けると思うこと
GROUP BYは指定した項目の値ごとに行をまとめる処理で、HAVINGはまとめた後のグループを絞る条件です。選択肢ウのように児童氏名でまとめても、求めている「同一の保護者を重複して抽出しない」という条件には合いません。また、SELECTに指定した保護者番号と保護者氏名がGROUP BYに含まれていないため、一般的なSQLでは適切な書き方ではありません。ここではSELECT DISTINCTで重複を除きます。
FAQ
Q: なぜイベント表を使わなくてよいのですか?
A: 今回必要なのは、イベントに参加した児童を特定することです。活動表に児童番号とイベント番号が記録されているので、この表を使って参加児童を判断できます。イベント名や開催日を表示する場合は、イベント表も使います。
A: 今回必要なのは、イベントに参加した児童を特定することです。活動表に児童番号とイベント番号が記録されているので、この表を使って参加児童を判断できます。イベント名や開催日を表示する場合は、イベント表も使います。
Q: SELECT DISTINCTは何を重複と判断しますか?
A: SELECTの後ろに指定した保護者番号と保護者氏名の組合せが同じ行を重複と判断します。同じ保護者の児童が複数人参加していても、同じ番号と氏名は1回だけ表示されます。
A: SELECTの後ろに指定した保護者番号と保護者氏名の組合せが同じ行を重複と判断します。同じ保護者の児童が複数人参加していても、同じ番号と氏名は1回だけ表示されます。
Q: 学年の条件をHAVINGではなくWHEREに書くのはなぜですか?
A: 学年は、グループにまとめる前の児童の行を選ぶ条件だからです。WHEREは行を条件で絞り込みます。HAVINGは、GROUP BYで行をまとめた後、そのグループを絞るときに使います。
A: 学年は、グループにまとめる前の児童の行を選ぶ条件だからです。WHEREは行を条件で絞り込みます。HAVINGは、GROUP BYで行をまとめた後、そのグループを絞るときに使います。
関連キーワード: SQL、表結合、WHERE句、GROUP BY、重複排除
設問3:
問題文を見る イベント名と、そのイベントに参加した児童の数を表示する。次のSQL文のに入れる正しい答えを、解答群の中から選べ。ここで、イベント名は全て異なるものとする。
SELECT イベント表.イベント名, b
FROM 活動表, イベント表
WHERE 活動表.イベント番号 = イベント表.イベント番号
GROUP BY イベント表.イベント名
bに関する解答群
ア:AVG(活動表.イベント番号)
イ:COUNT(*)
ウ:MAX(活動表.イベント番号)
エ:SUM(活動表.イベント番号)
模範解答
b:イ
解説
解答の導き方
この設問では、イベントごとに参加した児童の数を求めます。SQL(Structured Query Language:データベースに検索や集計を指示する言語)の処理を、順に見ていきます。
-
活動表の1行が何を表すかを確認します。
活動表には「児童番号」と「イベント番号」があります。下線付きの項目は主キー(表の中で行を特定する項目)です。この表では2項目が主キーなので、1行は「ある児童があるイベントに参加した」という組合せを表します。 -
FROMとWHEREで、活動表とイベント表を結び付けます。
WHERE句では、活動表とイベント表のイベント番号が同じ行を対応させています。これにより、参加記録にイベント名が結び付きます。 -
GROUP BYで、イベントごとに行をまとめます。
本文には「イベント名は全て異なるもの」とあります。そのため、イベント名でまとめれば、イベントごとのグループになります。 -
各グループの行数を数えます。
1行が児童1人の参加記録なので、グループ内の行数が、そのイベントに参加した児童の数です。SQLで行数を数える関数はCOUNT()です。したがって、bにはCOUNT()を入れます。
たとえば、図1の活動表ではイベント番号18001の記録が2行あります。そのイベントに対応するイベント名は「歓迎会」なので、参加した児童の数は2人です。
誤りやすいポイント
- AVG、MAX、SUMは、行数を数える関数ではありません。
これらは、数値の平均・最大値・合計を求めます。イベント番号の値を計算しても、参加した児童の数にはなりません。 - イベント番号の種類を数える問題ではありません。
イベントごとに行をまとめた後、そのイベントの参加記録が何行あるかを数えます。 - COUNT(*)は、表全体の行数ではありません。
GROUP BYによってイベントごとに分けられているため、COUNT(*)は各グループ内の行数を数えます。
FAQ
Q: COUNT(*)は何を数えていますか?
A: 集計対象となるグループ内の行数を数えています。この問題では、イベントごとの参加記録の行数です。
A: 集計対象となるグループ内の行数を数えています。この問題では、イベントごとの参加記録の行数です。
Q: なぜ行数が参加した児童の数になるのですか?
A: 活動表の1行が、児童1人とイベント1件の組合せを表しているためです。同じ児童が同じイベントに参加した記録を複数行にしないよう、児童番号とイベント番号が主キーになっています。
A: 活動表の1行が、児童1人とイベント1件の組合せを表しているためです。同じ児童が同じイベントに参加した記録を複数行にしないよう、児童番号とイベント番号が主キーになっています。
Q: イベント名ではなくイベント番号でまとめてもよいですか?
A: この設問ではイベント名が全て異なるので、イベント名でまとめています。イベント番号はイベントを識別する値ですが、設問のSQLではイベント名が集計の単位になっています。
A: この設問ではイベント名が全て異なるので、イベント名でまとめています。イベント番号はイベントを識別する値ですが、設問のSQLではイベント名が集計の単位になっています。
関連キーワード: GROUP BY、COUNT関数、集約関数、主キー、結合処理
設問4:
問題文を見る 年度の切替えのために、次に示す手順で表を更新する。(1)、(2)は入会前の準備のために3月31日に実行し、(3)〜(7)は6年生が退会した4月1日に実行する。次のSQL文のに入れる正しい答えを、解答群の中から選べ。
〔手順〕
(1) 新入会児童の保護者のうち、未登録の保護者を登録する。
(2) 新入会児童を登録する。このとき、学年の値は0とする。
(3) 活動表のレコードを全て削除する。
(4) 児童表の全ての児童に対して、学年の値に1を加える。
(5) 児童表から、学年の値が7の児童を削除する。
(6) 次のSQL文を実行して、保護者表から、在籍する児童がいなくなった保護者を削除する。
DELETE FROM 保護者表
WHERE c
(7) イベント表のレコードを全て削除してから、新年度の計画に合わせてイベントを登録する。
cに関する解答群
ア:保護者表.保護者番号 = NULL
イ:保護者表.保護者番号 IN (SELECT 児童表.保護者番号 FROM 児童表 WHERE 児童表.学年 = 7)
ウ:保護者表.保護者番号 IN (SELECT 児童表.保護者番号 FROM 児童表)
エ:保護者表.保護者番号 NOT IN (SELECT 児童表.保護者番号 FROM 児童表)
模範解答
c:エ
解説
解答の導き方
この設問では、児童がいなくなった保護者を保護者表から削除する条件を考えます。
まず、手順(4)では児童表の学年を全員分1増やし、手順(5)では学年が7になった児童を削除します。新入会児童は学年が0で登録されるため、学年を1増やすと1になります。一方、これまで6年生だった児童は学年が7になって削除されます。したがって、手順(6)の時点では、児童表には在籍している児童が残っています。
保護者表と児童表は、どちらにもある「保護者番号」で対応付けられます。児童表の「保護者番号」にある番号を調べれば、在籍する児童がいる保護者を見分けられます。つまり、保護者表から削除するのは、児童表に保護者番号が一度も現れない保護者です。
SQL(Structured Query Language:データベースを操作するための言語)では、サブクエリ(SQL文の中に書く別の検索)を使って、児童表にある保護者番号の一覧を取り出せます。その一覧に含まれない保護者を指定する条件が「保護者表.保護者番号 NOT IN (SELECT 児童表.保護者番号 FROM 児童表)」です。したがって、当てはまるのはエです。
ほかの選択肢が当てはまらない理由も確認しましょう。
- アは、保護者番号がNULL(値が設定されていない状態)である保護者を探す条件です。今回削除したいのは、保護者番号が空の保護者ではなく、児童表に対応する児童がいない保護者です。
- イは、児童表で学年が7の児童の保護者番号を探す条件です。手順(5)で学年が7の児童はすでに削除されているため、この条件では、児童がいない保護者を判定できません。
- ウは、児童表に保護者番号がある保護者を探す条件です。児童がいる保護者を削除することになり、目的と逆です。
誤りやすいポイント
- 「保護者番号がNULLであること」と「児童表にその保護者番号がないこと」を混同しないようにしましょう。今回は後者を調べます。
- INは、指定した一覧の中に値があるかを調べます。NOT INは、一覧の中に値がないかを調べます。
- 手順の順番にも注意が必要です。手順(5)で学年が7の児童を削除した後に、手順(6)で保護者を調べます。
FAQ
Q: 保護者に児童が複数いる場合、児童が一人でも残っていれば保護者は削除されませんか?
A: 削除されません。児童表にその保護者番号が一つでもあれば、NOT INの条件に当てはまらないためです。
A: 削除されません。児童表にその保護者番号が一つでもあれば、NOT INの条件に当てはまらないためです。
Q: 学年が7の児童の保護者を探すのではいけないのですか?
A: この処理では、学年が7の児童を先に児童表から削除しています。そのため、手順(6)では児童表に残った全ての児童を基準にし、保護者番号が見つからない保護者を探します。
A: この処理では、学年が7の児童を先に児童表から削除しています。そのため、手順(6)では児童表に残った全ての児童を基準にし、保護者番号が見つからない保護者を探します。
関連キーワード: 関係データベース、SQL、サブクエリ、IN条件、NOT IN条件、NULL



