2017-01-30 4 views
2

Ich versuche, wöchentliche Ergebnisse zu vergleichen. Um genauer zu sein, möchte ich Woche für Woche den Unterschied ausmachen.Offset auf Abfrageergebnisse

Zunächst möchte ich zeigen, wie das Ergebnis aussehen soll:

CalendarWeek  currently  previous_week  delta 
2016-01   200    
2016-02   210   200     10 
2016-03   205   210     -5 
2016-04   230   205     25 
...  

Ich habe eine Lösung, aber es ist ziemlich langsam.

Zur Zeit mache ich es wie folgt aus:

SELECT CalendarWeek, cur_value - prev_value AS delta 
FROM 
    (SELECT CalendarWeek, COUNT(Change_ID) AS cur_value 
    FROM Changes 
    WHERE ... 
    GROUP BY CalendarWeek) AS cur_week 
LEFT JOIN 
    (SELECT CalendarWeek, COUNT(Change_ID) AS prev_value 
    FROM Changes 
    WHERE ... 
    GROUP BY CalendarWeek) AS prev_week 
ON cur_week.CalendarWeek = prev_week.CalendarWeek + 1 

Mein Problem ist, dass die Unterabfragen laufen viel Zeit in Anspruch nimmt (habe ich sie für diese Vitrine vereinfachen). Die SELECT mit der COUNT() läuft 45 sek. jeweils = 1,5 min. Ich denke, es sollte eine geeignetere Lösung geben. Ich brauche nur den prev_value um 1 Zeile verschoben oder mit einem Offset von 1 Zeile.

Antwort

0

Verwenden Variablen statt:

SELECT w.*, 
     (CASE WHEN (@pcv := @prev_value) = NULL THEN NULL  -- never happens 
      WHEN (@prev_value := cur_value) = NULL THEN NULL -- never happens 
      ELSE @pcv 
     END) as prev_value 
FROM (SELECT CalendarWeek, COUNT(Change_ID) AS cur_value 
     FROM Changes 
     WHERE ... 
     GROUP BY CalendarWeek AS cur_week 
    ) w CROSS JOIN 
    (SELECT @prev_value := -1) params 
ORDER BY CalendarWeek; 

Sie können dann eine zusätzliche Unterabfrage verwenden Verhältnisse und Unterschiede zu berechnen.

Hinweis: Die Logik zum Zuweisen des vorherigen Werts besteht aus drei Schritten: (1) Zwischenspeichern des vorherigen vorherigen Werts in einer Variablen, (2) Neuzuweisen des vorherigen Werts und (3) Verwenden des zwischengespeicherten Werts.

MySQL garantiert nicht die Reihenfolge der Ausführung von Ausdrücken in einer SELECT, so dass dies alles in einem einzigen Ausdruck passieren muss (daher die = NULL, die nie wahr ist). Fast alle anderen Datenbanken unterstützen lag() für diesen Zweck, wodurch die Abfrage schneller und die Logik einfacher wird.

+0

Danke. Es funktioniert einwandfrei. Wirklich nette Idee, die Werte zwischenzuspeichern. Genau danach habe ich gesucht! Es gibt nur eine Klammer vor dem CROSS JOIN. :) – itonlytakesaminute