SQLのJOIN・サブクエリ・集計関数を身につける
前回は初級編としてデータベースの基本からSQLの基礎まで書いたので、
今回は、少し高度なSQLを中心に紹介します。
ジョイン(JOIN)
ジョイン(JOIN)
ジョインは、複数のテーブルから関連するデータを結合して取得する方法です。
以下のタイプのジョインがあります。
よく使うのは、INNER JOIN 、LEFT JOIN です。
ジョインタイプ | 説明 |
---|---|
INNER JOIN | 両方のテーブルに存在するデータのみを取得します。 |
LEFT JOIN | 左のテーブルの全てのデータと、右のテーブルに一致するデータを取得します。 右のテーブルに一致するデータがない場合はNULLが表示されます。 |
RIGHT JOIN | 右のテーブルの全てのデータと、左のテーブルに一致するデータを取得します。 左のテーブルに一致するデータがない場合はNULLが表示されます。 |
FULL OUTER JOIN | 両方のテーブルの全てのデータを取得します。 一致するデータがない場合はNULLが表示されます。 |
CROSS JOIN | 両方のテーブルの全ての組み合わせを取得します。 |
INNER JOIN
両方のテーブルに存在する共通のデータのみを取得します。
基本形:
SELECT カラム名1, カラム名2, ...
FROM テーブル1
INNER JOIN テーブル2 ON テーブル1.カラム名 = テーブル2.カラム名;
以下の例では、orders
テーブルと customers
テーブルを結合し、注文と対応する顧客の名前を取得します。
両方のテーブルに存在するデータのみを取得するため、NULL
のデータのレコードは削除されてしまいます。
クエリ:
SELECT orders.order_id, customers.customer_name
FROM orders
INNER JOIN customers ON orders.customer_id = customers.customer_id;
実行前のテーブル (orders
):
order_id | customer_id | order_date |
---|---|---|
1 | 101 | 2024-01-01 |
2 | 102 | 2024-01-02 |
3 | 103 | 2024-01-03 |
実行前のテーブル (customers
):
customer_id | customer_name |
---|---|
101 | Alice |
103 | Carol |
(↑customer_id
102が存在しない = NULL
)
実行結果:
order_id | customer_name |
---|---|
1 | Alice |
4 | Carol |
LEFT JOIN
左のテーブルの全てのデータと、右のテーブルに一致するデータを取得します。
右のテーブルに一致するデータがない場合はNULL
が表示されます。
ちなみに、LEFT JOIN
における「左のテーブル」とは、JOIN 句の前に記述されたテーブルのことを指します。
(以下の例では、orders
)
基本形:
SELECT カラム名1, カラム名2, ...
FROM テーブル1
LEFT JOIN テーブル2 ON テーブル1.カラム名 = テーブル2.カラム名;
以下の例では、orders
テーブルの全ての注文と、それに対応する顧客の名前を取得します。
対応する顧客がいない場合はNULL
を表示します。
クエリ:
SELECT orders.order_id, customers.customer_name
FROM orders
LEFT JOIN customers ON orders.customer_id = customers.customer_id;
実行前のテーブル (orders
):
order_id | customer_id | order_date |
---|---|---|
1 | 101 | 2024-01-01 |
2 | 102 | 2024-01-02 |
3 | 103 | 2024-01-03 |
実行前のテーブル (customers
):
customer_id | customer_name |
---|---|
101 | Alice |
103 | Carol |
(↑customer_id
102が存在しない = NULL
)
実行結果:
order_id | customer_name |
---|---|
1 | Alice |
2 | NULL |
3 | Carol |
RIGHT JOIN
右のテーブルの全てのデータと、左のテーブルに一致するデータを取得します。左のテーブルに一致するデータがない場合はNULL
が表示されます。
基本形:
SELECT カラム名1, カラム名2, ...
FROM テーブル1
RIGHT JOIN テーブル2 ON テーブル1.カラム名 = テーブル2.カラム名;
以下の例では、customers
テーブルの全ての顧客と、それに対応する注文を取得します。
対応する注文がない場合はNULL
を表示します。
クエリ:
SELECT orders.order_id, customers.customer_name
FROM orders
RIGHT JOIN customers ON orders.customer_id = customers.customer_id;
実行前のテーブル (orders
):
order_id | customer_id | order_date |
---|---|---|
1 | 101 | 2024-01-01 |
3 | 103 | 2024-01-03 |
(↑order_id
2が存在しない = NULL
)
実行前のテーブル (customers
):
customer_id | customer_name |
---|---|
101 | Alice |
102 | Bob |
103 | Carol |
実行結果:
order_id | customer_name |
---|---|
1 | Alice |
NULL | Bob |
3 | Carol |
FULL OUTER JOIN
両方のテーブルの全てのデータを取得します。一致するデータがない場合はNULL
が表示されます。
基本形:
SELECT カラム名1, カラム名2, ...
FROM テーブル1
FULL OUTER JOIN テーブル2 ON テーブル1.カラム名 = テーブル2.カラム名;
以下の例では、全ての注文と全ての顧客のデータを取得し、対応しない場合はNULL
を表示します。
クエリ:
SELECT orders.order_id, customers.customer_name
FROM orders
FULL OUTER JOIN customers ON orders.customer_id = customers.customer_id;
この FULL OUTER JOIN
のクエリ実行結果を得るためには、orders
テーブルと customers
テーブルの内容が以下のようになっている必要があります。
実行前のテーブル (orders
):
order_id | customer_id | order_date |
---|---|---|
1 | 101 | 2024-01-01 |
2 | 102 | 2024-01-02 |
3 | 104 | 2024-01-03 |
4 | 101 | 2024-01-04 |
実行前のテーブル (customers
):
customer_id | customer_name |
---|---|
101 | Alice |
102 | Bob |
103 | Carol |
実行結果:
order_id | customer_name |
---|---|
1 | Alice |
2 | Bob |
3 | NULL |
4 | Alice |
NULL | Carol |
CROSS JOIN
CROSS JOIN は、2つのテーブルのすべての組み合わせを取得します。
これにより、片方のテーブルの行数にもう片方のテーブルの行数を掛けた結果が得られます。
あまり使う機会はないですが、こういうこともできるんだなと程度で覚えておくと良いです。
(全ての組み合わせを生成するので、結果の行数が膨大になって、パフォーマンスに悪影響を及ぼす可能性があります。)
クエリ:
SELECT orders.order_id, customers.customer_name
FROM orders
CROSS JOIN customers;
実行前のテーブル (orders
):
order_id | customer_id | order_date |
---|---|---|
1 | 101 | 2024-01-01 |
2 | 102 | 2024-01-02 |
3 | 105 | 2024-01-03 |
実行前のテーブル (customers
):
customer_id | customer_name |
---|---|
101 | Alice |
102 | Bob |
103 | Carol |
orders
テーブルには 3 行、customers
テーブルには 3 行あります。
この場合、CROSS JOIN
を実行すると、結果は 3 × 3 = 9 行になります。
実行結果:
order_id | customer_name |
---|---|
1 | Alice |
1 | Bob |
1 | Carol |
2 | Alice |
2 | Bob |
2 | Carol |
3 | Alice |
3 | Bob |
3 | Carol |
サブクエリ(Subquery)
サブクエリは、クエリの内部で他のクエリを使用する方法です。
これにより、より複雑なデータの抽出が可能となり、複数のクエリを組み合わせて条件を設定することができます。
サブクエリもよく使うことになると思います。
(余談ですが、サブクエリは、副問合せって言ったりもします)
サブクエリの基本形
サブクエリは、メインクエリのSELECT
、FROM
、WHERE
などの節の中で使用できます。
特にWHERE
節で使用される場合が多く、ある条件を満たすデータを絞り込む際に便利です。
基本形:
SELECT カラム名1, カラム名2, ...
FROM テーブル名
WHERE カラム名 IN (SELECT サブクエリのカラム名 FROM サブクエリのテーブル名 WHERE 条件);
サブクエリの例
以下の例では、orders
テーブルで2024年1月1日以降に注文した顧客のcustomer_id
を取得し、その顧客のcustomer_id
とcustomer_name
をcustomers
テーブルから取得します。
クエリ:
SELECT customer_id, customer_name
FROM customers
WHERE customer_id IN (SELECT customer_id FROM orders WHERE order_date > '2024-01-01');
実行前のテーブル (customers
):
customer_id | customer_name |
---|---|
101 | Alice |
102 | Bob |
103 | Carol |
104 | Dave |
実行前のテーブル (orders
):
order_id | customer_id | order_date |
---|---|---|
1 | 101 | 2024-01-01 |
2 | 102 | 2024-01-02 |
3 | 103 | 2023-12-31 |
4 | 101 | 2024-01-03 |
実行結果:
customer_id | customer_name |
---|---|
101 | Alice |
102 | Bob |
集計関数
集計関数は、データを特定のグループごとに集計し、各グループに対して統計的な情報を計算するためのものです。これにより、データの要約や全体的な傾向を把握することができます。
代表的な集計関数
関数 | 説明 |
---|---|
COUNT() | グループ内の行数を数えます。 |
SUM() | グループ内の特定カラムの合計を計算します。 |
AVG() | グループ内の特定カラムの平均を計算します。 |
MIN() | グループ内の特定カラムの最小値を取得します。 |
MAX() | グループ内の特定カラムの最大値を取得します。 |
集計関数の基本使用方法
集計関数は、通常SELECT
文とGROUP BY
句を組み合わせて使用します。
GROUP BY
句は、どのカラムでデータをグループ化するかを指定し、各グループに対して集計処理を行います。
基本構文:
SELECT グループ化するカラム, 集計関数(カラム名) AS 別名, ...
FROM テーブル名
GROUP BY グループ化するカラム;
集計関数の使用例
以下の例では、employees
テーブルを使用して、各部署ごとの従業員数、給与の合計、平均給与、最小給与、最大給与を取得します。
クエリ:
SELECT department,
COUNT(*) AS num_employees,
SUM(salary) AS total_salary,
AVG(salary) AS avg_salary,
MIN(salary) AS min_salary,
MAX(salary) AS max_salary
FROM employees
GROUP BY department;
実行前のテーブル (employees
):
id | name | department | salary |
---|---|---|---|
1 | Alice | Sales | 5000 |
2 | Bob | HR | 4000 |
3 | Carol | Sales | 5500 |
4 | Dave | IT | 6000 |
5 | Eve | IT | 6500 |
6 | Frank | HR | 4200 |
実行結果:
department | num_employees | total_salary | avg_salary | min_salary | max_salary |
---|---|---|---|---|---|
Sales | 2 | 10500 | 5250 | 5000 | 5500 |
HR | 2 | 8200 | 4100 | 4000 | 4200 |
IT | 2 | 12500 | 6250 | 6000 | 6500 |
Discussion