はじめに
こんにちは!今回は、SQLの中でもよく使われるグループ化, 結合, そして副問合せについてまとめます。日々の業務や学習でよく登場するこれらの概念をしっかり押さえておくと、SQLの実用度がぐっと上がります。
本文
1. グループ化(GROUP BY)
1.1 GROUP BY句の基本
GROUP BY句は、特定の列または列の組(キー)を基準に複数の行をひとまとめにして集計する機能です。たとえば、商品番号ごとに売上数量を合計するケースでは次のように書きます。
-- 例
SELECT 商品番号, SUM(数量)
FROM 伝票明細
GROUP BY 商品番号;
これにより、同じ商品番号
を持つ行が一括りにまとめられ、数量が合計されます。
1.2 グループ化でアクセスできる列
GROUP BYを使うと、グループのキーと集約関数でまとめられた結果だけが扱えるようになります。
-
キーとして指定した列:
GROUP BY 商品番号
の場合、商品番号
は使える -
集計関数を適用した列:
SUM(数量)
など
グループ化されていない列(例えば商品名のみ)をSELECT句に含めたい場合は、キーに含める必要があります。
-- NG例: 商品名はキーでも集計対象でもない
SELECT 商品番号, 商品名, SUM(数量)
FROM 伝票明細
GROUP BY 商品番号;
上記はキーに商品名を含んでいないため、エラーになります。正しくは下記のようになります。
-- OK例
SELECT 商品番号, 商品名, SUM(数量)
FROM 伝票明細
GROUP BY 商品番号, 商品名;
1.3 HAVING句
グループ化した後の結果をさらに絞り込む場合は、HAVING句を使います。これはGROUP BYで生じた集計結果に対する検索条件です。
-- 例
SELECT グループ, AVG(年齢) AS 平均年齢
FROM 会員
GROUP BY グループ
HAVING COUNT(*) > 1;
ここでは、グループ内の行数(COUNT(*))が2行以上のものだけを表示しています。
2. 結合(JOIN)
2.1 θ結合(シータ結合)
結合の最も一般的な形であり、結合条件に<
, >
, <=
, >=
, =
などの演算子(θ)を使った結合です。
-- R.A > S.A で結合(例:θ結合)
SELECT *
FROM R INNER JOIN S
ON R.A > S.A;
従来の書き方では下記のようにFROM句に2つのテーブルを並べ、WHERE句で結合条件を書くこともできますが、SQL-92以降ではJOIN句を使った表記が推奨されます。
-- 例
SELECT *
FROM R, S
WHERE R.A > S.A;
2.2 等結合
演算子θが=
の場合の結合です。複数のテーブルに共通する列やキーを使い、その値が等しい行を組み合わせます。
-- 等結合(R.A = S.A)
SELECT *
FROM R INNER JOIN S
ON R.A = S.A;
2.3 自然結合(NATURAL JOIN)
等結合から重複列を取り除いて1回だけ表示させるのが自然結合です。
-
NATURAL JOIN
,USING(列名)
などの書き方が使えます - 同じ列名かつ同じ意味を持つ列が重複して表示されない点が特徴です
-- 例:A列が重複するなら1つだけにまとめる
SELECT *
FROM R NATURAL JOIN S;
2.4 外部結合(OUTER JOIN)
一方のテーブルに存在しない行も結果に含める結合が外部結合です。
- 左外部結合(LEFT OUTER JOIN): 左側テーブルの行は必ず保持し、右側は条件に合う行のみ表示
- 右外部結合(RIGHT OUTER JOIN): 右側テーブルの行は必ず保持し、左側は条件に合う行のみ表示
- 完全外部結合(FULL OUTER JOIN): 左側テーブルと右側テーブルのいずれかの行が存在すれば、結合条件に合致しない行も含めてすべて表示
-- 例
SELECT R.A, R.B, S.C
FROM R LEFT OUTER JOIN S
ON R.A = S.A;
3. 副問合せ(サブクエリ)
副問合せとは、主問合せ(外側のSELECT文)の中に入れ子構造で書かれるSELECT文のことです。
-- 例
SELECT 顧客番号, 顧客名
FROM 顧客
WHERE 顧客番号 IN (
SELECT 顧客番号
FROM 伝票
WHERE 商品番号 = '2001'
);
ここで、(SELECT 顧客番号 FROM 伝票 WHERE 商品番号='2001')
が副問合せになり、その結果に含まれる顧客番号だけをメインクエリで絞り込みます。
3.1 相関副問合せ
相関副問合せでは、副問合せが主問合せの値を参照し、各行ごとに異なる条件で副問合せを実行します。
-- 例
SELECT プロジェクト番号, 社員番号
FROM プロジェクト
WHERE EXISTS (
SELECT *
FROM 社員
WHERE 部門 <= '2000'
AND 社員.社員番号 = プロジェクト.社員番号
);
1行ずつプロジェクト.社員番号
を持ち込み、副問合せで一致する行があればEXISTS
は真となります。
3.2 NOT EXISTS / NOT IN / ALL / SOME
- NOT EXISTS: 存在しなければ真
- NOT IN: 指定リスト/サブクエリ結果に含まれていなければ真
- ALL: すべての値に対して条件を満たす
- SOME / ANY: いずれかの値に対して条件を満たす
共通して、テーブルの状況やインデックスにより速度が変わるため、実行計画をチェックする場合もあります。一般的に、EXISTSはテーブルの内容を取り出さず、インデックスで存在のみをチェックするだけなので高速なことが多いです。また、NOT EXISTS句など、NOTを入れた否定演算を行う場合には、結合では表現できません。
まとめ
SQLのポイントとして、
- グループ化(GROUP BY): 集計関数を使ってキー列ごとに行をまとめる。HAVINGでさらに絞り込み可能
- 結合(JOIN): 複数テーブルを組み合わせて必要な列を取り出す。外部結合や自然結合など、目的に応じた結合方法を選択
- 副問合せ(サブクエリ): 主問合せをサポートする形で入れ子型のSELECTを使う。相関副問合せなど高度な条件指定が可能
これらをマスターすると、複雑な要件にも柔軟に対応でき、日々の開発やデータ分析タスクがよりスムーズに進みます。場合によっては結合でも副問合せでも同等の結果を得られるので、パフォーマンスや可読性を考えて最適な方法を選びましょう。