データベーススペシャリスト 2021年 午後1 問03
テーブルの移行及びSQLの設計に関する次の記述を読んで、設問1,2に答えよ。
A社は、不動産賃貸仲介業を全国規模で行っている。 RDBMSを用いて物件情報検索システム(以下、検索システムという)を運用している運用部門のKさんは、物件情報を検索するSQL文を設計している。
〔検索システムの概要〕
検索システムは、物件を管理するシステムを補完するシステムであり、社内利用者が接客するとき、当該システムの “物件” テーブルを利用している。
1.社内利用者の接客業務の概要
(1) 物件を探している借主に対して、当該借主の希望に近い物件を探す支援を行い、借主と貸主との間の交渉・賃貸契約の仲介を行う。
(2) 物件の貸主に対して、物件の審査を行う。 当該貸主に長期の空き物件がある場合、周辺の競合物件の付帯設備 (以下、設備という) の設置状況を調査し、当該空き物件に人気の設備を増強することなど、物件の付加価値を高める対策の助言を行うこともある。
2.“物件” テーブル
(1) A社が仲介する全ての物件を、物件コードで一意に識別する。
(2) 物件の沿線、最寄駅、賃料、間取りなどの基本属性を記録する列がある。
(3) エアコン、オートロックなどの設備が設置されているかどうかの有無を記録する列があり、一つの物件に最大20個の設備の有無を記録できる。
(4) 記録されている20個の設備について、どの設備もいずれかの物件に設置されているが、20個全ての設備が設置されている物件は限られている。
(5) 設備に流行があるので、テーブルの定義を変更し、記録する人気の設備を毎年入れ替える処理を行っている。 この処理を物件設備の入替処理と呼んでいる。
(6) “物件” テーブルの全ての列に NOT NULL制約を指定している。
3.“物件” テーブルのテーブル構造、主な列の意味と制約及び主な統計情報
“物件” テーブルのテーブル構造を図1に、主な列の意味、制約を表1に、RDBMSの機能を用いて取得した主な統計情報を表2に示す。



4.検索システムの課題
Kさんは、社内利用者に聞取り調査を行い、その結果を二つの課題にまとめた。
(1) “物件”テーブルの各設備の有無を示す列 (以下、総称して設備列という)の数は不十分で、借主からの問合せに十分に対応できていない。 追加したい設備は、テレワーク対応、宅配ボックス、追い焚き風呂などがあり、現在の20個を含め、全部で100個ある。 将来、増える可能性がある。
(2) 設備の設置済個数が分からない。 例えば、借主から物件に設置されているエアコンについて問合せがあったとき、設置されている正確な個数が分からず、別の詳細な物件設備台帳を調べなければならない。
〔物件の設備に関する調査及び課題への対応〕
1.物件の設備に関する調査
Kさんは、現在検索できる設備の組合せを述語に指定したSQL文を調査した。そのSQL文の例を、表3に示す。 そしてKさんは、SQL文の結果行を保存するファイルの所要量を見積もる目的で、表3の各SQL文の結果行数を見積もった。
2.物件の設備に関する課題への対応
Kさんは、物件の設備に関する課題に対応するため、次の2案について長所及び短所を比較した結果、案Bを採用することにした。
案A:“物件” テーブルにエアコン台数列を追加する。
案B:追加・変更するテーブルのテーブル構造を、図2に示すとおりにする。
・“設備” テーブルを追加する。図1に示した “物件” テーブルを “新物件” テーブルに置き換える。
・“物件設備” テーブルを追加する。

設備コードは、全設備を一意に識別するコードで、そのうち20個は、“物件” テーブルの各設備列に対応させた。 また、“設備” テーブルの設備名の列値に “物件” テーブルの設備列名をそのまま設定し、今後追加される設備名を含めて重複させないことに決めた。
3.テーブルの移行
Kさんは、追加・変更するテーブルへの移行を、次のような手順で行った。
(1) “設備”、“新物件” 及び “物件設備” テーブルを定義した。
(2) “物件” テーブルから設備列20個を除いた全行を、“新物件” テーブルに複写した。
(3) “設備” テーブルに100個の設備を登録した。 エアコン又はオートロックを登録するSQL文の例を、表4のSQL4に示す。
(4) “物件設備” テーブルには “物件” テーブルにある設備に限って行を登録した。 エアコン又はオートロックがある行を登録するSQL文の例を、表4のSQL5に示す。 ここで、設置済個数列に1を設定し、正確な個数を移行後に設定することにした。
(5) テーブルの統計情報を取得した。 主な統計情報を表5に示す。
〔テーブルの移行の検証〕
Kさんは、テーブルの移行を次のように検証し、新たなビューを定義した。
1.SQL文の検証
テーブルの移行の前後でSQL文が同じ結果行を得るか検証するため、移行前のSQL文 (表3のSQL1, SQL2) に対応する移行後のSQL文を、それぞれ表6のSQL6, SQL7のとおりに設計した。 そして、"1.物件の設備に関する調査” で保存したファイルを用いて、SQL1とSQL6の結果行、SQL2とSQL7の結果行がそれぞれ一致することを確認した。
2.ビューの定義
Kさんは、“物件” テーブルの定義を削除した後でも実績のあるSQL文を変更することなく使いたいと考えている。 そのために “物件” テーブルにあった沿線列、かつ、エアコン列とオートロック列の両方を表示するビュー “物件”を、図3のとおりに定義した。
設問1:〔物件の設備に関する調査及び課題への対応〕について、(1)〜(4)に答えよ。
問題文を見る(1)表3中の(イ)、(ロ)に入れる適切な数値を、(ハ)〜(ホ)に入れる適切な字句を答えよ。 ここで、沿線、エアコン、オートロックの列値の分布は互いに独立し、各列の列値は一様分布に従うと仮定すること。
模範解答
イ:1,000
ロ:3,000
ハ:COUNT(*)
ニ:TOTAL
ホ:沿線,TOTAL
解説
解答の論理構成
- 前提確認
- “行数” 1,600,000、沿線の種類 400 → 1沿線当たり行数=。
- 各設備列は値 Y と N の2種類で一様 → 。
- 列どうしは「互いに独立」。
- (イ)SQL1の見積行数
- 条件確率:沿線 = 指定線 かつYかつY 。
- 。
- 行数=。
- (ロ)SQL2の見積行数
- Y OR Y: 。
- 全体確率:。
- 行数=。
- (ハ)〜(ホ)SQL3の集計句
- 分子は「条件を満たす行数」→ COUNT(*)。
- 分母は WITH TEMP(TOTAL) で求めた全行数列→ TOTAL。
- GROUP BY には 沿線 と TOTAL の両方を指定する必要がある(TOTAL を選択句で使用するため)。
誤りやすいポイント
- OR 条件を単純に と誤算しがち(重複部分の控除を忘れる)。
- GROUP BY 沿線 のみとすると TOTAL が非集約列扱いでエラーになる。
- 「一様分布=半数がY」を忘れ、実務経験則で偏った分布を想定してしまう。
FAQ
Q: CROSS JOIN TEMP を使う理由は何ですか?
A: “TOTAL” を各行に付けておくことで、GROUP BY した後でも全件数を分母にできるからです。サブクエリで毎回 COUNT するよりシンプルかつパフォーマンスが安定します。
A: “TOTAL” を各行に付けておくことで、GROUP BY した後でも全件数を分母にできるからです。サブクエリで毎回 COUNT するよりシンプルかつパフォーマンスが安定します。
Q: GROUP BY 沿線,TOTAL の順序は重要ですか?
A: 順序は問いません。同じグループ化キーを指定していれば結果は同じです。重要なのはTOTALを含めることです。
A: 順序は問いません。同じグループ化キーを指定していれば結果は同じです。重要なのはTOTALを含めることです。
関連キーワード: 一様分布、独立事象、条件付き確率、GROUP BY, 集約関数
設問1:〔物件の設備に関する調査及び課題への対応〕について、(1)〜(4)に答えよ。
問題文を見る(2)“2. 物件の設備に関する課題への対応” について、Kさんが採用した案Bの長所を一つ、本文中の用語を用いて、25字以内で具体的に述べよ。
模範解答
・物件設備の入替処理が不要である。
・全設備の有無と個数の問合せに答えられる。
・将来、増える設備に対して行追加で対応できる。
解説
解答の論理構成
- 現行方式の課題
- 【問題文】「(5) 設備に流行があるので、テーブルの定義を変更し、記録する人気の設備を毎年入れ替える処理」を実施しており、列の増減作業が発生。
- 案Bの構造
- 図2では“設備”と“物件設備”を追加。設備は行で増やすため列変更不要。
- 結果
- 行追加だけで設備の増減を吸収でき、列を削除・追加する「物件設備の入替処理」が不要となる。
- よって長所は「物件設備の入替処理が不要である」と言える。
誤りやすいポイント
- 「全設備の有無と個数が分かる」を答えると列幅問題の改善という別の観点になるため、入替処理の不要化を明示しないと減点されやすいです。
- 「正規化できる」「可変長に対応」など抽象表現のみで本文中の用語「物件設備の入替処理」を使わないと失点します。
- 25字以内という制約を意識しすぎて主語やキーワードを削り過ぎると、具体性不足で評価が下がります。
FAQ
Q: 入替処理が不要になる理由を一言で説明すると?
A: 列でなく行として設備を管理するので、追加時はINSERTだけで済むからです。
A: 列でなく行として設備を管理するので、追加時はINSERTだけで済むからです。
Q: 案Aでも列追加で個数管理はできないのか?
A: 案Aは列を追加するたびにスキーマ変更が発生するため、頻繁な設備入替には不向きです。
A: 案Aは列を追加するたびにスキーマ変更が発生するため、頻繁な設備入替には不向きです。
Q: 正規化の段階で言えば案Bは第何正規形?
A: “物件設備”で多値属性を分離しているため第3正規形を満たしています。
A: “物件設備”で多値属性を分離しているため第3正規形を満たしています。
関連キーワード: 正規化、多値属性、スキーマ変更、マスタ管理
設問1:〔物件の設備に関する調査及び課題への対応〕について、(1)〜(4)に答えよ。
問題文を見る(3)表4中の(a)、(c)及び(d)に入れる適切な字句を、(b)、(e)に入れる一つの適切な述語を答えよ。(a, bは順不同、d, eは順不同)
模範解答
a:物件コード、'A1',1
b:エアコン='Y'
c:UNION ALL
d:物件コード、'A2'、1
e:オートロック='Y'
解説
解答の論理構成
-
列順・値の決定
-
【問題文】「INSERT INTO 物件設備(物件コード、設備コード、設置済個数)」
⇒ 3列目に固定値「1」を入れる指示は「(4)…設置済個数列に1を設定し」と明示。 -
SQL4で設備コードが登録されている例:
sql INSERT INTO 設備 VALUES ('A1', 'エアコン') INSERT INTO 設備 VALUES ('A2', 'オートロック')⇒ 設備コードは 'A1'、'A2' しかあり得ない。 -
以上から (a) と (d) は「物件コード、'A1',1」と「物件コード、'A2',1」。
-
-
抽出条件の決定
- 【問題文】「…エアコン又はオートロックがある行を登録するSQL文の例を、表4のSQL5に示す。」
⇒ WHERE 句は各列の値が 'Y' であることを判定するだけ。 - 設備列名は エアコン と オートロック で固定なので
(b) は「エアコン='Y'」、(e) は「オートロック='Y'」。
- 【問題文】「…エアコン又はオートロックがある行を登録するSQL文の例を、表4のSQL5に示す。」
-
2つの SELECT を連結する演算子
- 行をまとめてインサートするため、重複検査を省きパフォーマンス重視の
UNION ALL が最適(UNION だと重複チェックが走る)。 - したがって (c) は「UNION ALL」。
- 行をまとめてインサートするため、重複検査を省きパフォーマンス重視の
誤りやすいポイント
- UNION と UNION ALL の混同
行数が巨大(【問題文】の表2で「1,600,000」行)なので重複チェックがかかるUNOINは性能劣化の原因。 - 設備コードの記号ミス
SQL4の 'A1'、'A2' を 'a1'、'A01' などと書き換えると参照整合性違反。 - 列順の取り違え
INSERT 対象列を明示していても VALUES/SELECT 側が「設備コード、物件コード…」の順になると挿入失敗。
FAQ
Q: 設置済個数を後で更新するなら最初はNULLにしても良いのでは?
A: 【問題文】「(6)“物件” テーブルの全ての列に NOT NULL制約を指定している。」と同様に、移行先も NOT NULLの想定です。そこで暫定値として1を入れ、その後正しい値へ更新する方が簡便です。
A: 【問題文】「(6)“物件” テーブルの全ての列に NOT NULL制約を指定している。」と同様に、移行先も NOT NULLの想定です。そこで暫定値として1を入れ、その後正しい値へ更新する方が簡便です。
Q: (c) を UNION にしてはいけませんか?
A: 技術的には可能ですが、UNION は重複行を排除するためにソートやハッシュ処理を行います。1,600,000 行規模ではコストが高くなるため、重複が決して起こらない今回のケースでは UNION ALL が推奨されます。
A: 技術的には可能ですが、UNION は重複行を排除するためにソートやハッシュ処理を行います。1,600,000 行規模ではコストが高くなるため、重複が決して起こらない今回のケースでは UNION ALL が推奨されます。
Q: WHERE 句に (エアコン='Y' OR オートロック='Y') とまとめて1本で登録する方法は?
A: 物件ごとに設備を別レコードに分けたい要件(正規化)と、設備コードを挿入時に固定したい要件が両立しにくく、結局 CASE 文や JOIN が必要になります。SELECT を分けて UNION ALL する方がシンプルです。
A: 物件ごとに設備を別レコードに分けたい要件(正規化)と、設備コードを挿入時に固定したい要件が両立しにくく、結局 CASE 文や JOIN が必要になります。SELECT を分けて UNION ALL する方がシンプルです。
関連キーワード: 正規化、UNION ALL, 挿入パフォーマンス、WHERE 句、外部キー
設問1:〔物件の設備に関する調査及び課題への対応〕について、(1)〜(4)に答えよ。
問題文を見る(4)表5中の (あ)、(い) に入れる適切な数値を答えよ。
模範解答
あ:1,600,000
い:20
解説
解答の導き方
まず、表5の(あ)(い)が何を問うているかを明確にします。表の列名「列値個数」はその列に存在する異なる値(=ユニークな値)の個数を示します。したがって、
- (あ)は「物件設備 テーブルの物件コード列に現れる異なる物件コードの個数」、
- (い)は「物件設備 テーブルの設備コード列に現れる異なる設備コードの個数」です。
以下、問題文の記述を順に読んで該当箇所を根拠に値を導きます。
-
(い)=20の根拠
- 問題文に「一つの物件に最大20個の設備の有無を記録できる」とあります。これが移行前に物件テーブルで定義されていた設備の種類数が20種類であることを示します。
- また移行手順(4)に「物件設備テーブルには“物件” テーブルにある設備に限って行を登録した」とあるので、物件設備に登録された設備は元の物件テーブルに列としてあった20種類に限定されます。
- したがって物件設備の設備コードの異なる値の個数は「20」です。
-
(あ)=1,600,000の根拠
- 表2により、移行元の「物件」テーブルの行数(物件数)が「1,600,000」であることが明示されています。
- 移行手順(2)に「“物件” テーブルから設備列20個を除いた全行を、“新物件” テーブルに複写した」とあるので、新物件テーブルの物件コードの集合は元の物件テーブルと同じく1,600,000個の物件コードを持ちます。
- 移行手順(4)の SQL の例(表4 の SQL5)を見ると、物件設備への登録は元の物件テーブルをソースにした INSERT … SELECT によって行われていることが分かります(SQL5 の構文に SELECT … FROM 物件 とある)。
- 問題文全体の移行方針は「元の物件テーブルに記録されていた設備情報を物件設備テーブルへ移す」ことですから、移行結果として物件設備に現れる物件コードの種類は元の物件(=新物件)の物件コードの範囲をカバーすることが前提になっています。よって物件設備の物件コードの異なる値の個数は元の物件数である「1,600,000」となります。
まとめ:
- (あ)=1,600,000
- (い)=20
誤りやすいポイント
- 「記録されている20個の設備について、どの設備もいずれかの物件に設置されている」を「各物件に必ず少なくとも1つの設備がある」と誤解しないこと。前者は「各設備に対して設置されている物件が少なくとも1件はある」という意味であり、各物件ごとに必ず設備があることを保証する文ではありません。
- 「列値個数」と「行数」を混同しないこと。列値個数はその列に出現するユニークな値の数、行数はテーブルの総行数です。問題では列値個数を問われています。
- 「設備」テーブルの行数(100)と「物件設備」に実際に現れる設備コードの種類(20)を混同しないこと。設備テーブルは100件分の設備を管理しますが、移行直後に物件設備へ登録したのは元の物件テーブルで列として扱われていた20種に限られる、という点に注意してください。
FAQ
Q: 「もし元の物件に設備が一切無い物件が存在したら(あ)は変わりますか?」
A: はい。実データとして一部の物件がすべての設備列で 'N'(=設置なし)であり、移行処理でそうした物件に対する物件設備の行が一切作られていなければ、物件設備に現れる物件コードの個数は1,600,000より小さくなります。ただし本問は移行手順の記述(INSERT … SELECT の実行)と表5の意図から、物件設備に元の物件コード集合を反映したものとして扱っており、その前提で(あ)は1,600,000としています。
A: はい。実データとして一部の物件がすべての設備列で 'N'(=設置なし)であり、移行処理でそうした物件に対する物件設備の行が一切作られていなければ、物件設備に現れる物件コードの個数は1,600,000より小さくなります。ただし本問は移行手順の記述(INSERT … SELECT の実行)と表5の意図から、物件設備に元の物件コード集合を反映したものとして扱っており、その前提で(あ)は1,600,000としています。
Q: (い)が100にならない理由は?設備テーブルには100個登録しているのでは?
A: 設備テーブルには確かに100個の設備を登録していますが、移行手順(4)に「物件設備テーブルには“物件” テーブルにある設備に限って行を登録した」とあるため、物件設備には移行元の物件テーブルで列として持っていた20種類だけが登録されています。したがって物件設備の設備コードのユニーク数は20です。
A: 設備テーブルには確かに100個の設備を登録していますが、移行手順(4)に「物件設備テーブルには“物件” テーブルにある設備に限って行を登録した」とあるため、物件設備には移行元の物件テーブルで列として持っていた20種類だけが登録されています。したがって物件設備の設備コードのユニーク数は20です。
Q: 表4のSQL5の構造はなぜ重要ですか?
A: SQL5 の雛形にある「SELECT … FROM 物件」は、物件設備への登録が元データである物件テーブルを直接参照して行われていることを示します。この点が、「物件設備に現れる物件コードは元の物件の物件コードに由来する」という判断の根拠になります。
A: SQL5 の雛形にある「SELECT … FROM 物件」は、物件設備への登録が元データである物件テーブルを直接参照して行われていることを示します。この点が、「物件設備に現れる物件コードは元の物件の物件コードに由来する」という判断の根拠になります。
関連キーワード: 正規化、外部結合、INSERT … SELECT、一意値(DISTINCT)、NOT NULL制約
設問2:〔テーブルの移行の検証〕について、(1)〜(3)に答えよ。
問題文を見る(1)表6中の(f)〜(j)に入れる適切な字句を答えよ。(h, iは順不同)
模範解答
f:INNER JOIN
g:INNER JOIN
h:・S1.設備名='エアコン'
・S1.設備コード='A1'
i:・S2.設備名='オートロック'
・S2.設備コード='A2'
j:・(S.設備名='エアコン' OR S.設備名='オートロック')
・(S.設備コード='A1' OR S.設備コード='A2')
解説
解答の論理構成
- 旧SQLの要件確認
- SQL1は「沿線 = '○△線'」かつ「エアコン = 'Y' AND オートロック = 'Y'」を満たす行を取得。
- 新スキーマへの写像
- “新物件” で「沿線 = '○△線'」を判定。
- “物件設備” は物件と設備の多対多を表すため、同じ物件に対して “エアコン” と “オートロック” の2行が必ず存在する必要がある。
- 2行の存在を保証するための結合方法
- 1物件に対し2レコードを必須としたい=結合に漏れがあってはいけない ⇒ INNER JOIN。
- よって (f)(g) ともに INNER JOIN。
- 設備を特定する述語
- 手順(3) で INSERT INTO 設備 VALUES ('A1'、'エアコン')、('A2'、'オートロック') と登録している。
- 同じ行は「設備名」でも「設備コード」でも一意に指せるので、(h)(i)(j) いずれも名称/コードのいずれか、あるいは両方を組み合わせた句が正答。
- OR/AND の違い
- SQL6は2回結合して AND 条件、SQL7は1回結合後に OR 条件でフィルタ。
誤りやすいポイント
- LEFT JOIN を選ぶと「どちらかが欠けていても行が残る」ため SQL1 の意味を満たさない。
- (h)(i) で = と IN の使い分けを間違え、冗長なサブクエリを作ってしまう。
- SQL7で DISTINCT を忘れると「エアコンとオートロック両方ある物件」が2行重複して返る可能性を見落とす。
FAQ
Q: 名称とコードのどちらで検索すべきですか?
A: 手順(3) で「設備名」の一意性を保証しているため、どちらでも正しく機能します。パフォーマンス面ではインデックスの有無に依存します。
A: 手順(3) で「設備名」の一意性を保証しているため、どちらでも正しく機能します。パフォーマンス面ではインデックスの有無に依存します。
Q: なぜSQL6は結合を2回書くのですか?
A: 「両方の設備が同一物件に存在する」ことを保証するには、同じ物件コードで2つの異なる設備コードを持つ行を同時に満たす必要があるためです。
A: 「両方の設備が同一物件に存在する」ことを保証するには、同じ物件コードで2つの異なる設備コードを持つ行を同時に満たす必要があるためです。
Q: OR 条件を使って1回の結合で AND 要件を表せませんか?
A: 1回結合+OR では「いずれか一方がある物件」しか判定できません。AND 要件を OR 句のみで表すことはできません。
A: 1回結合+OR では「いずれか一方がある物件」しか判定できません。AND 要件を OR 句のみで表すことはできません。
関連キーワード: INNER JOIN, 多対多リレーション、正規化、SQL述語、等価結合
設問2:〔テーブルの移行の検証〕について、(1)〜(3)に答えよ。
問題文を見る(2)表6中のSQL7の選択リストにある DISTINCT の目的は、結果行の重複を排除するためである。 このSQL7で行が重複するのはどのような場合か。 本文中の用語を用いて、30字以内で具体的に述べよ。
模範解答
エアコンとオートロックの両方が設置されている場合
解説
解答の論理構成
- 【問題文】表6の SQL7
SELECT DISTINCT B.物件コード, B.物件名 ...
とあり、DISTINCT で重複除去しています。 - 同じ表6で 物件設備 BS を JOIN し、さらに 設備 S で (j) 条件を付与。
(j) は「設備名が 'エアコン' 又は 'オートロック'」を意味します。 - 物件に
- エアコンだけ → 1行
- オートロックだけ → 1行
- エアコンとオートロック両方 → 2行
のようにヒット数が異なります。
- 両方がある場合、同じ 物件コード が 2回返るので重複し、DISTINCT が必要となります。
- したがって設問の「行が重複する場合」は「エアコンとオートロックの両方が設置されている場合」となります。
誤りやすいポイント
- 「沿線が同じ物件が多いから重複」と勘違いする
→ 重複源は設備の二重ヒットです。 - LEFT JOIN/INNER JOIN の違いに気を取られ、本質を見落とす
→ JOIN 種別ではなく 同じ物件が複数行マッチするかどうかが鍵。 - 別名BSとSの結合条件を読み飛ばし、DISTINCT を不要と判断する。
FAQ
Q: DISTINCT を外し GROUP BY 物件コード、物件名 にしても良いですか?
A: 技術的には可能ですが、DISTINCT の方がシンプルでパフォーマンスも同等か上回る場合が多いです。
A: 技術的には可能ですが、DISTINCT の方がシンプルでパフォーマンスも同等か上回る場合が多いです。
Q: 物件に3種類以上の設備を検索条件にしたら重複行は増えますか?
A: はい。OR 条件で指定する設備数が増えるほど、複数設備を持つ物件は重複ヒットし、DISTINCT がより重要になります。
A: はい。OR 条件で指定する設備数が増えるほど、複数設備を持つ物件は重複ヒットし、DISTINCT がより重要になります。
関連キーワード: DISTINCT, INNER JOIN, 重複行、OR 条件、正規化
設問2:〔テーブルの移行の検証〕について、(1)〜(3)に答えよ。
問題文を見る(3)図3中の(k)〜(o)に入れる適切な字句を答えよ。
模範解答
k:・BS1.設備コード='A1'
・BS1.設備コード IS NOT NULL
l:'Y'
m:'N'
n:LEFT OUTER JOIN
o:BS1.設備コード='A1'
解説
解答の導き方
まず何を求めるビューかを確認します。問題文に「“物件” テーブルの定義を削除した後でも実績のあるSQL文を変更することなく使いたい」とあるので、ビューは元の“物件”テーブルの列と同じ振る舞い(沿線、エアコン列、オートロック列が元の形式で得られること)を再現する必要があります。
移行時のデータ配置を確認します。問題文に「“物件設備” テーブルには “物件” テーブルにある設備に限って行を登録した。 エアコン又はオートロックがある行を登録する SQL文の例…」とあり、さらに設備登録の例に「INSERT INTO 設備 VALUES ('A1'、 'エアコン')」「INSERT INTO 設備 VALUES ('A2'、 'オートロック')」とあることから、エアコンは設備コード 'A1'、オートロックは 'A2' で登録されていることが分かります。したがって「エアコンが設置されているか」は、物件に対して物件設備テーブルに設備コード 'A1' の行が存在するかで判定できます。
ビューの SELECT 部分は CASE 式で値を 'Y'/'N' に変換しています(表1に "Y:設置あり、N:設置なし" とある)。存在すれば 'Y'、存在しなければ 'N' を返す必要があります。
ここで JOIN の種類を考えます。物件一覧(新物件 B)に対して該当する設備が無ければ 'N' を返す必要があるため、設備の有無で物件行自体を除外してはいけません。したがって物件側を基準に全物件を残す LEFT OUTER JOIN を使います。これにより該当設備がない場合は物件設備側の列が NULL になります。
ON 句の設備判定(BS1 にどの設備を割り当てるか)は、JOIN の時点で BS1 をエアコン用に限定しておくのが安全です。よって ON に BS1.設備コード='A1' を含めます。こうすると、BS1.設備コード はエアコンがある物件で 'A1'、ない物件で NULL になります。
CASE 式の条件は等価比較で十分です。LEFT OUTER JOIN と上記 ON の組合せでは、エアコンがある行は BS1.設備コード='A1' が TRUE、ない行は BS1.設備コード は NULL になって BS1.設備コード='A1' の評価は UNKNOWN(SQL の三値論理)となり CASE の ELSE 側に落ちて 'N' になります。したがって (k) は BS1.設備コード='A1'、(l) は 'Y'、(m) は 'N' が自然で簡潔です。また JOIN の種類 (n) は LEFT OUTER JOIN、ON の追加条件 (o) は BS1.設備コード='A1' となります。
以上をまとめると答えは次の通りです。
k:BS1.設備コード='A1'
l:'Y'
m:'N'
n:LEFT OUTER JOIN
o:BS1.設備コード='A1'
l:'Y'
m:'N'
n:LEFT OUTER JOIN
o:BS1.設備コード='A1'
(注意)オートロック側も同様にBS2.設備コード='A2' を ON と CASE の条件に使い、同じ 'Y'/'N' を返す設計になります。
誤りやすいポイント
-
BS1.設備コード='A1' とBS1.設備コード IS NOT NULLを OR で併記する誤り
- 誤り例:CASE WHEN BS1.設備コード='A1' OR BS1.設備コード IS NOT NULL THEN 'Y' …
- 問題点:ある物件に 'A3' のような別の設備行が存在してBS1.設備コード が非NULLなら OR 部分が真になり、エアコンが無くても誤って 'Y' を返す可能性があります。等価比較(='A1')だけで十分です。
-
ON 条件を WHERE に書く(あるいは ON に設備コードを加えず WHERE で設備コードを絞る)ことで LEFT OUTER JOIN の意味が変わる誤り
- 例:LEFT OUTER JOIN ... ON B.物件コード = BS1.物件コード で結合してから WHERE BS1.設備コード = 'A1' とすると、NULL を持つ行が WHERE 節で除外され、実質的に INNER JOIN と同じになり、設備なし物件が消えます。
-
INNER JOIN を使う誤り
- INNER JOIN にすると該当設備を持たない物件は結果から消えるため、元の 'N' を再現できません。
-
ON で設備コードを間違える/設備コードの対応を間違える('A1' と 'A2' の取り違え)
- 表示する列ごとに対応する設備コードを正しく割り当てる必要があります。
FAQ
Q: CASE の条件をBS1.設備コード IS NOT NULLにしてもよいですか?
A: ON 句にBS1.設備コード='A1' を入れているなら、BS1.設備コード は 'A1' かNULLのどちらかになるため IS NOT NULLでも結果は等価になります。ただし可読性と誤用を避ける観点から、エアコン判定はBS1.設備コード='A1' のように等価比較で書く方が分かりやすく安全です。
A: ON 句にBS1.設備コード='A1' を入れているなら、BS1.設備コード は 'A1' かNULLのどちらかになるため IS NOT NULLでも結果は等価になります。ただし可読性と誤用を避ける観点から、エアコン判定はBS1.設備コード='A1' のように等価比較で書く方が分かりやすく安全です。
Q: EXISTS を使した方が良いですか?(例:CASE WHEN EXISTS(SELECT 1 FROM 物件設備 WHERE 物件コード=B.物件コード AND 設備コード='A1') THEN 'Y' ELSE 'N' END)
A: 論理的には同等です。EXISTS は明示的で重複や結合数の問題が起きにくい利点がありますが、ビューとして複数設備列を作る場合は JOIN による方が構文が単純になることが多いです。パフォーマンスは実装する RDBMS の最適化に依存します。
A: 論理的には同等です。EXISTS は明示的で重複や結合数の問題が起きにくい利点がありますが、ビューとして複数設備列を作る場合は JOIN による方が構文が単純になることが多いです。パフォーマンスは実装する RDBMS の最適化に依存します。
Q: ON に設備コードを入れず、CASE で等価比較するだけでも問題ないですか?
A: ON に設備コードが無いと、物件ごとに物件設備の複数行が結合されて重複行が発生する可能性があります(後で DISTINCT 等で除去する必要が出る)。各設備列を作るなら、JOIN 時点でその JOIN が対象とする設備コードに絞る方が明快で安全です。
A: ON に設備コードが無いと、物件ごとに物件設備の複数行が結合されて重複行が発生する可能性があります(後で DISTINCT 等で除去する必要が出る)。各設備列を作るなら、JOIN 時点でその JOIN が対象とする設備コードに絞る方が明快で安全です。
関連キーワード: 正規化、LEFT OUTER JOIN、CASE式、NULL値、等価比較








