😀

サブクエリとCTE(Common Table Expressions)の違いと使い方

2025/03/09に公開

こんにちは、しがないバックエンドエンジニア、ウエダです。
最近SQLを勉強しているのですがサブクエリとCTEどっちも似たようなことが出来るけどどっち使えばいいんだ?
と思ったので記事にまとめて整理したいと思います🤔

サブクエリとは

サブクエリは、他のクエリ内で実行される入れ子クエリのことを指します。通常、SELECT、FROM、またはWHERE句内で使われ、データを一時的に抽出したりフィルタリングしたりするのに便利です。

サブクエリの例

以下は、顧客テーブル (customers) と注文テーブル (orders) を用いて、全体の平均注文額を超える注文を持つ顧客を取得します。また、その顧客の名前、注文額、さらにその顧客の最も新しい注文日も一緒に取得しているサブクエリの例です。

SELECT customer_id, customer_name, order_amount, latest_order_date
FROM (
    SELECT c.customer_id, c.customer_name, o.order_amount,
        (SELECT MAX(order_date) 
         FROM orders 
         WHERE orders.customer_id = c.customer_id) AS latest_order_date
    FROM customers c
    JOIN orders o ON c.customer_id = o.customer_id
    WHERE o.order_amount > (
        SELECT AVG(order_amount)
        FROM orders
    )
) AS SubQuery
ORDER BY order_amount DESC;

このクエリの問題点

  1. ネストが深い
  2. 複数のサブクエリの存在
  3. 複雑な条件の組み合わせ

CTEとは

CTEは、一時的に名前を付けた結果セットを使って、SQLクエリをより読みやすく、再利用しやすくする手法です。CTEはWITH句で定義され、メインクエリで使用されます。特に複数のCTEを連結して使う場合や、再帰的なクエリを実行する場合に便利です。

CTEを使用すればサブクエリの複雑なクエリが分かりやすくなる、、かも。

CTEで実装してみよう

では、先ほどサブクエリで実現したクエリを、CTEを使用して実装してみましょう。

WITH AverageOrderAmount AS (
    SELECT AVG(order_amount) AS avg_order_amount
    FROM orders
),
CustomerLatestOrder AS (
    SELECT customer_id, MAX(order_date) AS latest_order_date
    FROM orders
    GROUP BY customer_id
)
SELECT c.customer_id, c.customer_name, o.order_amount, clo.latest_order_date
FROM customers c
JOIN orders o ON c.customer_id = o.customer_id
JOIN AverageOrderAmount aoa ON o.order_amount > aoa.avg_order_amount
JOIN CustomerLatestOrder clo ON c.customer_id = clo.customer_id
ORDER BY o.order_amount DESC;

サブクエリと比べるとCTEの方がだいぶスッキリして可読性が上がりました!

まとめ

クエリが少しでも複雑になる場合や再利用性が求められる場合は、CTEを使うのが一般的にベストです。よりシンプルで一時的な処理ならサブクエリで十分ですが、チームでの開発やコードの可読性が求められるシーンではCTEが良いと考えます!

Discussion