🙆

SQLのJOIN・サブクエリ・集計関数を身につける

2024/09/03に公開

前回は初級編としてデータベースの基本からSQLの基礎まで書いたので、
今回は、少し高度なSQLを中心に紹介します。

データベース基礎とSQL入門学んで基礎固め

ジョイン(JOIN)

ジョイン(JOIN)
ジョインは、複数のテーブルから関連するデータを結合して取得する方法です。
以下のタイプのジョインがあります。
よく使うのは、INNER JOINLEFT 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_id102が存在しない = 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_id102が存在しない = 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_id2が存在しない = 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)

サブクエリは、クエリの内部で他のクエリを使用する方法です。
これにより、より複雑なデータの抽出が可能となり、複数のクエリを組み合わせて条件を設定することができます。
サブクエリもよく使うことになると思います。
(余談ですが、サブクエリは、副問合せって言ったりもします)

サブクエリの基本形

サブクエリは、メインクエリのSELECTFROMWHEREなどの節の中で使用できます。
特にWHERE節で使用される場合が多く、ある条件を満たすデータを絞り込む際に便利です。

基本形:

SELECT カラム名1, カラム名2, ...
FROM テーブル名
WHERE カラム名 IN (SELECT サブクエリのカラム名 FROM サブクエリのテーブル名 WHERE 条件);

サブクエリの例

以下の例では、orders テーブルで2024年1月1日以降に注文した顧客のcustomer_idを取得し、その顧客のcustomer_idcustomer_namecustomersテーブルから取得します。

クエリ:

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