Explication étape par étape :
D'abord, vous commandez la table par nom et horodatage et initialisez trois user -variables définies .
SELECT s.* FROM status_table s
, (SELECT @group_number := 0, @prevName := NULL, @prevStatus := NULL) var_init_subquery
ORDER BY name, timestamp
Comme vous pouvez le voir, nous pouvons utiliser une sous-requête pour cela. Le ORDER BY
est important, car il n'y a pas d'ordre dans une base de données relationnelle, sauf si vous le spécifiez.
Maintenant, MySQL évalue le SELECT
clause dans l'ordre spécifié, ne modifiez donc pas l'ordre ici.
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
Lorsque vous exécutez cette instruction, vous pouvez voir que lorsque nous sélectionnons simplement les variables, elles contiennent la valeur de la ligne précédente ou NULL lorsque c'est la première ligne qui a été lue. Ensuite, la valeur de la ligne courante est affectée aux variables. Nous pouvons donc maintenant comparer la ligne actuelle avec la ligne précédente. Si quelque chose a changé, nous incrémentons simplement la troisième variable, qui est un nombre pour chaque "groupe" que nous construisons.
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
Nous avons donc incrémenté le @group_number
quand quelque chose a changé et s'est assigné la variable si ce n'est pas le cas, pour qu'elle ne change pas.
Maintenant, nous pouvons simplement utiliser cette requête comme sous-requête et faire un regroupement simple.
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
- le voir fonctionner dans ce sqlfiddle