SELECT文の結果を抽出条件に使うSQL実践講座(7)

» 2001年02月24日 00時00分 公開
[篠原光太郎@IT]

今回掲載の内容

  • IN句を用いた条件抽出
  • サブクエリーとは何か?
  • ANYとSOME


IN句を用いた条件抽出

 今回は、SELECT文を入れ子にした副問い合わせ(サブクエリー)を説明します。

 まずは、本講座の第1回(「SQLの基礎SELECT文を覚えよう」)で解説した「IN」をもう一度復習しましょう。次の例題を実行してみてください。

【例1】

SELECT *
FROM Customers
WHERE CustomerID IN ('ALFKI', 'ANATR', 'ANTON')
画面1 IN句を使って条件抽出を行った例(画面をクリックすると拡大表示します) 画面1 IN句を使って条件抽出を行った例(画面をクリックすると拡大表示します)

 IN句を使用すると、“ ( ) ”の中に指定された値を持つ行のみが抽出され、結果として表示されます。例1では、CustomerIDが「ALFKI」か「ANATR」か「ANTON」の顧客のみ、Customersテーブルから抽出されて表示されているのが分かりますね。これは、例2のように、すべてをORで条件指定した場合と、結果は同じです。

【例2】

SELECT *
FROM Customers
WHERE CustomerID = 'ALFKI'
OR CustomerID = 'ANATR'
OR CustomerID = 'ANTON'

 この例のように、同じカラムに対する複数のORを並べるより、IN句を使用した方が、より判読しやすいSQL文の記述ができる場合が多いです。

 また、IN句は、NOTで否定することもできます。次の例では、例1とは逆で、CustomerIDがALFKI、ANATR、ANTONのどれでもない行が結果として返されます。

【例3】

SELECT *
FROM Customers
WHERE CustomerID NOT IN ('ALFKI', 'ANATR', 'ANTON')

サブクエリー(副問い合わせ)とは何か?

 では次に、「過去に注文があった顧客のリスト」を表示させてみましょう。

 注文を顧客単位に管理しているテーブルは「Orders」テーブルですので、OrdersテーブルにCustomerIDが保存されている顧客が、過去に注文があった顧客と見なすことができます。では、そのIDを表示してみましょう。

【例4】

SELECT CustomerID
FROM Orders
画面2 CustomerIDの一覧をSELECT文で表示してみたところ(画面をクリックすると拡大表示します) 画面2 CustomerIDの一覧をSELECT文で表示してみたところ(画面をクリックすると拡大表示します)

 同じIDが複数表示されているので、「同じCustomerIDは1度だけ表示される」ようにするためには、例5のようにDISTINCTを使用します。

【例5】

SELECT Distinct(CustomerID)
FROM Orders
画面3 DISTINCTを使用して、画面2の例で重複する結果をまとめて表示してみたところ(画面をクリックすると拡大表示します) 画面3 DISTINCTを使用して、画面2の例で重複する結果をまとめて表示してみたところ(画面をクリックすると拡大表示します)

 このように、DISTINCTを使用すると、同じ値は1つにまとめられて表示されます。

 さて、ここからが本題です。例5のCustomerIDの結果を、例1のIN句の“ ( ) ”の値のリストとすることで、過去に注文があった顧客のリストを表示させましょう。次のSQL文を実行してみてください。

【例6】

SELECT *
FROM Customers
WHERE CustomerID IN (
  SELECT Distinct(CustomerID)
  FROM Orders
)
画面4 画面3の結果をもとに、過去に注文のあった顧客のリストを表示してみたところ(画面をクリックすると拡大表示します) 画面4 画面3の結果をもとに、過去に注文のあった顧客のリストを表示してみたところ(画面をクリックすると拡大表示します)

 この例では、IN句の条件である“ ( ) ”の値のリストを、SELECT文で置き換えています。IN句の中のSELECT文が先に実行され、CustomerIDのリストを生成し、そのCustomerIDに含まれている顧客データを表示します。

 このように、SELECT文の結果を、ほかのSELECT文の一部として使用することが可能です。これを、副問い合わせ(サブクエリー)と呼びます。

 では次に、例6とは逆に、「いままで1度も注文をしていない顧客」を表示してみましょう。

【例7】

SELECT *
FROM Customers
WHERE CustomerID NOT IN (
  SELECT Distinct(CustomerID)
  FROM Orders
)
画面5 画面4とは逆に、過去に注文のなかった顧客のリストを表示してみたところ(画面をクリックすると拡大表示します) 画面5 画面4とは逆に、過去に注文のなかった顧客のリストを表示してみたところ(画面をクリックすると拡大表示します)

 例3と同じように、INの前にNOTを入れることで、条件を逆にすることが可能です。

ANYとSOME

 INと同じような使われ方をする句に、ANYSOMEALLEXISTSがあります。今回は、ANYとSOMEを使ってみましょう。

 次のSQL文を実行してみてください。

【例8】

SELECT *
FROM Customers
WHERE CustomerID = ANY (
  SELECT Distinct(CustomerID)
  FROM Orders
)

 結果は、例7と同じです。ANYは、「値リストとして指定された値のいずれかの値」を指定します。例えば、「CustomerID = ANY('ALFKI', 'ANATR', 'ANTON') 」とすれば、CustomerIDが「ALFKI」「ANATR」「ANTON」の3つの値のうちいずれかと合致すれば、その行が結果リストとして返されることになります(実際には、ANYの後ろの“ ( ) ”の中には、サブクエリーのみ指定できます)。

 では、INと何が違うか、というと、ANYの前に比較演算子が指定されている点です。例8では「=」を使用しましたが、ANYはほかのすべての比較演算子と組み合わせて使うことができます。

【例9】

SELECT *
FROM Products
WHERE UnitPrice > ANY (
  SELECT UnitPrice
  FROM "Order Details"
)

 例9では、Order Detailsに保存されている単価(UnitPrice)のいずれかよりも高い単価を持つProductをリストアップします(あまり現実的な例ではありません)。

 このように、ANYはさまざまな使い方ができますが、今回の例に示すように、ほかのSQL文で置き換え可能なため、実際にはあまり使われません。なお、SOMEは、SQL92ではANYと同義です。

今回のまとめ

今回は、「副問い合わせ(サブクエリー)」を紹介しました。次回は、サブクエリーの応用について解説予定です



訂正履歴

【例9】2行目 FROM CustomersをFROM Productsに訂正しました。 (2003.3.25)


「SQL実践講座」バックナンバー

Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。