SQL自己結合の仕組みと実践的な使い方

自己結合(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

次に、自己結合を使って同じ NameScore を持つ行の中で、最大の 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;

自己結合は、同一テーブル内の行間の関係を扱う強力な手法であり、重複除去や連続データの比較など、多くのシーンで活用できます。

タグ: SQL 自己結合 重複削除 ROW_NUMBER データベース

6月22日 19:44 投稿