SQL OUTER JOIN: 左結合とレコード数
問題: 左結合(LEFT OUTER JOIN)は、左側のテーブルのすべてのレコードと、右側のテーブルのマッチするレコードを結合します。しかし、なぜ左結合が左側のテーブルよりも多くのレコードを返すことができるのでしょうか?
これは、左結合の定義と、NULL 値の扱い方に関連しています。
左結合の定義:
- 左結合は、左側のテーブルのすべてのレコードを返すことを保証します。
- 右側のテーブルのマッチするレコードが見つからない場合、右側の列には NULL 値が挿入されます。
NULL 値の扱い:
- SQL では、NULL 値は "未知の値" と解釈されます。
- 2 つの NULL 値の比較は、通常、結果が不明であるため、比較演算子 (เช่น
=
,!=
) を使用しても一致しないものと見なされます。
例:
SELECT *
FROM TableA LEFT OUTER JOIN TableB ON TableA.ColumnA = TableB.ColumnB;
- TableA に 100 レコードがあり、TableB に 50 レコードがあるとします。
- TableA の ColumnA には、TableB の ColumnB と一致する値が 70 レコードだけ存在するとします。
- 左結合を実行すると、次のようになります:
- TableA の 100 レコードすべてが結果に含まれます。
- TableB の 70 レコードがマッチする ColumnA のレコードと結合されます。
- TableA の残りの 30 レコードは、TableB の ColumnB に NULL 値が挿入されて結合されます。
結果:
最終的に、左結合は 100 レコードを返します。これは、左側のテーブルである TableA のすべてのレコードが含まれるためです。右側のテーブルである TableB のレコードは、マッチするレコードが存在する場合にのみ結合されます。
左結合とレコード数の例
CREATE TABLE TableA (
ColumnA INT PRIMARY KEY
);
CREATE TABLE TableB (
ColumnB INT PRIMARY KEY,
ColumnC VARCHAR(50)
);
INSERT INTO TableA (ColumnA) VALUES (1), (2), (3), (4), (5);
INSERT INTO TableB (ColumnB, ColumnC) VALUES (1, 'A'), (2, 'B'), (3, 'C');
SELECT *
FROM TableA LEFT OUTER JOIN TableB ON TableA.ColumnA = TableB.ColumnB;
解説:
テーブルの作成:
TableA
とTableB
という 2 つのテーブルを作成します。TableA
にはColumnA
という列があり、TableB
にはColumnB
とColumnC
という列があります。
データの挿入:
TableA
に 5 つのレコードを挿入します。
TableA
を左側のテーブル、TableB
を右側のテーブルとして左結合を実行します。- 結合条件は、
TableA.ColumnA
とTableB.ColumnB
が一致することです。
ColumnA | ColumnB | ColumnC
------- | ------- | --------
1 | 1 | A
2 | 2 | B
3 | 3 | C
4 | NULL | NULL
5 | NULL | NULL
分析:
TableA
には 5 つのレコードがありますが、TableB
には 3 つのレコードしかありません。TableB
のレコードは、マッチするレコードが存在する場合にのみ結合されます。TableA
のレコード 4 と 5 は、TableB
のレコードとマッチしないため、ColumnB
とColumnC
に NULL 値が挿入されます。
代替方法:
サブクエリを使用:
- 左側のテーブルのすべてのレコードをサブクエリで取得し、右側のテーブルと結合します。
- この方法では、左側のテーブルのすべてのレコードが確実に含まれます。
SELECT * FROM TableA LEFT JOIN ( SELECT ColumnB, ColumnC FROM TableB ) AS Subquery ON TableA.ColumnA = Subquery.ColumnB;
UNION ALL を使用:
- 左側のテーブルのすべてのレコードと、右側のテーブルのすべてのレコードを
UNION ALL
で結合します。
SELECT ColumnA, ColumnB, ColumnC FROM TableA FULL OUTER JOIN TableB ON TableA.ColumnA = TableB.ColumnB;
- 左側のテーブルのすべてのレコードと、右側のテーブルのすべてのレコードを
CASE WHEN を使用:
- 左側のテーブルのすべてのレコードを結合し、右側のテーブルのレコードが存在しない場合は、右側の列に NULL 値を挿入します。
SELECT TableA.ColumnA, CASE WHEN TableB.ColumnB IS NULL THEN NULL ELSE TableB.ColumnB END AS ColumnB, CASE WHEN TableB.ColumnB IS NULL THEN NULL ELSE TableB.ColumnC END AS ColumnC FROM TableA LEFT JOIN TableB ON TableA.ColumnA = TableB.ColumnB;
選択基準:
- サブクエリ: 複雑な条件や計算が必要な場合に適しています。
- UNION ALL: 両方のテーブルのすべてのレコードを結合する必要がある場合に適しています。
- CASE WHEN: シンプルな条件で右側の列に NULL 値を挿入する必要がある場合に適しています。
sql sql-server sql-server-2005