SQL Serverで理解しておきたいJOIN構文と種類ごとの使い分け
JOINは、複数のテーブルを結合して一つの結果セットにまとめるための構文です。
リレーショナルデータベースの基本かつ中心的な機能であり、業務データ分析やアプリケーション開発でも頻繁に使用されます。
本記事では、JOINの種類と使い分け、そして実務で役立つ注意点を実例付きで詳しく解説します。
目次
JOINとは
JOINは、異なるテーブル間の関連性(キー列)をもとに結合し、複数テーブルを1つの結果として扱うSQL構文です。
リレーショナルデータベースでは、テーブルを正規化することで冗長性を減らしていますが、JOINはそれらを再び論理的にまとめるための仕組みです。
SQL Serverでは、主に INNER / LEFT / RIGHT / FULL / CROSS の5種類が提供されています。
INNER JOIN(内部結合)
INNER JOINは「両方のテーブルに共通して存在するデータ」だけを取り出す結合です。
もっとも一般的で、基礎となるJOINの形です。
-- INNER JOIN の基本構文
SELECT o.OrderId, c.FullName
FROM dbo.Orders AS o
INNER JOIN dbo.Customers AS c
ON o.CustomerId = c.CustomerId;
この例では、顧客テーブルと注文テーブルを顧客IDで結合し、両方に存在するデータのみを取得します。
🔹 実務例:社員と部署を結合して一覧を表示
SELECT e.EmployeeId, e.FullName, d.DepartmentName
FROM dbo.Employees AS e
INNER JOIN dbo.Departments AS d
ON e.DepartmentId = d.DepartmentId
ORDER BY d.DepartmentName;
INNER JOINでは「結合条件(ON)」と「絞り込み条件(WHERE)」を分けて記述するのがベストプラクティスです。
可読性と保守性が高まり、他のJOIN構文でも統一した書き方ができます。
LEFT / RIGHT OUTER JOIN(外部結合)
OUTER JOINは、一方のテーブルに存在しないデータも含めたい場合に使います。
LEFTは左側テーブルを基準に、RIGHTは右側を基準にします。
ONとWHEREの位置による違い
-- ON に条件を書く(NULLを保持)
SELECT c.CustomerId, c.FullName, o.OrderId
FROM dbo.Customers AS c
LEFT JOIN dbo.Orders AS o
ON c.CustomerId = o.CustomerId
AND o.Region = 'Tokyo';
-- WHERE に条件を書く(NULLは除外される)
SELECT c.CustomerId, c.FullName, o.OrderId
FROM dbo.Customers AS c
LEFT JOIN dbo.Orders AS o
ON c.CustomerId = o.CustomerId
WHERE o.Region = 'Tokyo';
前者は「東京の注文がある顧客は結合、ない場合はNULL」を返し、
後者は「東京以外の顧客が除外」されます。
この違いを理解していないと、OUTER JOINの意味が変わってしまうので要注意です。
比較イメージ
| 条件の書き方 | 結果の特徴 | NULL保持 |
|---|---|---|
| ON に条件を書く | 結合条件に合わない右側行は NULL として保持 | 保持される |
| WHERE に条件を書く | WHERE で絞り込まれるため、NULL行は除外 | 除外される |
アンチ結合(存在しないデータを抽出)
LEFT JOINとIS NULLを組み合わせることで、「関連データが存在しない行」を抽出できます。
これは アンチ結合 と呼ばれ、実務で頻出するパターンです。
-- 注文が存在しない顧客を抽出
SELECT c.CustomerId, c.FullName
FROM dbo.Customers AS c
LEFT JOIN dbo.Orders AS o
ON c.CustomerId = o.CustomerId
WHERE o.CustomerId IS NULL;
この構文は「未注文の顧客」「未処理の申請」など、業務システムでよく使われます。
FULL OUTER JOIN(全結合)
FULL OUTER JOINは、両方のテーブルを結合し、どちらか一方にしか存在しないデータも含めます。
両テーブルの差分確認やデータ同期チェックで活躍します。
SELECT a.KeyId, a.Value AS LeftValue, b.Value AS RightValue
FROM dbo.TableA AS a
FULL OUTER JOIN dbo.TableB AS b
ON a.KeyId = b.KeyId;
NULLを多く含むため、実務では「差分検出」など限定的な用途に使われます。
CROSS JOIN(直積結合)
CROSS JOINは、両テーブルの全行を掛け合わせた結果を返します。
行数が「左×右」となるため、意図せず使うとデータが爆発的に増える点に注意が必要です。
SELECT e.FullName, p.ProductName
FROM dbo.Employees AS e
CROSS JOIN dbo.Products AS p;
意図的に使うケースとしては、カレンダーテーブルと商品リストを組み合わせて「販売予定表」を生成するなどがあります。
JOIN省略記法と注意点
旧来のSQLではFROM句でカンマ区切りにし、WHERE句で結合条件を書く方法がありました。
SELECT *
FROM dbo.Orders AS o, dbo.Customers AS c
WHERE o.CustomerId = c.CustomerId;
しかし、可読性と保守性の観点から、現在ではANSI JOIN構文(INNER/LEFTなど)を使用することが推奨されています。
複数テーブルを扱う際、カンマ区切り構文では誤結合(クロス結合化)のリスクが高くなります。
実務での注意点
- ON句とWHERE句の役割を明確に分ける:結合条件と抽出条件を混在させない。
- 多対多のJOINは重複行に注意:意図せず行数が増える場合は DISTINCT または集約を検討。
- インデックスを活用:結合キーにインデックスを付与するとパフォーマンスが向上。
- NULL比較の落とし穴:JOIN条件にNULLが絡む場合は IS NULL / IS NOT NULL を明示。
- 実行計画の確認:複雑なJOINはSQL Server Management Studioの実行計画で検証する。
実務課題と回答例
以下はJOINを理解するための練習課題です。
それぞれの構文を実際に書いて動作を確認してみましょう。
🔹 課題1:INNER JOINで顧客と注文を結合
-- 回答例
SELECT o.OrderId, c.FullName, o.OrderDate
FROM dbo.Orders AS o
INNER JOIN dbo.Customers AS c
ON o.CustomerId = c.CustomerId;
🔹 課題2:OUTER JOINで全顧客と注文を一覧化
-- 回答例
SELECT c.CustomerId, c.FullName, o.OrderId
FROM dbo.Customers AS c
LEFT JOIN dbo.Orders AS o
ON c.CustomerId = o.CustomerId
ORDER BY c.CustomerId;
🔹 課題3:アンチ結合で「注文がない顧客」を抽出
-- 回答例
SELECT c.CustomerId, c.FullName
FROM dbo.Customers AS c
LEFT JOIN dbo.Orders AS o
ON c.CustomerId = o.CustomerId
WHERE o.CustomerId IS NULL;
🔹 課題4:CROSS JOINで組み合わせを生成
-- 回答例
SELECT e.FullName, p.ProductName
FROM dbo.Employees AS e
CROSS JOIN dbo.Products AS p;
🔹 課題5:3テーブルをJOINして顧客・注文・商品を結合
-- 回答例
SELECT c.FullName, o.OrderId, p.ProductName, o.Quantity
FROM dbo.Customers AS c
INNER JOIN dbo.Orders AS o
ON c.CustomerId = o.CustomerId
INNER JOIN dbo.Products AS p
ON o.ProductId = p.ProductId;
まとめ
JOINを使いこなすことで、複数テーブルのデータを自由に組み合わせられます。
- INNER JOIN:共通データの取得
- LEFT / RIGHT OUTER JOIN:片側データを保持
- FULL OUTER JOIN:差分確認に利用
- CROSS JOIN:全組合せを生成
- アンチ結合:存在しないデータを抽出
- 結合条件はONに、絞り込みはWHEREに分けて記述することが重要です。
参考リンク

補足:JOIN構文はSQL Serverの全バージョンで共通して使用可能です。
結合数が多いクエリでは、実行計画の確認とインデックス設計がパフォーマンス最適化の鍵になります。
0 件のコメント:
コメントを投稿