2017-11-03 13 views
0

テーブルを指定すると、レコードグループを選択し、各グループの最後の列Classを合計しようとしています。グループ化の規則はやや複雑であり、行を相互に比較する必要があります。MySQL以前のグループと比較して値の変化に基づいてレコードグループを選択

|| Seq || Time || Spec || Class 
|| 1 || 8:05 || 0 || 5 
|| 2 || 8:06 || 1 || 5 
|| 3 || 8:07 || 2 ||10 
|| 4 || 8:08 || 4 ||10 
|| 5 || 8:09 || 3 || 5 
|| 6 || 8:10 || 2 || 5 
|| 7 || 8:11 || 6 || 5 
|| 8 || 8:12 || 6 ||15 

私はSpec列の値の変化(増加または減少)に基づいてレコードをグループ化する必要があります。必要な値の変更は2です。したがって、行1から開始して、Spec0です。行3まで少なくとも2は増加しません。これは有効なグループであり、Classフィールドを合計する必要があります。予想される出力はStartTime,StartSpec,EndTime,EndSpecおよびTotalClassです。

次のグループを決定するには、以前のグループで使用された最後の行の値の変化を測定する必要があります。見て分かるように、行4は直ちに2増加し、この1行は有効なグループです。

予想される出力:

||StartTime || StartSpec || EndTime || EndSpec || TotalClass 
|| 8:05 || 0  || 8:07 || 2 || 20 
|| 8:08 || 4  || 8:08 || 4 || 10 
|| 8:09 || 3  || 8:10 || 2 || 10 
|| 8:11 || 6  || 8:11 || 6 ||  5 
+0

'8:09'行に' spec'値が3の場合、なぜ期待される出力に独自のレコードもありません。 –

+0

使用された最後のレコード(8:08)は4のスペックを持っているので、これを3のスペックを持つ8:09と比較する。 '値の必要な変更は2' –

+0

あなたの数学は私には分かりません。 –

答えて

1

は、以下に示されるように、グループ内の最初と最後の行を検出するために、いくつかの中間変数を使用することによって行うことができます。

最後のグループがまだ閉じていない場合は、このグループが「自動クローズ」されることに注意してください。

このようなユースケースの場合、アプリケーションレベルのソリューション は(すでにコメントに記載されているように)より洗練されたオプションかもしれません。

もう一つの選択肢は、データ挿入時に明示的なグループ識別子(すなわち "gid")を計算してそれをテーブル自体に格納することです。これにより、標準的な方法でデータにクエリを行うことができますどんな変数でも。

SELECT 
    MAX(startTime) as startTime, 
    MAX(startSpec) as startSpec, 
    MAX(endTime) as endTime, 
    MAX(endSpec) as endSpec, 
    SUM(class) as totalClass 
FROM (
    SELECT 
     /* Detect first and last rows in a group (when ordered by "seq") */ 
     @first as isFirst, 
     @last:=(ABS(@prev-spec)>1 OR seq=(SELECT MAX(seq) FROM groups)) as isLast,  

     /* If this is a first row, set "startTime" and "startSpec" */ 
     IF(@first,time,NULL) as startTime, 
     IF(@first,spec,NULL) as startSpec, 

     /* If this is a last row, set "endTime" and "endSpec" */ 
     IF(@last,time,NULL) as endTime, 
     IF(@last,spec,NULL) as endSpec, 

     /* Start the next group */ 
     IF(@last,@prev:=spec,NULL) as nextPrev, 
     IF(@last,(@gid:[email protected]+1)-1,@gid) as gid, 

     /* Flip "first" */ 
     @first:[email protected] as nextIsFirst, 

     /* Row "class" */ 
     class 
    FROM 

    /* Declare some variables */ 
    (SELECT @first:=TRUE,@last:=FALSE,@prev:=0,@gid:=0) init 

    CROSS JOIN Groups ORDER BY seq 
) labeled GROUP BY gid; 
+0

ありがとうございました。挿入時にグループを決定する際の主な問題は、異なる値の「変更」を使用してデータを後で照会する必要があることです。この例では、必要な変更速度は2ですが、3または4などの値を使用してクエリを実行する必要があります。 (ABS(@ prev-spec)> 1' – nodoze

+0

助けてくれてありがとう、これは本当に近いです。私の唯一の懸念は、最終的なグループ分けは '8:12 || 6 || 8:12 || 6 || 15'ですしかし、これは有効なグループではありません。前のグループの最後の行の値は6です。したがって、6から6への変更はゼロです必要な変更は2です – nodoze

+0

@nodoze私は意図的に 'OR seq =(SELECT最後の "閉じられていない"グループが "自動閉鎖"され、結果に含まれるように、あなたが望むものではないので、それを削除し、 'HAVING SUM(isLast) > 0 "を外側のクエリに渡して完全に除外します。 – zeppelin

関連する問題