2010-02-10 3 views
1

J'ai une série de horodatées données on/off dans un tableau, ce qui représente on/off états, ou le point où un état « commence »requête MySQL pour évaluer la durée totale de quelque chose est « sur »

00:00:00 0 
04:00:00 1 
08:00:00 0 
09:00:00 1 
15:00:00 0 
20:00:00 1 
23:59:59 0 

J'ai besoin de calculer la durée totale de (disons) l'état ON sur une période de 24h.

Dans cet exemple simplifié, la durée totale = 1 est (04: 00: 00-> 08:00:00, 09: 00: 00-> 15:00:00, 20: 00: 00-> 23: 59:59 ie 13:59:59 environ 14h

Je ne peux pas déterminer si cela peut être fait dans SQL seul, ou si l'infrastructure sous-jacente que j'utilise (django) devrait le faire en fonction des données retournées Je préférerais évidemment que la base de données fasse le gros du travail si possible, car il se peut que nous devions aussi utiliser le SQL dans notre paquetage de statistiques séparé

Je ne sais pas si je peux faire des opérations sur (disons) élément précédent ou suivant dans la sélection, je suis un utilisateur SQL confiant, mais ne peut pas voir par où commencer pour cela ou l'approche généralisée, des idées?

Je voudrais vraiment cela dans une seule requête, ou une autre façon intelligente de calculer ce qui me manque!

+0

tout d'abord, je desi gn la table de sorte que les heures d'état ON et OFF sont sur la même ligne sur des colonnes différentes, alors cette tâche serait triviale. Si c'est impossible pour vous, alors vous avez beaucoup de piratage pour le faire :) –

Répondre

1

Il n'y a pas row_number() dans MySQL, mais vous pouvez faire une double jointure pour rechercher la ligne précédente:

select 
    sum(case when cur.state = 0 then 0 
     else subtime(cur.timeCol, prev.timeCol) 
     end) as TotalOnTime 
from YourTable cur 
join YourTable prev 
    on prev.timeCol < cur.timeCol 
left join YourTable inbetween 
    on prev.timeCol < inbetween.timeCol 
    and inbetween.timeCol < cur.timeCol 
where inbetween.timeCol is null; 

MySQL, vous pouvez également utiliser une variable, qui dans ce cas est probablement plus efficace:

set @total := '00:00:00'; 
set @lasttime := '00:00:00'; 

select 
    @total := addtime(@total, case 
     when state = 0 then 0 
     when @lasttime is null then 0 
     else subtime(timeCol, @lasttime) 
     end) 
, @lasttime := timeCol 
from YourTable 
order by timeCol; 

select 'Result = ', @total; 

code pour créer et table de test:

DROP TABLE IF EXISTS YourTable; 
CREATE TABLE YourTable (
    timeCol time, 
    state bit 
) ENGINE=MyISAM DEFAULT CHARSET=latin1; 

insert into YourTable values ('00:00:00', 0); 
insert into YourTable values ('04:00:00', 1); 
insert into YourTable values ('08:00:00', 0); 
insert into YourTable values ('09:00:00', 1); 
insert into YourTable values ('15:00:00', 0); 
insert into YourTable values ('20:00:00', 1); 
insert into YourTable values ('23:59:59', 0); 
+0

La complexité de cette requête me fait me demander si cela pourrait être beaucoup plus efficace si elle est faite en code et non en SQL. Mais on dirait que ça marcherait, cependant. –

+0

Je pense que je devine où vous allez avec l'exemple variable, et je pense que je suis beaucoup plus proche grâce à votre aide. Je ne connais pas le préfixe point (".") Avant le @lasttime var, qu'est-ce que cela fait? Je reçois une erreur avec cette syntaxe en place, et je ne peux pas trouver ce que cela signifie dans les manuels. – Aitch

+0

@Aitch: Cela aurait dû être un ',' virgule, pour la colonne suivante – Andomar

Questions connexes