スカラーまたは複数値のサブクエリを使用する
スカラー サブクエリとは、外側のクエリの内側の SELECT ステートメントが、単一の値を返すように記述されているものです。 スカラー サブクエリは、SELECT 句、WHERE 句、HAVING 句、さらには FROM 句など、単一値式が許可される外側の T-SQL ステートメント内の任意の場所で使用できます。 UPDATE や DELETE などのデータ変更ステートメントでも使用できます。
複数値サブクエリとは、名前が示すように、複数の行を返すことができます。 ただし、返される列は 1 つのままです。
スカラー サブクエリ
SalesOrderID 値が最も高い注文であることを前提として、最後に注文された注文の詳細を取得するとします。
最高の SalesOrderID 値を検索するには、次のクエリを使用します。
SELECT MAX(SalesOrderID)
FROM Sales.SalesOrderHeader
このクエリは、SalesOrderHeader テーブルの OrderID の最大値を示す 1 つの値を返します。
この注文の詳細を取得するには、上記のクエリによって返される値に基づいて SalesOrderDetails テーブルをフィルター処理することが必要になる場合があります。 このタスクを達成するには、注文の詳細を取得するクエリの WHERE 句内に、最大の SalesOrderID を取得するための入れ子クエリを使用します。
SELECT SalesOrderID, ProductID, OrderQty
FROM Sales.SalesOrderDetail
WHERE SalesOrderID =
(SELECT MAX(SalesOrderID)
FROM Sales.SalesOrderHeader);
スカラー サブクエリを記述するには、次のガイドラインを考慮してください。
- クエリをサブクエリとして示すには、それをかっこで囲みます。
- Transact-SQL では、複数レベルのサブクエリがサポートされています。 このモジュールでは、2 レベルのクエリ (1 つの外側のクエリ内に 1 つの内側のクエリ) のみを検討しますが、最大で 32 レベルまでサポートされています。
- サブクエリが行を返さない場合 (空のセット)、サブクエリの結果は NULL になります。 ご自分のシナリオで行が返されない可能性がある場合は、他の予期される結果に加えて、外側のクエリが NULL を適切に処理できるように保証する必要があります。
- 通常、内側のクエリは単一の列を返す必要があります。 サブクエリ内で複数の列を選択すると、ほとんどの場合、エラーになります。 唯一の例外は、EXISTS キーワードを使用してサブクエリを導入した場合です。
スカラー サブクエリは、SELECT リストなど、値が期待されるクエリ内の任意の場所で使用できます。 たとえば、最新の注文の詳細を取得したクエリを、注文された品目の平均数量を含むように拡張できます。これにより、最新の注文で注文された数量とすべての注文の平均を比較できます。
SELECT SalesOrderID, ProductID, OrderQty,
(SELECT AVG(OrderQty)
FROM SalesLT.SalesOrderDetail) AS AvgQty
FROM SalesLT.SalesOrderDetail
WHERE SalesOrderID =
(SELECT MAX(SalesOrderID)
FROM SalesLT.SalesOrderHeader);
複数値サブクエリ
複数値サブクエリは、IN 演算子を使用して結果を返すのに適しています。 次の仮定の例では、カナダの顧客によって行われたすべての注文の CustomerID、 SalesOrderID 値を返します。
SELECT CustomerID, SalesOrderID
FROM Sales.SalesOrderHeader
WHERE CustomerID IN (
SELECT CustomerID
FROM Sales.Customer
WHERE CountryRegion = 'Canada');
この例では、内部クエリのみを実行する場合は、 CustomerID 値の列が返され、カナダの顧客ごとに 1 行が返されます。
多くの場合、複数値サブクエリは結合を使用して簡単に記述できます。 たとえば、結合を使用して前の例と同じ結果を返すクエリを次に示します。
SELECT c.CustomerID, o.SalesOrderID
FROM Sales.Customer AS c
JOIN Sales.SalesOrderHeader AS o
ON c.CustomerID = o.CustomerID
WHERE c.CountryRegion = 'Canada';
そうすると、複数のテーブルが関係するクエリを JOIN として記述するのか、それともサブクエリを使用するのかは、どのように決めるのでしょうか。 場合によっては、単にどちらの方が使いやすいかによって決めます。 入れ子になったクエリのほとんどは、JOIN に簡単に変換され、実際、内部的に JOIN に変換されることになります。 このようなクエリの場合は、どちらの方法で記述しても実質的に違いはありません。
留意すべき 1 つの制限が、入れ子になったクエリを使用する場合、クライアントに返される結果に含めることができるのは外側のクエリの列のみであるということです。 そのため、両方のテーブルから列を返す必要がある場合は、JOIN を使用してクエリを記述する必要があります。
最後に、内側のクエリで、この例のシンプルな取得よりもはるかに複雑な操作を実行する必要がある状況があります。 JOIN を使用する複雑なサブクエリの書き換えは難しい場合があります。 サブクエリは、処理をより小さなステップに分解できるため、多くの SQL 開発者が、複雑な処理に最適であると考えています。