SELECT文の総仕上げはサブクエリ:さらっと覚えるSQL&T-SQL入門(7)
アプリケーション開発でデータベースを利用する新人プログラマに向けて、SQLおよびT-SQLを短期間で理解できるよう、開発現場ですぐに必要となる内容を中心に解説する。(編集部)
主な内容
▼サブクエリとは
▼複数の結果を返すサブクエリ
▼サブクエリのさまざまな場所での利用
▼まとめ
初回から7回にわたってSELECT文の利用法を取り上げてきましたが、それも今回でとうとう最後となります。今回取り上げるのは、SQL文の中にSELECT句を入れ子にして埋め込む「サブクエリ」です。
サブクエリとは
サブクエリは「副問い合わせ」とも呼ばれ、SQL文の中にSELECT文を埋め込み、抽出条件として利用することを可能としています。これまで、テーブルからデータを抽出するためにWHERE句による絞り込みやJOIN句による結合を利用してきましたが、サブクエリはその応用といえる存在です。
では、次のような例を見てみましょう。
SELECT ProductID FROM Production.Product WHERE Name = 'Chain' 結果 ProductID ------------- 952
このSQL文は、特定の名前に対する商品IDを求めている単純な問い合わせです。続いてこの条件をそのままに、商品テーブルと受注明細テーブルを結合させ、特定の商品に対する受注の一覧を調べるSQL文は次のような形になります。
SELECT SalesOrderID FROM Sales.SalesOrderDetail AS SOD INNER JOIN Production.Product AS Pdt ON SOD.ProductID = Pdt.ProductID WHERE Pdt.Name = 'Chain' 結果 SalesOrderID ------------- 51083 51084 51090 …中略… 71952
このようなSQLを発行する場合、サブクエリを利用すれば同じ結果をよりシンプルに得られます。それでは、まずはサブクエリの簡単な構文から見てみましょう。
SELECT 列名 FROM テーブル名
WHERE 列名 演算子 (サブクエリ)
WHERE句にて、列に対する条件式としてサブクエリを使用しています。通常、WHERE句に使う条件としては、数値や文字列といった何らかの値を利用しますが、サブクエリを利用することにより、SELECT文の結果を条件として利用できます。
先ほど取り上げた商品テーブルと商品明細テーブルを結合させたSQL文について、同じ結果をサブクエリで求めてみましょう。
SELECT SalesOrderID FROM Sales.SalesOrderDetail WHERE ProductID = (SELECT ProductID FROM Production.Product WHERE Name = 'Chain') 結果 SalesOrderID ------------- 51083 51084 51090 …中略… 71952
WHERE句にて「ProductID」列に対する条件として、冒頭で取り上げた商品マスタに対するSELECT文がサブクエリとして埋め込まれています。このように、サブクエリを利用することにより、SELECT文の結果を利用した抽出を行うことが可能です。
複数の結果を返すサブクエリ
サブクエリとしてSELECT文を記述する際、単一の結果を返すSELECT文と複数行にわたる結果を返すSELECT文が存在します。単一の結果であれば、先ほど取り上げたようなイコール、大小といった条件式を利用できます。しかし、サブクエリの結果が複数行となる場合はこのような条件式は利用できず、「条件のいずれかと一致する」を意味する「IN」句を利用する必要があります。具体的な例を見てみましょう。
SELECT ProductID FROM Production.Product WHERE ProductModelID = 21 結果 ProductID ------------- 785 786 787 788
このSELECT文は複数の結果を返します。このようなSELECT文をサブクエリとして埋め込む場合、IN句を利用した次のような構成となります。
SELECT SalesOrderID FROM Sales.SalesOrderDetail WHERE ProductID IN (SELECT ProductID FROM Production.Product WHERE ProductModelID = 21) 結果 SalesOrderID ------------- 46608 46610 46611 …中略… 50756
サブクエリとして指定したSELECT文は複数の結果を返しますが、そのいずれかに一致するデータが抽出されていることが分かります。JOINを利用した結合でもまったく同じ結果を得られますが、サブクエリを利用した方が構成が分かりやすく記述も容易です。
サブクエリのさまざまな場所での利用
ここまで取り上げたサブクエリはWHERE句で利用してきましたが、サブクエリはWHERE句だけでなくさまざまな場所でも利用可能です。ここでは、代表的な利用方法であるSELECT句とFROM句での利用を取り上げます。
SELECT句でのサブクエリの利用
WHERE句でサブクエリを利用する場合、サブクエリの結果を取得することはできず、WHERE句にて条件式として利用するだけでした。一方、SELECT句でサブクエリを利用する場合、メインクエリの結果としてサブクエリの結果を取得できます。具体的な例を見てみましょう。
SELECT CustomerID,COUNT(*) AS Cnt_Cust, (SELECT COUNT(*) FROM Sales.SalesOrderHeader) AS Cnt_All FROM Sales.SalesOrderHeader GROUP BY CustomerID 結果 CustomerID Cnt_Cust Cnt_All ----------------------------------------- 1 4 31465 2 8 31465 3 12 31465 …中略… 29483 1 31465
この例では、顧客ごとの受注件数と全体の受注件数の差異を確認できます。単一のSELECT文で、グループ化された結果と全体の結果を同時に得ることはできませんが、サブクエリを組み合わせることで、このような性格の異なる値を同時に取得することが可能です。
また、SELECT句で利用するサブクエリでは、メインクエリから列値を渡すことによって、関数のような動きをさせることが可能です。次の例ではメインクエリから受注番号を受け取り、その明細行数を結果として出力しています。
SELECT SOH.SalesOrderID, (SELECT COUNT(*) FROM Sales.SalesOrderDetail AS SOD WHERE SOD.SalesOrderID = SOH.SalesOrderID ) AS Cnt_Detail FROM Sales.SalesOrderHeader SOH 結果 SalesOrderID Cnt_Detail --------------------------- 43659 12 43660 2 43661 15 …中略… 75123 3
FROM句でのサブクエリの利用
FROM句でのサブクエリの利用は、これまでのサブクエリと性格が異なります。WHERE句、SELECT句でのサブクエリはあくまで結果として値を利用していました。これがFROM句での利用では、サブクエリの結果を1つのテーブルとして扱うことが可能となります。FROM句でのサブクエリの利用は非常に応用性が高く、サブクエリの主だった利用目的はこのFROM句での利用にあるといえるほどです。それでは、早速サンプルを見てみましょう。
SELECT AVG(Cnt_Detail) AS AVG_Detail FROM (SELECT COUNT(*) AS Cnt_Detail FROM Sales.SalesOrderDetail GROUP BY SalesOrderID ) AS SOD 結果 AVG_Detail ---------- 3
まず、FROM句で指定したサブクエリでは、受注明細テーブルから受注ごとの明細件数を計算し、これを1つのテーブルとして返しています。
さらに、このテーブルから取り出した値から平均受注明細数を求めています。これまで取り上げてきたSQLでは集計関数を組み合わせた計算は不可能でしたが、サブクエリを使うことによって可能となりました。
このように、サブクエリをFROM句にて指定することで結果をあたかも1つのテーブルとして扱うことが可能であり、多様な表現を簡単に行うことができます。
まとめ
今回はSELECT文に関する記事としては最終回ということで、サブクエリを取り上げました。これまでWHERE句による絞り込みやGROUP BYによるグループ化、関数の利用、テーブルの結合など、さまざまな構文を取り上げてきましたが、サブクエリは最後に取り上げるのにふさわしい応用的な内容となっています。その利用範囲は非常に広く、これまでの構文では不可能だった柔軟な表現が可能です。サンプルデータベースを利用して、サブクエリの動きや応用、テーブル結合との組み合わせなど、その動作を確認しておきましょう。
次回はデータの登録・更新・削除を行う、INSERT、UPDATE、DELETE文を取り上げます。お楽しみに!(次回へ続く)
筆者プロフィール
石橋潤一
株式会社システムインテグレータ勤務。Web+DBの業務アプリをメインに開発に携わる。@IT連載記事「SQL Server 2005を使いこなそう」「SQL Server 2005 CTPレビュー」執筆のほか、著書に『DBマガジン別冊 SQL Server 2005徹底活用ガイド』(翔泳社刊/共著)、『ASP.NET+SQL Server ゼロからはじめるWebアプリケーション』(ソフトバンクパブリッシング刊/共著)。
Copyright © ITmedia, Inc. All Rights Reserved.