【SQLの知っておきたい・知っておきたい】 - レッスン11 サブクエリの使い方

目次

サブクエリ

サブクエリを使用したフィルター

SQLのフォーマット

単一列のみにすることができます

サブクエリとパフォーマンス

サブクエリを計算フィールドとして使用する

注: 完全修飾された列名

ヒント: 複数の解決策


サブクエリ

        SELECT ステートメントは SQL クエリです。これまで見てきた SELECT ステートメントはすべて単純なクエリ、つまり単一のデータベース テーブルからデータを取得する単一のステートメントでした。

        SQL では、サブクエリ (他のクエリ内にネストされたクエリ) を作成することもできます。


サブクエリを使用したフィルター

SELECT cust_id
FROM Orders
WHERE order_num IN (SELECT order_num
                    FROM OrderItems
                    WHERE prod_id = 'RGAN01');

        SELECT ステートメントでは、サブクエリは常に内側から外側に処理されます。上記の SELECT ステートメントを処理する際、DBMS は実際に 2 つの操作を実行します。

        まず、次のクエリを実行します。

SELECT order_num FROM orderitems WHERE prod_id='RGAN01'

        このクエリは、20007 と 20008 の 2 つの注文番号を返します。これら 2 つの値は、IN 演算子に必要なカンマ区切り形式で外側のクエリの WHERE 句に渡されます。外側のクエリは次のようになります。

SELECT cust_id FROM orders WHERE order_num IN (20007,20008)

SQLのフォーマット

        サブクエリを含む SELECT ステートメントは、特に複雑なステートメントの場合、読み取りとデバッグが困難になります。上に示したように、サブクエリを複数の行に分割し、適切にインデントすると、サブクエリの使用が大幅に簡素化されます。

        ちなみに、ここで色分けが重要になります。優れた DBMS クライアントは、まさにこの理由から色分けされた SQL を使用します。

        WHERE 句でサブクエリを使用すると、強力で柔軟な SQL ステートメントを作成できることがわかります。ネストできるサブクエリの数に制限はありませんが、実際の使用ではパフォーマンスの制限があるため、あまりにも多くのサブクエリをネストすることはできません。


単一列のみにすることができます

        サブクエリである SELECT ステートメントは、単一の列のみをクエリできます。複数の列を取得しようとすると、エラーが返されます。

SELECT cust_id
FROM Orders
WHERE order_num IN (SELECT order_num, order_id
                    FROM OrderItems
                    WHERE prod_id = 'RGAN01');

        上記のステートメントではエラーが発生します。サブクエリには 2 つの列がありますが、外側のクエリの条件には 1 つの列しかありません。不一致によりエラーが発生します。2 つの列を一致させたい場合は、次のように記述できます。

SELECT cust_id
FROM Orders
WHERE order_num IN (SELECT order_num
                    FROM OrderItems
                    WHERE prod_id = 'RGAN01')
AND   order_id IN (SELECT order_id
                    FROM OrderItems
                    WHERE prod_id = 'RGAN01');

サブクエリとパフォーマンス

        ここで指定したコードは機能し、望ましい結果が得られます。ただし、サブクエリの使用が、このタイプのデータ取得を実行する最も効率的な方法であるとは限りません。詳細については、レッスン 12 を参照してください。ここでもこの例が示されています。


サブクエリを計算フィールドとして使用する

SELECT cust_name,
        cust_state,
        (SELECT COUNT(*)
        FROM Orders
        WHERE Orders.cust_id = Customers.cust_id) AS orders
FROM Customers
ORDER BY cust_name;

        この SELECT ステートメントは、Customers テーブル内の顧客ごとに 3 つの列 (cust_name、cust_state、orders) を返します。order は、かっこで囲まれたサブクエリから構築される計算フィールドです。このサブクエリは、取得された顧客ごとに 1 回実行されます。この場合、5 人の顧客が取得されたため、サブクエリは 5 回実行されます。

        サブクエリの WHERE 句は、列名 ( cust_id ) だけではなく完全修飾列名を使用するという点で、前に使用した WHERE 句とは少し異なります。テーブル名と列名 (Orders.cust_id および Customers.cust_id) を指定します。次の WHERE 句は、Orders テーブルの cust_id と、Customers テーブルから現在取得されている cust_id を比較するように SQL に指示します。

WHERE Orders.cust_id = Customers.cust_id

        テーブル名と列名をピリオドで区切ります。列名が混乱する可能性がある場合は、この構文を使用する必要があります。この例では、2 つの cust_id 列があります。1 つは Customers に、もう 1 つは Orders にあります。列名を完全修飾しないと、DBMS は Orders テーブルの cust_id がそれ自体と比較されていると考えます。なぜなら

SELECT COUNT(*) FROM Orders WHERE cust_id = cust_id

        常に Orders テーブル内の注文の合計数を返しますが、これは私たちが望むものではありません。

SELECT cust_name,
    cust_state,
    (SELECT COUNT(*)
    FROM Orders
    WHERE cust_id = cust_id) AS orders
FROM Customers
ORDER BY cust_name;

        サブクエリは、このような SELECT ステートメントを構築する際に非常に便利ですが、あいまいな列を制限するように注意する必要があります。

        また、テーブル エイリアスの形式を使用してフィールドを区別することもできます。たとえば、テーブル 1 にはエイリアス a、テーブル 2 にはエイリアス b を使用し、a.field = b.field を使用してフィールド名を区別することもできます。


注: 完全修飾された列名

        DBMS がその意味を誤解するため、完全修飾列名を使用し、指定しないと偽の結果が返される理由はすでに説明しました。場合によっては、列名の競合によるあいまいさが原因で、DBMS がエラー メッセージをスローすることがあります。たとえば、WHERE 句または ORDER BY 句で指定された列名が複数のテーブルに出現する場合があります。SELECT ステートメントで複数のテーブルを操作する場合は、曖昧さを避けるために完全修飾列名を使用することをお勧めします。


ヒント: 複数の解決策

        このレッスンの前半で述べたように、ここで紹介するサンプル コードはうまく機能しますが、この種のデータ取得を解決する最も効率的な方法ではありません。次の 2 つのレッスンで JOIN を学習するときに、この例に再び遭遇します。

おすすめ

転載: blog.csdn.net/qq_57163366/article/details/130007545