2016-09-06 13 views
1

MySQLクエリで変数を保存する際に問題が発生しました。私が持っているテーブルはシンプルです:MySQLの前の行の計算

+--------------+-------------+ 
| SUM(price) | timestamp | 
+--------------+-------------+ 
|433   |2015-05-02 | 
+--------------+-------------+ 
|498   |2015-06-02 | 
+--------------+-------------+ 
|440   |2015-06-04 | 
+--------------+-------------+ 
|434   |2015-06-07 | 
+--------------+-------------+ 
|433   |2015-06-09 | 
+--------------+-------------+ 

タイムスタンプは毎日/毎月ではなく、インデックスがありません。上記の表は、次のクエリの結果です。

SELECT SUM(price) AS totalvalue, timestamp AS ts FROM basetable GROUP BY timestamp ORDER BY timestamp ASCこの結果、特定のタイムスタンプ内のすべての価格の合計が日付(タイムスタンプ)になります。

+--------------+-------------+--------+ 
| SUM(price) | timestamp | diff | 
+--------------+-------------+--------+ 
|433   |2015-05-02 |0  | 
+--------------+-------------+--------+ 
|498   |2015-06-02 |65  | 
+--------------+-------------+--------+ 
|440   |2015-06-04 |-58  | 
+--------------+-------------+--------+ 
|434   |2015-06-07 |-6  | 
+--------------+-------------+--------+ 
|433   |2015-06-09 |-1  | 
+--------------+-------------+--------+ 

すべて差分カラム:(従ってによって基、によって順序が年表のためのものである)私は必要なもの

はそうのような、現在の行の合計と行それ以前との間の差でありますはcurrent row total - previous row totalです。 (そして最初の行は0)私がしようとしたのは、現在の行の合計を@variableに保存し、次の行でそれを取得することでしたが、動作させることはできません。

ソリューションは、おそらく簡単ですが、私はちょうどそれを得るように見えることはできません...

UPDATE:私が試し(失敗した)しましたこれらのメソッド:

SELECT SUM(a.price) AS totalvalue, a.timestamp, SUM(a.price)-COALESCE(SUM(b.price),0) as previous_row_diff FROM basetable a LEFT JOIN basetable b on a.timestamp=b.timestamp-1

と私はこの作業を取得する方法が分からないよう

SET @prev := 0; SELECT timestamp, SUM(price), SUM(price)[email protected] AS diff, @prev := SUM(price) AS diff2 FROM basetable ORDER BY timestamp ASC;

の両方が、このサイトからのものであった...

+0

試してみませんか?何が間違っていたのか、どうやって教えてくれますか? – Barmar

+0

ダビデは将来的にフィドルを作成する – Drew

+0

こんにちは。 SQLFiddleは現在、私のためにダウンしています(ビルドやクエリはありませんが、サンプルもあります)。そのため、フィドルはありません。私ができるときに私は1つを追加します –

答えて

1

他のほとんどのデータベースはLAG()をサポートしているため、これははるかに簡単です。私たちは、変数を使用してMySQLでこれをエミュレートすることができます。

SELECT totalvalue, ts, 
     (CASE WHEN (@save_prev := prev) = NULL THEN NULL -- = NULL is *never* true 
      WHEN (@prev := totalvalue) = NULL THEN NULL -- = NULL is *never* true 
      ELSE @save_prev 
     END) as prev_value 
FROM (SELECT SUM(price) AS totalvalue, timestamp AS ts 
     FROM basetable 
     GROUP BY timestamp 
    ) t CROSS JOIN 
    (SELECT @prev := 0) params 
ORDER BY timestamp ASC; 

diffが容易で、その後で取得するには:

SELECT totalvalue, ts, 
     (totalvalue - 
     (CASE WHEN (@save_prev := prev) = NULL THEN NULL -- = NULL is *never* true 
       WHEN (@prev := totalvalue) = NULL THEN NULL -- = NULL is *never* true 
       ELSE @save_prev 
     END) 
     ) as diff 
FROM (SELECT SUM(price) AS totalvalue, timestamp AS ts 
     FROM basetable 
     GROUP BY timestamp 
    ) t CROSS JOIN 
    (SELECT @prev := 0) params 
ORDER BY timestamp ASC; 

注:変数の使用は注意が必要です。 MySQLは式の評価順序をSELECTで保証しません。したがって、関連するすべての変数の計算は同じ式にする必要があります。

上記は、これを確実にするための条件CASEの逐次評価を使用しています。 = NULLは意識的に常にfalseを返すものとして意識的に使用されています(実際にはAND falseまたはAND 1 = 0は同じことを行います)。これにより、変数値が正しい順序で確実に計算されます。