はい、単一のSQLステートメントで指定された結果セットを返すことができます。
残念ながら、MySQLは分析関数をサポートしていないため、かなり単純なステートメントになります。MySQLにはそれらをサポートする構文がありませんが、MySQLユーザー変数を使用して一部の分析関数をエミュレートすることは可能です。
(単一のSQLステートメントで)指定された結果セットを実現する方法の1つは、各行に一意の昇順整数値(rownum、クエリによって派生され、クエリ内で割り当てられる)を使用してJOIN操作を使用することです。
例えば:
SELECT q.rownum AS rownum
, q.date AS latest_date
, q.miles/q.gallons AS latest_mpg
, COUNT(1) AS cnt_rows
, MIN(r.date) AS earliest_date
, SUM(r.miles) AS rtot_miles
, SUM(r.gallons) AS rtot_gallons
, SUM(r.miles)/SUM(r.gallons) AS rtot_mpg
FROM ( SELECT @s_rownum := @s_rownum + 1 AS rownum
, s.date
, s.miles
, s.gallons
FROM mytable s
JOIN (SELECT @s_rownum := 0) c
ORDER BY s.date
) q
JOIN ( SELECT @t_rownum := @t_rownum + 1 AS rownum
, t.date
, t.miles
, t.gallons
FROM mytable t
JOIN (SELECT @t_rownum := 0) d
ORDER BY t.date
) r
ON r.rownum <= q.rownum
AND r.rownum > q.rownum - 2
GROUP BY q.rownum
GROUP BY
各ロールアップ行に含める行数を指定するための「n」の目的の値は、句の直前の述語で指定されます。この例では、現在の合計行ごとに最大「2」行です。
値1を指定すると、(基本的に)元のテーブルが返されます。
「不完全な」実行中の合計行(「n」未満の行で構成される)を削除するには、「n」の値を再度指定して、次を追加する必要があります。
HAVING COUNT(1) >= 2
sqlfiddleデモ:http ://sqlfiddle.com/#!2/52420/2
ファローアップ:
Q: SQLステートメントを理解しようとしています。あなたのソリューションは、データベースの各行に対して20行の選択を行いますか?言い換えると、1000行ある場合、ステートメントは20000選択を実行しますか?(パフォーマンスが気になります)...
A:あなたはパフォーマンスに関心を持つ権利があります。
あなたの質問に答えるために、いいえ、これは1,000行に対して20,000の選択を実行しません。
パフォーマンスへの影響は、2つの(本質的に同一の)インラインビュー(別名q
とr
)から生じます。MySQLがこれらを(基本的に)行うのは、一時的なMyISAMテーブル(MySQLでは「派生テーブル」と呼ばれます)を作成することです。これは基本的にmytable
、追加の列を持つのコピーであり、各行には1から行数までの一意の整数値が割り当てられます。
2つの「派生」テーブルが作成されてデータが入力されると、MySQLはそれらの2つの「派生」テーブルを行ソースとして使用して外部クエリを実行します。からの各行は、rからq
の最大行と照合されn
、「現在の合計」マイルとガロンが計算されます。
パフォーマンスを向上させるには、クエリに一意の整数値を割り当てるのではなく、テーブルにすでに存在する列を使用できます。たとえば、date
列が一意である場合、特定の期間の「現在の合計」を計算できます。
SELECT q.date AS latest_date
, SUM(q.miles)/SUM(q.gallons) AS latest_mpg
, COUNT(1) AS cnt_rows
, MIN(r.date) AS earliest_date
, SUM(r.miles) AS rtot_miles
, SUM(r.gallons) AS rtot_gallons
, SUM(r.miles)/SUM(r.gallons) AS rtot_mpg
FROM mytable q
JOIN mytable r
ON r.date <= q.date
AND r.date > q.date + INTERVAL -30 DAY
GROUP BY q.date
(パフォーマンスのためdate
に、インデックスの先頭の列としてで定義された適切なインデックスが必要になります。)
最初のクエリの場合、返される行数を減らすために(インラインビュー定義クエリに)含まれる述語(たとえば、過去1年間の日付値のみを返す)は、処理される行数を減らします。性能を上げる。
繰り返しになりますが、1,000行に対して20,000選択を実行することについての質問に対して、ネストされたループ操作は、同じ結果セットを取得する別の方法です。行数が多い場合、パフォーマンスが低下する可能性があります。(一方、返される行が数行しかない場合、このアプローチはかなり効率的です。
SELECT q.date AS latest_date
, q.miles/q.gallons AS latest_mpg
, ( SELECT SUM(r.miles)/SUM(r.gallons)
FROM mytable r
WHERE r.date <= q.date
AND r.date >= q.date + INTERVAL -90 DAY
) AS rtot_mpg
FROM mytable q
ORDER BY q.date