第10章 サブクエリ

サブクエリとは

サブクエリ(または副問い合わせ)は、SQLステートメントの内部に埋め込まれたSQLクエリです。サブクエリは主要なSQLステートメントの一部として実行され、主要なクエリが必要とするデータを提供します。サブクエリはFROM、WHERE、またはSELECTステートメント内に配置することができます。

以下に具体的な例を示します。まず、次のような2つのテーブルを定義します。

Employeesテーブルを作成します。

CREATE TABLE Employees (
    EmployeeID int,
    Name varchar(255),
    Salary int,
    DepartmentID int
);

INSERT INTO Employees (EmployeeID, Name, Salary, DepartmentID)
VALUES (1, 'John', 2000, 1), (2, 'Sarah', 3000, 2), (3, 'Tom', 4000, 2), (4, 'Alice', 5000, 3);

Departmentsテーブルを作成します。

CREATE TABLE Departments (
    DepartmentID int,
    DepartmentName varchar(255)
);

INSERT INTO Departments (DepartmentID, DepartmentName)
VALUES (1, 'Sales'), (2, 'Marketing'), (3, 'Accounting');

これで、テーブルとデータが用意できました。


サブクエリの例

これらのテーブルを用いて、マーケティング部門に所属する従業員の名前を取得したいとしましょう。以下のようにサブクエリを使用します

SELECT Name FROM Employees
WHERE DepartmentID = 
    (SELECT DepartmentID FROM Departments WHERE DepartmentName = 'Marketing');

このクエリの中にあるサブクエリ(SELECT DepartmentID FROM Departments WHERE DepartmentName = 'Marketing')は、マーケティング部門のIDを取得します。そして、そのIDはメインクエリのWHERE句で使用され、マーケティング部門に所属する従業員の名前を取得します。

このクエリを実行すると、以下の結果が得られます。

+-------+
| Name  |
+-------+
| Sarah |
| Tom   |
+-------+


FROM句での使用

サブクエリはFROM句の中で使用することもでき、一時的なテーブルを作成して、それに対して操作を行うことが可能です。この一時的なテーブルは、元のクエリが完了すると同時に消滅します。

このクエリでは、サブクエリを使用して一時的に部門1の従業員の給与についてのテーブルを作成し、その平均給与を計算しています。

SELECT AVG(Salary)
FROM (SELECT Salary FROM Employees WHERE DepartmentID = 1) AS Department1Employees;
+-------------+
| AVG(Salary) |
+-------------+
|   2000.0000 |
+-------------+


複数行を返すサブクエリ

サブクエリは一般的に一つの値を返しますが、複数の行を返すことも可能です。その場合、INやANY、ALLなどの演算子と一緒に使われます。

このクエリでは、部門名が'Sales'または'Marketing'である部門のIDをサブクエリが返し、それに基づいて従業員の名前が選択されます。

SELECT Name
FROM Employees
WHERE DepartmentID IN (SELECT DepartmentID FROM Departments WHERE DepartmentName IN ('Sales', 'Marketing'));
+-------+
| Name  |
+-------+
| John  |
| Sarah |
| Tom   |
+-------+


ネストされたサブクエリ

サブクエリはさらにネスト(入れ子に)することができます。つまり、サブクエリ内部にさらにサブクエリを書くことが可能です。ただし、ネストが深くなるほどクエリは複雑になり、理解やデバッグが難しくなるため、適切な使用が求められます。

このクエリでは、Sales部門の平均給与よりも多く給与を受け取っている従業員の名前を選択しています。部門名からIDを検索するためのサブクエリがネストされています。

SELECT e.Name
FROM Employees e
WHERE Salary > (
    SELECT AVG(Salary) 
    FROM Employees
    WHERE DepartmentID = (
        SELECT DepartmentID 
        FROM Departments
        WHERE DepartmentName = 'Sales'
    )
);

+-------+
| Name  |
+-------+
| Sarah |
| Tom   |
| Alice |
+-------+


サブクエリは複雑な問い合わせを行う際に非常に有用です。特定の条件を満たすレコードを探す、あるいは複数のテーブルから特定のデータを抽出する場合などに使用されます。サブクエリを使用する際は、クエリが複雑になりがちなので注意が必要です。