応用情報技術者 2021年 秋期 午前2 問29
問題文
“部門別売上”表から、部門コードごと、期ごとの売上を得るSQL文はどれか。

選択肢
ア:
SELECT 部門コード, '第1期' AS期, 第1期売上 AS 売上
FROM 部門別売上
INTERSECT
(SELECT 部門コード, '第2期' AS 期, 第2期売上 AS 売上
FROM 部門別売上)
ORDER BY 部門コード, 期
イ:
SELECT 部門コード, '第1期' AS期, 第1期売上 AS 売上
FROM 部門別売上
UNION
(SELECT 部門コード, '第2期' AS期, 第2期売上 AS 売上
FROM 部門別売上)
ORDER BY 部門コード, 期
(正解)ウ:
SELECT A.部門コード, '第1期' AS期, A.第1期売上 AS 売上
FROM 部門別売上 A
CROSS JOIN
(SELECT B.部門コード, '第2期' AS 期, B.第2期売上 AS 売上
FROM 部門別売上 B) T
ORDER BY 部門コード, 期
エ:
SELECT A.部門コード, '第1期' AS期, A.第1期売上 AS 売上
FROM 部門別売上 A
INNER JOIN
(SELECT B.部門コード, '第2期' AS期, B.第2期売上 AS 売上
FROM 部門別売上 B) T ON A.部門コード = T.部門コード
ORDER BY 部門コード, 期
🔒 解説は解答すると表示されます
列から行への変換【午前2解説】
正解の理由
与えられた問合せ結果は「各部門について第1期と第2期を別行に並べる(ワイド形式をロング形式に変換)」ことを求めています。これは同じ列構成(部門コード、期、売上)を持つ2つのSELECT結果を縦に連結すれば得られるため、複数行を結合する操作である イ のUNIONを使った構文が最も適切です。UNIONは列数・型・順序が一致するSELECT同士を結合し、結果を1つの集合として返します。本問では第1期と第2期を別々のSELECTで取り出し、それらを結合することで期待する6行(各部門につき2行)を得られます。
(補足)与えられたデータに重複行は存在しないため、実行結果はUNIONとUNION ALLで同一になります。重複を明示的に残したい場合はUNION ALL、重複を排除したい場合はUNIONを使います。
解法ステップ
- 問題が「列を行に変換」する(ワイド→ロング)であると把握する。
- 第1期分を部門コード・'期'ラベル・第1期売上の列順でSELECTする。
- 第2期分も同様の列順・型でSELECTする('期'ラベルは'第2期')。
- 2つのSELECTをUNION(または必要に応じてUNION ALL)で結合する。
- 最後にORDER BYで部門コード・期の順に整列する。
正答に相当するSQL(選択肢と同等の構文)は次の通りです。
SELECT 部門コード, '第1期' AS 期, 第1期売上 AS 売上
FROM 部門別売上
UNION
SELECT 部門コード, '第2期' AS 期, 第2期売上 AS 売上
FROM 部門別売上
ORDER BY 部門コード, 期;
選択肢別の誤答解説
-
ア(INTERSECT を使用)
INTERSECTは2つのSELECTの「全列の値が完全に一致する行のみ」戻します。本問では同じ部門でも'期'列が'第1期'と'第2期'で異なるため、完全一致する行は存在せず、結果は空になります。よって不適切です。 -
ウ(CROSS JOIN を使用)
CROSS JOIN は直積(Cartesian product)を生成します。元テーブルが3行ずつなら、3×3=9行となり、選択列がA側の値のみを参照しているため同じ行が複数回現れる(重複)ことになります。問合せ結果の意図である「各部門につき第1期と第2期をそれぞれ1行ずつ」の構成にはならず誤りです。 -
エ(INNER JOIN を使用)
INNER JOIN で部門コードを結合すると部門ごとに対応する行がマッチしますが、選択している列がA(第1期)のみであるため、結果は第1期の行だけ(各部門1行)になり、第2期の行が出力されません。したがって問合せ結果と合致しません。
よくある誤解
- UNIONは必ず重複排除が必要だと思い込みUNION ALLを避ける
- 実際にはUNIONは重複を排除し、UNION ALLは重複を保持します。データに重複がなければ結果は同じです。パフォーマンス面ではUNION ALLの方が高速な場合が多いので、重複があり得ない(または許容する)ならUNION ALLを選ぶ判断もあります。
- INTERSECTは「キーだけ一致すればよい」と考える誤解
- INTERSECTはSELECTの全列の値が一致する行を返します。キー列だけ一致してもその他の列(本問では'期')が異なれば一致行にはなりません。
- JOINで列向け変換ができると思い込むミス
- JOIN(INNER/CROSS等)は行同士の組合せを作るため、列を行に変換する目的には不適切な設計になることが多いです。単純なワイド→ロング変換ならUNION(またはDBMSのUNPIVOT機能)を使うのが明快です。
補足コラム
- DBMSによってはUNPIVOT句やクロス適用(CROSS APPLY / LATERAL)など、列を行へ変換するための専用構文があります(例:OracleのUNPIVOT、SQL ServerのUNPIVOTやCROSS APPLY + VALUES)。これらは記述が簡潔になり性能上も有利な場合がありますが、試験問題では汎用的に使えるUNION/UNION ALLで解けるケースが多いです。
- ORDER BYについて:UNIONを使う場合、ORDER BYは全体の結果に適用されます。列名の曖昧さを避けるためにはSELECTで付けたエイリアス(ここでは期、売上)を使うと読みやすいです。
FAQ
Q1. UNIONとUNION ALLのどちらを常に使うべきですか?
A1. 重複を排除したい場合はUNION、重複をそのままにしたいか性能重視ならUNION ALLを使います。今回のように元データに重複がないと分かっている場合はUNION ALLでも結果は同じです。
A1. 重複を排除したい場合はUNION、重複をそのままにしたいか性能重視ならUNION ALLを使います。今回のように元データに重複がないと分かっている場合はUNION ALLでも結果は同じです。
Q2. INTERSECTやEXCEPTはよく使いますか?
A2. 使いどころはありますが、列全体の一致に依存すること、DBMSによってはサポートが限られることに注意してください。集合演算は行集合の比較に便利です。
A2. 使いどころはありますが、列全体の一致に依存すること、DBMSによってはサポートが限られることに注意してください。集合演算は行集合の比較に便利です。
Q3. 「期」の順序が意図した通りにならない場合は?
A3. 文字列ソートの結果が想定と違うときは、ソートキーを付け(例:期番号カラムやCASE式で順序を数値化)てORDER BYに使うと確実に期待順で並べられます。
A3. 文字列ソートの結果が想定と違うときは、ソートキーを付け(例:期番号カラムやCASE式で順序を数値化)てORDER BYに使うと確実に期待順で並べられます。
関連キーワード: SQL、UNION ALL、INTERSECT、UNPIVOT、ワイドからロング変換、CROSS JOIN、INNER JOIN、ORDER BY、列の正規化

\ せっかくなら /
応用情報技術者を
クイズ形式で学習しませんか?
クイズ画面へ遷移する→
すぐに利用可能!

