パソナについて
記事検索

【SQL】JOINの種類や応用的な使い方について解説

SQLを用いてデータベースから情報を抽出する際、JOINを用いてテーブルを結合することがあります。本記事では、おもなJOINの種類や応用的な使い方について解説します。

【SQL】JOINの種類や応用的な使い方について解説

SQLを用いてデータベースから情報を抽出する際、JOINを用いてテーブルを結合することがあります。本記事では、おもなJOINの種類や応用的な使い方について解説します。

スキルアップ

2022/12/26 UP

SQLを用いてデータベースから情報を抽出する際、JOINを用いてテーブルを結合することがあります。本記事では、おもなJOINの種類や応用的な使い方について解説します。RDBMS(リレーショナルデータベース管理システム)にてデータを分析するのに必要な操作となるので、参考にしてください。

JOINとは

JOINとは複数のテーブルの行を条件によって結合する操作のことで、結合したテーブルから任意の情報を取得可能です。リレーショナルデータベースにおいて、テーブルを分けて情報の重複をなくした状態で保存することを正規化と呼びます。正規化によってデータの冗長性をなくし、一貫性のある状態で保存できることが利点です。

正規化された複数のテーブルからデータの確認や分析を行なうとき、JOINを用いてデータを連結します。テーブルにおいて、ある1つのレコードを特定できるカラムはプライマリーキー、他のテーブルの情報を特定するカラムは外部キーと呼ばれています。2つのテーブルのプライマリーキーと外部キーをJOINで結びつけると、一致する情報を同じレコードとして抽出できます。

本記事では、下記の商品データ(productテーブル)と明細データ(receiptテーブル)を用いて解説します。各データは以下のような内容です。

商品データ(productテーブル)

product_cd
(商品コード)
category_cd
(カテゴリコード)
unit_cost
(単価)
1001 2001 300
1002 2001 500
1003 2002 620
1004 2002 450
1005 2003 800
1006 2003 1020

明細データ(receiptテーブル)

receipt_cd
(明細コード)
sales_ymd
(販売日)
customer_id
(顧客ID)
product_cd
(製品コード)
quantity
(数量)
3001 20190422 CS906414 1001 10
3002 20190511 CS908457 1003 2
3003 20190823 CS928987 1005 1
3004 20191205 CS900321 1007 7
3005 20200406 CS900478 1003 5
3006 20201013 CS903119 1001 12
3007 20210625 CS909984 1002 9

JOIN の種類

おもなJOINの種類を5つ紹介します。選択するJOINによって2つのテーブルの結合の仕方が異なるため、違いを理解して使い分ける必要があります。

INNER JOIN:内部結合

INNER JOINは、指定した結合条件が両方のテーブルでマッチするレコードのみを返します。FROM内にてON句を用いて結合する条件を指定します。INNERは含めず、JOINのみ記載しても構いません。

下記のコードでは、productテーブルとreceiptテーブルを、product_cd(商品コード)が一致するという条件で内部結合しました。各テーブルはASを用いて別名(エイリアス名)を付けていることにご注意ください。SELECT内で出力するカラムを選択しています。

※サンプルコード

SELECT
 pr.*,
 re.receipt_cd,
 re.quantity
FROM product AS pr
INNER JOIN receipt AS re
 ON pr.product_cd = re.product_cd
product_cd category_cd unit_cost receipt_cd quantity
1 1001 2001 300 3001 10
2 1001 2001 300 3006 12
3 1002 2001 500 3007 9
4 1003 2002 620 3002 2
5 1003 2002 620 3005 5
6 1005 2003 800 3003 1

INNER JOINを用いると、2つのテーブルで共通するproduct_cd(商品コード)である1001、1002、1003、1005の4つのレコードを抽出されました。

LEFT (OUTER) JOIN:左外部結合

LEFT JOINは、左テーブルのレコードすべてと、結合条件にマッチする右テーブルのレコードを返します。「左テーブル LEFT JOIN 右テーブル」のように記述し、OUTERは省略可能です。基準となるテーブルに、別のテーブルから情報を追加するという使い方ができます。右テーブルのレコードで結合条件にマッチしない場合はNULLが返されます。

以下のコードでは、productテーブルを左、receiptテーブルを右として、product_cd(商品コード)のデータをもとに左外部結合しました。

※サンプルコード

SELECT
 pr.*,
 re.receipt_cd,
 re.quantity
FROM product AS pr
LEFT JOIN receipt AS re
 ON pr.product_cd = re.product_cd
product_cd category_cd unit_cost receipt_cd quantity
1 1001 2001 300 3001 10
2 1001 2001 300 3006 12
3 1002 2001 500 3007 9
4 1003 2002 620 3002 2
5 1003 2002 620 3005 5
6 1004 2002 450 null null
7 1005 2003 800 3003 1
8 1006 2003 1020 null null

左側のproductテーブルにはproduct_cd(商品コード)が1001~1006まで1レコードずつあり、すべて抽出されています。一方で右側のreceiptテーブルのレコードには1004や1006のレコードが含まれていません。receiptテーブルが持っているreceipt_cd(明細コード)やquantity(数量)のデータには、nullと表示されています。

RIGHT (OUTER) JOIN:右外部結合

RIGHT JOINとは、LEFT JOINの左右の関係を逆にしたものです。わかりづらくなるためLEFT JOINに統一することが多く、RIGHT JOINは使用頻度が低いといえるでしょう。「左テーブル RIGHT JOIN 右テーブル」のように記述したとき、右テーブルのレコードすべてと、結合条件にマッチする左テーブルのレコードを返します。

※サンプルコード

SELECT
 pr.*,
 re.receipt_cd,
 re.quantity
FROM product AS pr
RIGHT JOIN receipt AS re
 ON pr.product_cd = re.product_cd
product_cd category_cd unit_cost receipt_cd quantity
1 1001 2001 300 3001 10
2 1001 2001 300 3006 12
3 1002 2001 500 3007 9
4 1003 2002 620 3002 2
5 1003 2002 620 3005 5
6 1005 2003 800 3003 1
7 null null null 3004 7

右側のreceiptテーブルに含まれるproduct_cd(商品コード)の値をもとに、右外部結合しています。receiptテーブルのproduct_cdに含まれる1001、1002、1003、1005のレコードが抽出されています。

7行目はreceiptテーブルにおけるproduct_cdが1007のレコードに該当しますが、抽出結果ではnullと表示されました。なぜならSELECT内では、「pr.*」のようにproductテーブルに含まれるproduct_cdを表示するよう指定していたので、productテーブルに含まれないデータは表示されないためです。

FULL (OUTER) JOIN:完全外部結合

左右のテーブルにおいて、指定した結合条件にマッチしないレコードも含めたすべてのレコードを抽出します。条件にマッチしなくても、テーブルが保有する全レコードの情報を表示して欲しい場合に使用するとよいでしょう。

※サンプルコード

SELECT
 pr.*,
 re.receipt_cd,
 re.quantity
FROM product AS pr
FULL JOIN receipt AS re
 ON pr.product_cd = re.product_cd
product_cd category_cd unit_cost receipt_cd quantity
1 1004 2002 450 null null
2 1003 2002 620 3002 2
3 1003 2002 620 3005 5
4 1005 2003 800 3003 1
5 1001 2001 300 3001 10
6 1001 2001 300 3006 12
7 1006 2003 1020 null null
8 1002 2001 500 3007 9
9 null null null 3004 7

上記のコードの結果ですが、ON句で指定した条件とマッチしなかったレコードも表示されています。9行目がproductテーブルでマッチしなかったレコードで、1と7行目がreceiptテーブルでマッチしなかったレコードです。テーブル内に該当するレコードが見つからないときはnullと表記しています。

JOINの応用

JOINの基本的な使い方について解説しましたが、保存されているテーブルの関係によっては、これまでの方法では対応できないことがあります。JOINの応用的な使い方について紹介します。

複数の結合条件がある場合

結合条件はON句で指定しますが、結合条件が複数ある場合はAND演算子で条件式をつなげることができます。データの抽出条件を細かく指定したい場合や、テーブルの持つプライマリーキーが2カラム以上ある場合などに使用するとよいでしょう。ON句にはAND以外にもORやNOTなど任意の条件式が使えます。

以下のコードでは、INNER JOINでproductテーブルとreceiptテーブルを内部結合する際の条件を2つ指定しました。product_cd(商品コード)の一致と、category_cd(カテゴリコード)が2001という条件です。

※サンプルコード

SELECT‘
 pr.*,
 re.receipt_cd,
 re.quantity
FROM product AS pr
INNER JOIN receipt AS re
 ON pr.product_cd = re.product_cd
 AND category_cd = 2001
product_cd category_cd unit_cost receipt_cd quantity
1 1001 2001 300 3001 10
2 1001 2001 300 3006 12
3 1002 2001 500 3007 9

出力されたテーブルはINNER JOINによる内部結合した結果から、さらにcategory_cdが2001のレコードのみを抽出しています。

複数のテーブルを結合する場合

あるテーブルが外部キーを複数持つとき、欲しい情報が3つ以上のテーブルに分かれていることがあります。その場合は3つ以上のテーブルをすべて結合する必要がありますが、JOINを複数並べて結合できます。今回は3つ目のテーブルとして、商品のカテゴリ名を記したcategoryテーブルを用意しました。

category_cd
(カテゴリコード)
category_name
(カテゴリ名)
2001 meat
2002 vegetable
2003 fruit

以下のコードでは、INNER JOINを2回用いてproductテーブルにreceiptテーブルとcategoryテーブルを結合しています。ON句による結合条件の指定も追加することを忘れないようにしてください。SELECTにて、categoryテーブル内にあるcategory_name(カテゴリ名)も表示するよう指定しています。

※サンプルコード

SELECT
 pr.*,
 re.receipt_cd,
 re.quantity,
 ca.category_name
FROM product AS pr
INNER JOIN receipt AS re
 ON pr.product_cd = re.product_cd
INNER JOIN category AS ca
 ON pr.category_cd = ca.category_cd
product_cd category_cd unit_cost receipt_cd quantity category_name
1 1001 2001 300 3001 10 meat
2 1001 2001 300 3006 12 meat
3 1002 2001 500 3007 9 meat
4 1003 2002 620 3002 2 vegetable
5 1003 2002 620 3005 5 vegetable
6 1005 2003 800 3003 1 fruit

JOINの使い方のヒント

ここまでJOINの使い方について解説しましたが、合わせて覚えておくと役立つ方法や注意点を紹介します。

テーブル名の指定

JOINで複数のテーブルを結合するとき、同じ名称のカラムがあると、どちらのテーブルのものか判別ができません。カラム名を記載するときは、「テーブル名.カラム名」のようにテーブル名を明示する必要があります。可読性を考えると、カラム名が重複していなくても常にテーブル名も明示するとよいでしょう。

またテーブル名にはASを使ってエイリアス名を付けるのがおすすめです。「product AS pr」のように記載すると、productテーブルに「pr」というエイリアス名を付けられます。ほかの箇所では「pr」のみでテーブルを指定できるため、特にテーブル名が長い場合にはコードの記述量を大きく減らせます。

テーブル名を指定する際にデータベース名を合わせて指定する場合もあります。「データベース名.テーブル名」と記載する必要があり、毎回書くのは大変になるでしょう。その場合もエイリアス名を設定しておくと便利です。

USING

ここまではON句で結合条件を指定していましたが、USINGを用いると簡略的に表記できます。以下に示した例は、ON句で記載した結合条件についてUSINGを用いて記載しています。テーブル名を省略してカラム名のみ記載する形になるので、記述量を省略できます。

ON pr.product_cd = re.product_cd
↓
USING(product_cd)

複数の条件式を指定したい場合は、カラム名をカンマで区切って並べることで実行できます。下記の例では、product_cd1、product_cd2という2つの商品コード列を持つテーブルを結合したと想定しています。

ON pr.product_cd1 = re.product_cd1 AND pr.product_cd2 = product_cd2
↓
USING(product_cd1, product_cd2)

ただし、USINGは利用するリレーショナルデータベース管理システムによっては利用できずエラーになる場合もあるのでご注意ください。

JOINで複数のテーブルから情報を抽出

リレーショナルデータベース管理システムで正規化されたテーブルから情報を抽出するとき、JOINを用いてテーブル同士を結合します。データの分析において、JOINは必須の操作となるでしょう。

内部結合や外部結合などさまざまな結合方法があるため、各結合の違いを理解して用途に応じて使い分けるようにしてください。複数の条件を指定してテーブルを結合したり、3つや4つなど複数のテーブルを結合したりも可能です。JOINを使いこなせるようになると、データベースから必要な情報のみ抽出できるため、効率的なデータ分析が可能となるでしょう。