自己結合(Self-Join)とは、同じテーブルを2回参照し、それぞれに別名(エイリアス)を付けて結合する手法です。テーブルの構造とデータは同一ですが、別のインスタンスとして扱うことで、同一テーブル内の行同士を比較・組み合わせることが可能になります。
基本例:無条件の自己結合
まず、以下のような生徒テーブル Students を考えます。
-- Students テーブル
Name | Score
---------|------
田中 | 85
鈴木 | 92
佐藤 | 78
高橋 | 88
何も条件を付けずに自己結合すると、すべての行の組み合わせ(直積)が生成されます。
SELECT
a.Name AS Name1,
b.Name AS Name2
FROM Students a, Students b;
結果は数学的な順列のようになります(4×4=16行)。
条件付き自己結合
通常は何らかの条件を指定します。例えば、同じ名前を持つ行同士を結合したい場合:
SELECT
a.Name AS Name1,
b.Name AS Name2
FROM Students a, Students b
WHERE a.Name = b.Name;
これは各行同士が自分自身と結合するため、もとの行数と同じ4行が返ります。
実務では、異なる行同士を比較するために自己結合を使うことが多いです。たとえば、名前が異なるペアをすべて取得する場合:
SELECT
a.Name AS Name1,
b.Name AS Name2
FROM Students a, Students b
WHERE a.Name <> b.Name;
この結果は12行(順序ありの組み合わせ)になります。さらに、重複するペア(例:「田中・鈴木」と「鈴木・田中」)を排除したい場合は、不等号ではなく大小比較を用います。
SELECT
a.Name AS Name1,
b.Name AS Name2
FROM Students a, Students b
WHERE a.Name > b.Name;
これにより、辞書順で大きい名前が左側、小さい名前が右側に来る組み合わせのみ(3行)が取得できます。これは数学的な組合せ(nC2)に相当します。
自己結合の実践例:重複行の削除
自己結合は重複データの削除にも応用できます。次のように、主キーがない Scores テーブルを考えます。
-- Scores テーブル(重複あり)
Name | Score
---------|------
田中 | 85
鈴木 | 92
田中 | 85
佐藤 | 78
鈴木 | 92
このテーブルから重複行を1つだけ残すには、まず識別用の連番を追加します。SQL Serverの例では IDENTITY 関数を使えますが、ここでは汎用的な方法として ROW_NUMBER() を利用した一時テーブルを作成します。
-- 一時テーブルに連番付きでデータを格納
SELECT
ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS RowID,
Name,
Score
INTO #TempScores
FROM Scores;
これで #TempScores テーブルには以下のように連番が振られます。
RowID | Name | Score
------|---------|-------
1 | 田中 | 85
2 | 鈴木 | 92
3 | 田中 | 85
4 | 佐藤 | 78
5 | 鈴木 | 92
次に、自己結合を使って同じ Name と Score を持つ行の中で、最大の RowID 以外(つまり最小以外)を削除します。
DELETE FROM #TempScores
WHERE #TempScores.RowID < (
SELECT MAX(t2.RowID)
FROM #TempScores t2
WHERE #TempScores.Name = t2.Name
AND #TempScores.Score = t2.Score
);
削除後の #TempScores は以下のように重複が除去されます。
RowID | Name | Score
------|---------|-------
1 | 田中 | 85
2 | 鈴木 | 92
4 | 佐藤 | 78
最後に、この一時テーブルを元のテーブルに戻せば完了です。なお、元のテーブルから直接重複を削除する場合は DISTINCT を使って一時テーブルにユニーク行を入れ、元テーブルをトランケートしてから再挿入する方法も一般的です。
SELECT DISTINCT * INTO #UniqueScores FROM Scores;
TRUNCATE TABLE Scores;
INSERT INTO Scores SELECT * FROM #UniqueScores;
DROP TABLE #UniqueScores;
自己結合は、同一テーブル内の行間の関係を扱う強力な手法であり、重複除去や連続データの比較など、多くのシーンで活用できます。