インラインビューはサブクエリの一種で、FROM句の中に置いたSELECT結果を外側から表のように参照します。 集計後の値で絞り込む、計算した列を別の段階で使う、といった処理を読みやすく分けられます。CREATE VIEWで保存するビューや一時テーブルとは異なり、インラインビューを書いただけで別クエリから使える保存物は作られません。
インラインビューとは
インラインビューは、FROM句の中のサブクエリです。外側のクエリは、そのSELECTが出力する列を表の列のように参照します。Oracleの公式定義はこの形式をinline viewと呼び、MySQLやPostgreSQLではderived table(派生テーブル)として説明されます。
以降のSQL例はMySQL 8.4を前提にしています。DATE_FORMAT、EXPLAIN、ウィンドウ関数、日付の解釈は、他のDBMSではそのまま使えない場合があります。表と列は説明用なので、実際のスキーマに合わせてください。
| 書き方 | 名前を参照する範囲 | 主な役割 |
|---|---|---|
| インラインビュー/派生テーブル | そのSQL文の外側のクエリ | FROM内の結果を表として参照 |
| サブクエリ | 含まれるSQL文の該当位置 | IN・EXISTS・スカラー・FROM等の総称 |
| CTE(WITH) | 定義に続く同じSQL文 | 名前付きの結果を読みやすく分割 |
| 保存ビュー(CREATE VIEW) | 権限等に従い他のSQL文からも参照 | クエリ定義をDBオブジェクトとして保存 |
別名は省略せず、(SELECT ... ) AS vの形を基本にします。PostgreSQL 17の説明は別名の省略を認めますが、他システムへの移植を考えて書くことを勧めています。DBMSや版ごとの構文を混同しないでください。
インラインビューの基本的な使い方
インラインビューの基本的な使い方は、FROM句内でサブクエリを定義し、それをテーブルのように参照することです。例えば、以下のようなSQLクエリでインラインビューを使用できます。
SELECT v.customer_id, v.total_amount
FROM (
SELECT customer_id, SUM(amount) AS total_amount
FROM orders
GROUP BY customer_id
) AS v
WHERE v.total_amount > 1000;この例では、インラインビューvを利用して、特定の条件を満たす顧客の合計金額を抽出しています。
基本例の入力と結果を追う
ordersに次の3行があるとします。内側では顧客ごとに合計し、外側では合計が1000を超える顧客だけを残します。単一注文のamountが1000を超えるかどうかを調べる条件とは意味が異なります。
| customer_id | amount |
|---|---|
| 1 | 600 |
| 1 | 500 |
| 2 | 800 |
| 内側のcustomer_id | 内側のtotal_amount | 外側の条件 > 1000 |
|---|---|---|
| 1 | 1100 | 残る |
| 2 | 800 | 除外 |
外側の結果はcustomer_id=1、total_amount=1100の一行です。集計だけで足りるなら、同じ条件をGROUP BYに続くHAVING SUM(amount) > 1000で書く方法もあります。インラインビューを使うと、計算済み列に付けた名前を外側で参照できます。
インラインビューのメリット
インラインビューを使用することで得られる主なメリットは以下の通りです。
クエリの簡潔化
複雑なクエリを簡潔に記述でき、可読性が向上します。
一時的な結果セットの利用
同じSQL文の外側で、内側の結果に付けた別名を参照できます。その文が終わった後に、別のSQL文から同じインラインビュー名を再利用できるという意味ではありません。
データのフィルタリングと集計
集計前の条件と集計後の条件を分けて表現できます。記述が読みやすくなることと、実行時間が短くなることは別なので、性能は実行計画と同じデータで確認します。
コードの再利用性向上
一つのSQL文の中で処理の意図をまとめるのに役立ちます。同じ文で複数回参照したい場合はCTE、複数のSQL文で定義を共有したい場合は保存ビューなどを検討します。
インラインビューとサブクエリの違い
サブクエリという大きなくくりの中に、FROM句で使うインラインビューが含まれます。違いを考えるときは、含める句と必要な結果の形を確認します。
インラインビュー
インラインビューはFROM句で使用するサブクエリであり、サブクエリと対立する種類ではありません。括弧の外に別名を付け、外側から参照する計算列にも名前を付けると、どの列を使うか明確になります。
サブクエリ
サブクエリは他のSQL文に含まれるクエリの総称です。FROMのインラインビューのほか、INで値の集合を調べる形式、EXISTSで存在を調べる形式、単一値を返すスカラーサブクエリなどがあります。返す行・列の数は使う位置と演算子によって異なり、サブクエリ全体がインラインビューより用途の狭い機能という説明は適切ではありません。
例えば、サブクエリは以下のように使用されます:
SELECT customer_id, name
FROM customers
WHERE customer_id IN (
SELECT customer_id
FROM orders
WHERE amount > 1000
);この例では、サブクエリを使って特定の条件を満たす顧客IDを取得し、その顧客の情報をメインクエリで抽出しています。
インラインビューの実践例
インラインビューは、実際の業務で多様なシナリオに活用できます。以下に、売上データを集計し特定の条件でフィルタリングする例を示します。
売上データの集計とフィルタリング
次のSQLクエリは、各製品カテゴリの総売上を集計し、売上が100,000円以上のカテゴリのみを抽出します。
SELECT category, total_sales
FROM (
SELECT category, SUM(sales_amount) AS total_sales
FROM sales
GROUP BY category
) AS sales_summary
WHERE total_sales >= 100000;このクエリでは、sales_summaryという別名で集計結果を外側から参照し、合計値でフィルタリングします。これはSQL文内の論理的な分割であり、必ず一時テーブルへ保存されるという意味ではありません。
特定の月の売上ランキング
次の例は、特定の月における売上ランキングを表示するものです。
SELECT product_id, monthly_sales, RANK() OVER (ORDER BY monthly_sales DESC) AS sales_rank
FROM (
SELECT product_id, SUM(sales_amount) AS monthly_sales
FROM sales
WHERE sales_date >= '2024-01-01'
AND sales_date < '2024-02-01'
GROUP BY product_id
) AS monthly_sales_data
ORDER BY monthly_sales DESC, product_id;sales_dateが時刻を含む列でも1月31日全体を含めるため、月初以上・翌月初未満の半開区間を使います。RANKの同額順位は同じですが、結果の表示順は最後のORDER BYで指定します。ウィンドウ内のORDER BYだけで最終表示順を保証しません。
このクエリでは、インラインビューmonthly_sales_dataを用いて特定の月の売上データを集計し、その結果に対してランキングを計算しています。インラインビューを使うことで、集計とランキングを一つのクエリで効率的に処理しています。
インラインビューを使用したデータの集計
インラインビューは、複雑なデータの集計を簡単に行うための強力なツールです。以下に、複数の集計を一つのクエリで行う方法を示します。
複数の集計を一つのクエリで実行
次のSQLクエリは、各店舗の月別売上と平均売上を同時に計算し、結果を店舗ごとに表示します。
SELECT store_id, month, total_sales, avg_sales
FROM (
SELECT store_id,
DATE_FORMAT(sales_date, '%Y-%m') AS month,
SUM(sales_amount) AS total_sales,
AVG(sales_amount) AS avg_sales
FROM sales
GROUP BY store_id, month
) AS store_sales_summary;このクエリでは、インラインビューstore_sales_summaryを利用して、各店舗の月別売上合計と平均売上を集計し、その結果セットをメインクエリで参照しています。
インラインビューによる累積売上の計算
次の例では、各商品の累積売上を計算し、累積売上が特定の閾値を超えた商品のみを抽出します。
SELECT product_id, cumulative_sales
FROM (
SELECT product_id,
SUM(sales_amount) OVER (
PARTITION BY product_id
ORDER BY sales_date, sales_id
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
) AS cumulative_sales
FROM sales
) AS cumulative_sales_data
WHERE cumulative_sales > 50000;この累積例ではsales_idを一意の売上行IDとして追加し、同じ時刻の行も一行ずつ加算する順序を決めています。ROWSとRANGEの公式説明のとおり、同じ並び値の行をまとめる既定のフレームと、一行ずつ加算するフレームでは結果が変わります。実表にsales_idがなければ、一意の並びを決める列へ置き換えてください。同じ商品の複数の売上行が閾値を超えれば、外側にもその商品が複数行出ます。商品ごとの最終合計だけを一行で出したい場合は、GROUP BYで合計する例を選んでください。
このクエリでは、インラインビューcumulative_sales_dataを使って、各商品の累積売上を計算し、その結果から累積売上が50,000円を超えた商品を抽出しています。インラインビューを用いることで、複雑な累積計算もシンプルに記述できます。
インラインビューのパフォーマンス最適化
インラインビューを効率的に使用するためには、パフォーマンスの最適化が重要です。以下に、インラインビューのパフォーマンスを向上させるためのいくつかの方法を紹介します。
インデックスの活用
元のテーブルの検索条件や結合条件に合うインデックスを検討します。ただし、インデックス追加で必ず速くなるとは限らず、更新コストも増えます。まず実行計画と対象件数を確認して、必要な列と列順を選びます。
不要なデータのフィルタリング
インラインビューの中で必要なデータだけを抽出するようにし、不要なデータをフィルタリングすることで、クエリのパフォーマンスを向上させることができます。これは、インラインビュー内のWHERE句やHAVING句を適切に使用することで実現できます。
適切な集計関数の選択
集計関数を使用する際には、パフォーマンスに影響を与えることがあります。必要に応じて、適切な集計関数を選択し、パフォーマンスを考慮して使用しましょう。
クエリプランの確認と最適化
実行計画で、読み取る行数、結合、集計や一時領域などを確認します。次のEXPLAIN例はMySQLを前提とします。実行計画の構文や出力はDBMSによって異なります。
MySQL 8.4の公式説明では、派生テーブルは外側にマージされる場合と内部一時テーブルへ実体化される場合があります。インラインビューの形だけを見て、内側が必ず先に実行・保存されるとは判断できません。
EXPLAIN SELECT category, total_sales
FROM (
SELECT category, SUM(sales_amount) AS total_sales
FROM sales
GROUP BY category
) AS sales_summary
WHERE total_sales >= 100000;結合の最適化
インラインビューで複数のテーブルを結合する場合、結合順序や結合条件を最適化することで、パフォーマンスを向上させることができます。インラインビュー内で不要な結合を避け、効率的な結合順序を選択しましょう。
インラインビューの使用を控える場合
同じSQL文の中で名前付きの結果を複数箇所から参照したい場合は、WITH句のCTEで意図を整理できます。ただし「CTEなら一度保存して速くなる」とは限りません。SQL Serverの説明ではCTEの結果は実体化されず、外側からの参照で定義クエリが再実行されるとされています。DBMSごとの実行計画を比較してください。
WITH sales_summary AS (
SELECT category, SUM(sales_amount) AS total_sales
FROM sales
GROUP BY category
)
SELECT category, total_sales
FROM sales_summary
WHERE total_sales >= 100000;最適化では、変更前後で結果が同じか、同じ件数・条件で実行時間がどう変わるかを確認します。集計前と後で条件を動かすと意味が変わる場合があるので、速さより先に結果の正しさを照合します。
公式資料
- Oracle:FROM句のサブクエリとinline viewの定義
- PostgreSQL:テーブル式・別名・FROMのサブクエリ
- MySQL 8.4:派生テーブルとCTEのマージ/実体化
- SQL Server:CTEの適用範囲と非実体化
- MySQL 8.4:ウィンドウ関数のROWSとRANGE
まとめ
インラインビューは、FROM句内のサブクエリを外側から表として使う書き方です。まず別名と出力列をそろえ、集計前・集計後の条件を分けます。CTEや保存ビューとの使い分けは名前を使う範囲で考え、速度や物理的な保存はDBMSの実行計画で確認してください。



コメント