更新
MySQL 8.0では、SQL Serverの「ウィンドウ関数」と同等の機能である「ウィンドウ関数」が導入されています(Transact-SQL OVER
によって提供されるパーティション分割と順序付けを使用) 構文)、およびOracleの「分析関数」。
MySQLリファレンスマニュアル12.21ウィンドウ関数
ここで提供される答えは、8.0より前のバージョンのMySQLに対するアプローチです。
元の回答
MySQLは、他のDBMS(OracleやSQL Serverなど)で使用可能な分析関数のように、実行中の「累積合計」を取得するために使用する型分析関数を提供していません。
ただし、MySQLを使用して、一部の分析関数をエミュレートすることは可能です。
(少なくとも)2つの実行可能なアプローチがあります:
1つは、相関サブクエリを使用して小計を取得することです。このアプローチは、大規模なセットではコストがかかる可能性があり、外部クエリの述語が複雑な場合は複雑になる可能性があります。 「複数のテーブルでの複数の結合」がどれほど複雑かによって異なります。 (残念ながら、MySQLもCTEをサポートしていません。)
もう1つのアプローチは、MySQLユーザー変数を使用して、コントロールブレーク処理を実行することです。ここでの「トリック」は、(ORDER BYを使用して)ソートされたクエリの結果を取得し、クエリを別のクエリでラップすることです。
後者のアプローチの例を示します。
MySQLが操作を実行する順序のため、cumulative_total
id
の値の前に列を計算する必要があります およびday
現在の行からユーザー変数に保存されます。この列を最初に配置するのが最も簡単です。
(以下のクエリで)iとしてエイリアスされたインラインビューは、ユーザー変数がセッションですでに設定されている場合に備えて、ユーザー変数を初期化するためにあります。それらにすでに値が割り当てられている場合は、現在の値を無視する必要があります。これを行う最も簡単な方法は、それらを初期化することです。
元のクエリは括弧で囲まれ、エイリアスc
が与えられます 以下の例では。元のクエリに対する唯一の変更は、ORDER BY句の追加であるため、クエリの行を順番に処理することができます。
外側の選択は、id
かどうかをチェックします およびday
現在の行の値は前の行と「一致」します。含まれている場合は、amount
を追加します 現在の行から累積小計まで。それらが一致しない場合は、累積小計をゼロにリセットし、現在の行からの金額を追加します(または、より簡単に言えば、現在の行からの金額を割り当てるだけです)。
累積合計の計算が完了したら、id
を保存します。 およびday
現在の行の値をユーザー変数に変換するため、次の行を処理するときに使用できます。
例:
SELECT IF(@prev_id = c.id AND @prev_day = c.day
,@cumtotal := @cumtotal + c.amount
,@cumtotal := c.amount) AS cumulative_total
, @prev_id := c.id AS `id`
, @prev_day := c.day AS `day`
, c.hr
, c.amount AS `amount'
FROM ( SELECT @prev_id := NULL
, @prev_day := NULL
, @subtotal := 0
) i
JOIN (
select id, day, hr, amount from
( //multiple joins on multiple tables)a
left join
(//unions on multiple tables)b
on a.id=b.id
ORDER BY 1,2,3
) c
累積合計を最後の列として、別の順序で列を返す必要がある場合、1つのオプションは、ステートメント全体を一連の親でラップし、そのクエリをインラインビューとして使用することです。
SELECT d.id
, d.day
, d.hr
, d.amount
, d.cumulative_total
FROM (
// query from above
) d