背景
データベースを扱うとき、「複数のテーブルを結合して最終的に件数を出したい」 という場面はよくあります。
例えば次のような構造を考えてみましょう。

- Aテーブル … 拠点や住所などの基本情報
- Bテーブル … Aテーブルと紐づく組織コードを持つ
- Cテーブル … Bテーブルの組織コードを使って所属ユーザーを管理している
最終的には「拠点+組織ごとのユーザー数」を1本のSQLで取得したいわけです。
よくある分割クエリ
まずは単純に分けて考えるとこうなります。
AとBを結合
SELECT DISTINCT
B.組織コード,
A.拠点コード,
A.住所
FROM Aテーブル A
LEFT JOIN Bテーブル B
ON B.拠点コード = A.拠点コード;
Cで件数を集計
SELECT
組織コード,
COUNT(ユーザーID) AS 件数
FROM Cテーブル
GROUP BY 組織コード;
3テーブルをまとめたクエリ
実際には JOINを重ねてGROUP BYするだけ で、1つにまとめられます。
NULLを0として残す場合
SELECT
B.組織コード,
A.拠点コード,
A.住所,
COALESCE(COUNT(C.ユーザーID), 0) AS 件数
FROM Aテーブル A
LEFT JOIN Bテーブル B
ON B.拠点コード = A.拠点コード
LEFT JOIN Cテーブル C
ON C.組織コード = B.組織コード
GROUP BY
B.組織コード,
A.拠点コード,
A.住所;
件数が存在する組織だけ出したい場合
SELECT
B.組織コード,
A.拠点コード,
A.住所,
COUNT(C.ユーザーID) AS 件数
FROM Aテーブル A
INNER JOIN Bテーブル B
ON B.拠点コード = A.拠点コード
INNER JOIN Cテーブル C
ON C.組織コード = B.組織コード
GROUP BY
B.組織コード,
A.拠点コード,
A.住所;
ポイント
- 3テーブルを1本のクエリでまとめる
A → B → C とJOINを重ねればOK - COUNTとGROUP BYで集計
件数を集めたいカラムを基準にまとめる - NULLをどう扱うか
LEFT JOIN + COALESCE()
→ 件数が無くても0で表示INNER JOIN
→ 件数がある組織だけ抽出
WITH(共通テーブル式)で可読性を上げる
そんな時に便利なのが WITH句(Common Table Expression, CTE) です。
サブクエリに名前をつけて、処理を段階的に整理できます。
WITHを使った例
USE SampleDB;
WITH q1 AS (
SELECT DISTINCT
a.Unit_Code, -- 組織コード
p.Location_Code, -- 拠点コード
p.Location_Name -- 拠点名
FROM A_Location_Master p
LEFT JOIN B_Unit_Location a
ON a.Location_Code = p.Location_Code
),
q2 AS (
SELECT
o.Unit_Code,
COUNT(o.User_Id) AS EmployeeCount
FROM C_Employee_Unit o
GROUP BY o.Unit_Code
)
SELECT
q1.Unit_Code,
q1.Location_Name,
q2.EmployeeCount
FROM q1
INNER JOIN q2
ON q2.Unit_Code = q1.Unit_Code;
ポイント解説
- q1 … 拠点と組織コードをまとめた部分(A+B)
- q2 … 組織ごとの件数をまとめた部分(Cの集計)
- 最後に両者を結合して「拠点+組織ごとの件数」を取得
👉 このように 処理を2段階に分けて名前をつける ことで、SQLの流れがはっきりします。
まとめ
- JOINとGROUP BYを組み合わせると、3テーブルをまとめて集計できる
COALESCE
を使えばNULLを0として扱えるWITH
を使うとクエリの見通しが良くなり、ナレッジとして共有する時にも分かりやすい
SQLは「動けばOK」ではなく、「読みやすさ・保守しやすさ」も大事です。
特に社内ナレッジとして残す場合、WITHで分割して説明しやすくするのがおすすめです。
コメント