応用情報 科目A #14:SQLの結合・集約・NULL

応用情報技術者試験の科目Aに必要なSELECT・WHEREと整列、内部結合と左外部結合、GROUP BY・HAVINGとCOUNT、NULLと3値論理、NOT INの落とし穴、DISTINCTを、固定データの追跡例とオリジナル演習問題5問で学びます。

応用情報技術者試験科目AデータベースSQLNULL

AP科目A・第14回 · 2026年度・シラバスVer.7.2に基づく独立した学習資料です。IPAとの提携はなく、合格を保証しません。 シリーズ一覧を見る

IPAとの提携・公認関係がない独立学習資料である。過去問題及び第三者解説は使用せず、合格を保証しない。

学習インデックス

1. 公式の範囲

出典:IPA 応用情報技術者試験(レベル3)シラバス Ver.7.2, https://www.ipa.go.jp/shiken/syllabus/omgdg50000005kq5-att/syllabus_ap_ver7_2.pdf(2026-10-21確認、PDF 43~44頁・印刷フッター39~40頁)。

階層は、大分類3「技術要素」→中分類9「データベース」→2.データベース設計→(2)③データベースの論理設計(NULL)、及び3.データ操作→(1)データベースの操作、(2)②(b)データ操作言語(SELECT文)。SELECT/WHERE、結合、グループ化・集約、NULL、重複、整列を扱う。AP13からは正規化済みのキー接続だけを引き継ぎ、PDF 44頁(印刷フッター40頁)からのトランザクション処理はAP15へ回す。

2. 用語

韓国語 日本語 英語
선택 / 조건절 選択 / WHERE句 selection / WHERE clause
내부 조인 内部結合 inner join
왼쪽 외부 조인 左外部結合 left outer join
그룹화 / 그룹 조건 グループ化 / HAVING句 grouping / HAVING clause
집계 함수 集約関数 aggregate function
널(NULL) NULL(ヌル) NULL
3값 논리 3値論理 three-valued logic (3VL)
중복 제거 重複排除 duplicate elimination
정렬 整列 ordering
상관 서브쿼리 相関副問合せ correlated subquery

3. 固定データ

DEPARTMENT(dept_id PK, dept_name)と、NULL可の外部キーEMPLOYEE.dept_idを接続する。正規化は復習しない。

dept_id dept_name
10 Sales
20 Dev
30 HR
40 Legal
emp_id emp_name dept_id bonus
1 Aki 10 100
2 Bo 10 NULL
3 Chika 20 200
4 Dai NULL 50
5 Emi 20 NULL
6 Fumi 30 100

BLOCKED_DEPT(dept_id nullable)は(20)と(NULL)だけを持つ。論理的な処理の理解順はFROM/JOIN → WHERE → GROUP BY → HAVING → SELECT → ORDER BY。これは意味上の手掛かりであり、DBMSの物理的実行順序ではない。

4. SELECT、WHERE、ORDER BY

SELECT emp_id, emp_name, bonus FROM EMPLOYEE
WHERE bonus >= 100
ORDER BY bonus DESC, emp_id ASC;
emp_id emp_name bonus
3 Chika 200
1 Aki 100
6 Fumi 100

WHEREはTRUEだけを残す。NULLとの比較はUNKNOWNなのでBoとEmiは除外される。第2整列キーが100の同順位を確定する。

5. INNER JOINとLEFT JOIN

SELECT e.emp_id, e.emp_name, d.dept_name
FROM EMPLOYEE AS e INNER JOIN DEPARTMENT AS d ON d.dept_id=e.dept_id
ORDER BY e.emp_id;
emp_id emp_name dept_name
1 Aki Sales
2 Bo Sales
3 Chika Dev
5 Emi Dev
6 Fumi HR

内部結合はTRUEで一致する行だけを残す。DaiのNULL = 値はUNKNOWNである。

SELECT e.emp_id, e.emp_name, d.dept_id, d.dept_name
FROM EMPLOYEE AS e LEFT JOIN DEPARTMENT AS d ON d.dept_id=e.dept_id
ORDER BY e.emp_id;
emp_id emp_name dept_id dept_name
1 Aki 10 Sales
2 Bo 10 Sales
3 Chika 20 Dev
4 Dai NULL NULL
5 Emi 20 Dev
6 Fumi 30 HR

左外部結合は左の全行を保存し、不一致の右列をNULLで補う。

6. GROUP BY、HAVING、COUNT

移植性のある標準的な書き方として、選択する非集約列をすべてGROUP BYに含める。

SELECT d.dept_id, d.dept_name, COUNT(*) AS joined_rows,
 COUNT(e.emp_id) AS employee_count, COUNT(e.bonus) AS known_bonus_count
FROM DEPARTMENT AS d LEFT JOIN EMPLOYEE AS e ON e.dept_id=d.dept_id
GROUP BY d.dept_id, d.dept_name ORDER BY d.dept_id;
dept_id dept_name joined_rows employee_count known_bonus_count
10 Sales 2 2 1
20 Dev 2 2 1
30 HR 1 1 1
40 Legal 1 0 0

COUNT(*)は行を数え、COUNT(式)は式が非NULLの行だけを数える。LegalにはNULL補完行が1行あるため1,0,0になる。

SELECT d.dept_id, d.dept_name, COUNT(e.emp_id) AS employee_count
FROM DEPARTMENT AS d LEFT JOIN EMPLOYEE AS e ON e.dept_id=d.dept_id
GROUP BY d.dept_id, d.dept_name
HAVING COUNT(e.emp_id) >= 2 ORDER BY d.dept_id;
dept_id dept_name employee_count
10 Sales 2
20 Dev 2

WHEREはグループ化前の行、HAVINGは集約後のグループを絞る。HAVINGでの別名利用は製品差があるため集約式を繰り返した。

7. 右表の条件:ONとWHERE

ON内の条件は右側の一致を限定しつつ全4部門を保存する。

SELECT d.dept_id, d.dept_name, e.emp_name, e.bonus
FROM DEPARTMENT AS d LEFT JOIN EMPLOYEE AS e
 ON e.dept_id=d.dept_id AND e.bonus >= 150
ORDER BY d.dept_id, e.emp_id;
dept_id dept_name emp_name bonus
10 Sales NULL NULL
20 Dev Chika 200
30 HR NULL NULL
40 Legal NULL NULL
SELECT d.dept_id, d.dept_name, e.emp_name, e.bonus
FROM DEPARTMENT AS d LEFT JOIN EMPLOYEE AS e ON e.dept_id=d.dept_id
WHERE e.bonus >= 150 ORDER BY d.dept_id, e.emp_id;
dept_id dept_name emp_name bonus
20 Dev Chika 200

後者は結合後に条件不成立行とNULL補完行を除く。このNULL拒否の右側述語は結果を内部結合のようにするが、「全てのWHEREが全てのLEFT JOINを内部結合にする」と一般化してはいけない。

8. NULLと3値論理

式 結果
100 >= 100 TRUE
NULL >= 100 UNKNOWN
TRUE AND UNKNOWN UNKNOWN
FALSE AND UNKNOWN FALSE
TRUE OR UNKNOWN TRUE

WHEREとHAVINGはTRUEだけを残す。= NULLと<> NULLはNULL判定ではなくUNKNOWNになる。IS NULL、IS NOT NULLを使う。

SELECT emp_id, emp_name FROM EMPLOYEE
WHERE bonus IS NULL ORDER BY emp_id;
emp_id emp_name
2 Bo
5 Emi

9. NULLを含むNOT IN

SELECT e.emp_id, e.emp_name FROM EMPLOYEE AS e
WHERE e.dept_id NOT IN (SELECT dept_id FROM BLOCKED_DEPT)
ORDER BY e.emp_id;
emp_id emp_name
(結果なし)

x NOT IN (20,NULL)は概念上x<>20 AND x<>NULL。20はFALSE、他の値はUNKNOWN、従業員側NULLもUNKNOWNで、TRUEはない。

SELECT e.emp_id, e.emp_name FROM EMPLOYEE AS e
WHERE e.dept_id NOT IN
 (SELECT dept_id FROM BLOCKED_DEPT WHERE dept_id IS NOT NULL)
ORDER BY e.emp_id;
emp_id emp_name
1 Aki
2 Bo
6 Fumi

DaiのNULL NOT IN (20)はなおUNKNOWNである。

SELECT e.emp_id, e.emp_name FROM EMPLOYEE AS e
WHERE NOT EXISTS (SELECT 1 FROM BLOCKED_DEPT AS b
                  WHERE b.dept_id=e.dept_id)
ORDER BY e.emp_id;
emp_id emp_name
1 Aki
2 Bo
4 Dai
6 Fumi

DaiにはTRUEの等値一致がないためNOT EXISTSはTRUE。所属不明を除く業務意図ならe.dept_id IS NOT NULLを加える。

SELECT e.emp_id, e.emp_name FROM EMPLOYEE AS e
WHERE e.dept_id IS NOT NULL
 AND NOT EXISTS (SELECT 1 FROM BLOCKED_DEPT AS b WHERE b.dept_id=e.dept_id)
ORDER BY e.emp_id;
emp_id emp_name
1 Aki
2 Bo
6 Fumi

二つのNOT EXISTSは異なる業務意図を表し、常に一方が唯一の代替ではない。

10. 重複、DISTINCT、並び順

SELECT dept_id FROM EMPLOYEE
WHERE dept_id IS NOT NULL ORDER BY dept_id;
dept_id
10
10
20
20
30
SELECT DISTINCT dept_id FROM EMPLOYEE
WHERE dept_id IS NOT NULL ORDER BY dept_id;
dept_id
10
20
30

SQLは指定しなければ重複を残す。ORDER BYなしの行順は未定義。NULLの既定位置とNULLS FIRST/LASTの構文・対応状況にはDBMS差がある。次は確定的な同順位キーを持つ移植可能なNULL-last例である。

SELECT emp_id, emp_name, bonus FROM EMPLOYEE
ORDER BY CASE WHEN bonus IS NULL THEN 1 ELSE 0 END,
         bonus DESC, emp_id ASC;
emp_id emp_name bonus
3 Chika 200
1 Aki 100
6 Fumi 100
4 Dai 50
2 Bo NULL
5 Emi NULL

例はSQLiteで確定的に検証した。NULL・結合・COUNTの中核的意味は標準SQLだが、実行計画、照合順序・大文字小文字、NULL既定位置、一部構文はDBMSごとに異なる。

11. 早見表と落とし穴

目的 要点
行/グループの絞込み グループ前はWHERE、後はHAVING
左側の保存 LEFT JOIN。一致条件は意図に応じONへ
実体数 安易なCOUNT(*)でなくCOUNT(右キー)
NULL判定 IS NULL / IS NOT NULL
除外 NULLの業務意図を定め、NULL入りNOT INに注意
重複/順序 DISTINCT、明示的ORDER BYと同順位キー

落とし穴:NULLを0・空文字とみなす、= NULL、非集約選択列をグループ化しない、HAVINGの別名に依存、論理順序を物理順序と誤認、DISTINCTが整列すると思う、行に自然順があると思う。

12. オリジナル練習問題

以下は全てオリジナルの4択問題(過去問題ではない)。選択肢はア/イ/ウ/エ。

問1 — SELECT/WHERE

4節の問合せが返す従業員IDの順はどれか。

  • ア. 1,3,6
  • イ. 3,1,6
  • ウ. 3,1,2,5,6
  • エ. 3,6,1

正解:イ(2)。 アはbonus降順を無視。イは200の後、100をID昇順にする。ウはNULLを含める。エは同順位を逆にする。

問2 — ON/WHERE

7節の二つの問合せを正しく比較した記述はどれか。

  • ア. 両方ともDev/Chikaだけを返す。
  • イ. WHERE版が4部門を保存する。
  • ウ. ON版にLegal行はない。
  • エ. ON版は4部門行、WHERE版はDev/Chikaだけを返す。

正解:エ(4)。 アはONでの左側保存を無視。イは逆。ウはLegalのNULL補完行を見落とす。エが追跡表どおり。

問3 — COUNT

Legalの(COUNT(*),COUNT(e.emp_id),COUNT(e.bonus))はどれか。

  • ア. (0,0,0)
  • イ. (1,1,0)
  • ウ. (1,0,0)
  • エ. (1,0,1)

正解:ウ(3)。 アは補完行を忘れる。イはNULLのemp_idを数える。ウは1行と非NULL式0個を正しく数える。エはNULL bonusを数える。

問4 — NOT IN

9節最初の問合せの行数はどれか。

  • ア. 0
  • イ. 3
  • ウ. 4
  • エ. 5

正解:ア(1)。 アが正しい。イはNULL除去副問合せ、ウはガードなしNOT EXISTSの結果。エはデータに根拠がない。

問5 — 重複と順序

標準SQLのもとで正しい記述はどれか。

  • ア. DISTINCTは必ず昇順に整列する。
  • イ. 整列時の非NULL部門値は10,10,20,20,30で、ORDER BYなしの順序は未定義。
  • ウ. 従業員主キーは射影したdept_idの重複も防ぐ。
  • エ. NULLは全DBMSで常に最後になる。

正解:イ(2)。 アは重複排除と整列を混同。イが正しい。ウはemp_idの一意性とdept_id射影を混同。エは製品差を無視。

正解(1-based):[2,4,3,1,2] = [イ,エ,ウ,ア,イ]。

13. 自己点検と復習計画

SQLを動かさず全結果表、Legalの1,0,0、NOT INの0行、Daiを含むかという業務意図、確定的NULL-lastを説明できるか確認する。

  • 1日後:固定表を描き、WHERE、二つの結合、COUNTを手で追う。
  • 3日後:ON/WHEREと三つの除外問合せをTRUE/FALSE/UNKNOWNで再現する。
  • 7日後:5問を見ずに解き、GROUP/HAVING問合せと結果表を一つ書く。

出典・完全性:公式範囲には上記IPAシラバスだけを用いた。過去問題・第三者解説は使用していない。

ブログへ