Spiegazione passo passo:
Per prima cosa ordini la tabella per nome e timestamp e inizializzi tre utente -variabili definite .
SELECT s.* FROM status_table s
, (SELECT @group_number := 0, @prevName := NULL, @prevStatus := NULL) var_init_subquery
ORDER BY name, timestamp
Come puoi vedere, possiamo usare una sottoquery per questo. Il ORDER BY
è importante, perché non c'è ordine in un database relazionale, a meno che tu non lo specifichi.
Ora MySQL valuta SELECT
clausola nell'ordine specificato, pertanto non modificare l'ordine qui.
SELECT
s.*,
@prevName,
@prevStatus,
@prevName := s.name,
@prevStatus := s.status
FROM status_table s
, (SELECT @group_number := 0, @prevName := NULL, @prevStatus := NULL) var_init_subquery
ORDER BY name, timestamp
Quando esegui questa istruzione, puoi vedere che quando selezioniamo semplicemente le variabili mantengono il valore della riga precedente o NULL quando è la prima riga, quella è stata letta. Quindi il valore della riga corrente viene assegnato alle variabili. Quindi possiamo confrontare ora la riga corrente con la riga precedente. Se qualcosa è cambiato, incrementiamo semplicemente la terza variabile, che è un numero per ogni "gruppo" che stiamo costruendo.
SELECT
s.*,
@group_number := IF(@prevName != s.name OR @prevStatus != s.status, @group_number + 1, @group_number) AS group_number,
@prevName := s.name,
@prevStatus := s.status
FROM status_table s
, (SELECT @group_number := 0, @prevName := NULL, @prevStatus := NULL) var_init_subquery
ORDER BY name, timestamp
Quindi abbiamo incrementato il @group_number
quando qualcosa è cambiato e si è assegnata la variabile in caso contrario, in modo che non cambi.
Ora possiamo semplicemente usare questa query come sottoquery ed eseguire un semplice raggruppamento.
SELECT
group_number AS id,
name,
status,
MIN(error) AS error,
MIN(timestamp) AS firstEntry,
MAX(timestamp) AS lastEntry,
COUNT(*) AS entries
FROM (
SELECT
s.*,
@group_number := IF(@prevName != s.name OR @prevStatus != s.status, @group_number + 1, @group_number) AS group_number,
@prevName := s.name,
@prevStatus := s.status
FROM status_table s
, (SELECT @group_number := 0, @prevName := NULL, @prevStatus := NULL) var_init_subquery
ORDER BY name, timestamp
) sq
GROUP BY
group_number,
name,
status
- lo vedi funzionare in questo sqlfiddle