2017-06-09 3 views
2

So habe ich die folgende Struktur:Zählen nicht zusammenhängende Werte

+------+---------------+---------------+----+ 
| guid | current_level | current_value | pk | 
+------+---------------+---------------+----+ 
| a |   100 |   12 | 1 | 
| a |   200 |   12 | 2 | 
| a |   200 |   12 | 3 | 
| a |   200 |   12 | 4 | 
| a |   200 |   12 | 6 | 
| a |   300 |   14 | 7 | 
| a |   300 |   12 | 9 | 
| a |   300 |   12 | 10 | 
| a |   300 |   14 | 12 | 
| b |   100 |   10 | 5 | 
| b |   100 |   10 | 8 | 
| b |   200 |   12 | 11 | 
| b |   200 |   12 | 13 | 
+------+---------------+---------------+----+ 

Ich möchte die Anzahl der Male, a und b zählen gingen 200 nicht-zusammenhängend zu nivellieren (und 300, sondern nur 200 bis jetzt) ​​ dh das Ergebnis erwarte ich:

+------+-------+-------+ 
| guid | level | times | 
+------+-------+-------+ 
| a | 200 |  1 | 
| b | 200 |  1 | 
+------+-------+-------+ 

(ich kann nicht nur einzigartig, weil getrennte Streifen von 200s separat gezählt werden)

Wenn ich folgendes tun:

set @id = "none"; 
set @lev = 10; -- arbitary non zero starting level 

SELECT guid, current_level , if(@id <> guid, @lev := 10, 0) AS useless, case when @id <> guid then @id := guid else 0 end AS useless2 
     , (case when (current_level = 200 AND current_level <> @lev) then 1 else 0 end) as TIMES 
     , if(current_level = 200 AND current_level <> @lev, @lev := current_level, 0) AS useless3 

FROM (SELECT * FROM sensor_logs order by guid) as T 

ich:

+------+---------------+---------+----------+----------+----------+ 
| guid | current_level | useless | useless2 | TIMES | useless3 | 
+------+---------------+---------+----------+----------+----------+ 
| a |   100 |  10 | a  |  0 |  0 | 
| a |   200 |  0 | 0  |  1 |  200 | 
| a |   200 |  0 | 0  |  0 |  0 | 
| a |   200 |  0 | 0  |  0 |  0 | 
| a |   200 |  0 | 0  |  0 |  0 | 
| a |   300 |  0 | 0  |  0 |  0 | 
| a |   300 |  0 | 0  |  0 |  0 | 
| a |   300 |  0 | 0  |  0 |  0 | 
| a |   300 |  0 | 0  |  0 |  0 | 
| b |   100 |  10 | b  |  0 |  0 | 
| b |   100 |  0 | 0  |  0 |  0 | 
| b |   200 |  0 | 0  |  1 |  200 | 
| b |   200 |  0 | 0  |  0 |  0 | 
+------+---------------+---------+----------+----------+----------+ 

So, jetzt Addition der TIMES Spalte und Gruppierung von guid sollte es tun, das heißt:

set @id = "none"; 
set @lev = 10; -- arbitary non zero starting level 

SELECT guid, current_level , if(@id <> guid, @lev := 10, 0) AS useless, case when @id <> guid then @id := guid else 0 end AS useless2 
     , sum(case when (current_level = 200 AND current_level <> @lev) then 1 else 0 end) as TIMES 
     , if(current_level = 200 AND current_level <> @lev, @lev := current_level, 0) AS useless3 

FROM (SELECT * FROM sensor_logs order by guid) as T 
GROUP BY guid 

Aber ich folgendes:

+------+---------------+---------+----------+----------+----------+ 
| guid | current_level | useless | useless2 | TIMES | useless3 | 
+------+---------------+---------+----------+----------+----------+ 
| a |   100 |  10 | a  |  4 |  0 | 
| b |   100 |  10 | b  |  2 |  0 | 
+------+---------------+---------+----------+----------+----------+ 

I verstehe nicht, warum das Summieren einer Spalte, die zwei 1s (eine für jede GUID) hatte, 4 und 2 ergibt.

Ist es etwas, was ich falsch mache? oder mehr mit der zugrundeliegenden Mechanik zu tun, wie die Abfrage (und die Summenfunktion) ausgeführt wird?

+0

es klar ist, dass Sie die ocurrences von 200 –

Antwort

1

Ihre erste Abfrage, die Sie besser schreiben Sie es wie folgt aus:

SELECT guid, current_level , if(@id <> guid, @lev := 10, 0) AS useless, case when @id <> guid then @id := guid else 0 end AS useless2 
     , (case when (current_level = 200 AND current_level <> @lev) then 1 else 0 end) as TIMES 
     , if(current_level = 200 AND current_level <> @lev, @lev := current_level, 0) AS useless3 

FROM sensor_logs 
, (SELECT @id := 'none', @lev := 10) var_init_subquery 
ORDER BY guid 

Es ist nicht nur sauberer die Reihenfolge explizit zu tun, wenn nötig, nicht in einer Unterabfrage, es in einer Unterabfrage tun könnte auch zu einem führen schlechter Ausführungsplan (was eine schlechte Leistung im Falle einer temporären Tabelle bedeutet).

Für Ihr Endergebnis sollten Sie GROUP BY nicht direkt anwenden. Die SELECT (und damit Ihre Variablen und Berechnungen) werden nach der GROUP BY bewertet. Um die Gruppierung nach Ihren Berechnungen, setzen Sie Ihre Abfrage in einer Unterabfrage:

SELECT guid, SUM(times) FROM (
    SELECT guid, current_level , if(@id <> guid, @lev := 10, 0) AS useless, case when @id <> guid then @id := guid else 0 end AS useless2 
      , (case when (current_level = 200 AND current_level <> @lev) then 1 else 0 end) as TIMES 
      , if(current_level = 200 AND current_level <> @lev, @lev := current_level, 0) AS useless3 

    FROM sensor_logs 
    , (SELECT @id := 'none', @lev := 10) var_init_subquery 
    ORDER BY guid 
) sq 
GROUP BY guid 
+0

Danke summieren! funktioniert perfekt. Aus Performance-Sicht, wo steht das? (bei einer mittelgroßen Datenbank) – user3690467

+0

Hängt vollständig von Ihrem Computer ab. Es findet keine Filterung statt, daher werden Sie einen Scan für ganze Tabellen durchführen. – fancyPants

+0

Angesichts des Problems gibt es einen "klügeren" Weg, dies zu tun? – user3690467

Verwandte Themen