2010-11-30 7 views
18

On suppose ce tableau:MySQL: intervalle moyen entre les enregistrements

id date 
---------------- 
1  2010-12-12 
2  2010-12-13 
3  2010-12-18 
4  2010-12-22 
5  2010-12-23 

Comment puis-je trouver les intervalles moyens entre ces dates, en utilisant MySQL Seules les requêtes?

Par exemple, le calcul de ce tableau sera

(
    (2010-12-13 - 2010-12-12) 
    + (2010-12-18 - 2010-12-13) 
    + (2010-12-22 - 2010-12-18) 
    + (2010-12-23 - 2010-12-22) 
)/4 
---------------------------------- 
= (1 DAY + 5 DAY + 4 DAY + 1 DAY)/4 
= 2.75 DAY 
+2

Cela sera beaucoup plus facile sans le faire en SQL. Pourquoi avez-vous besoin de le faire en SQL? – jwueller

+1

Parce que cela semble être une chose amusante à faire. J'ai déjà implémenté ceci avec ma fonction PHP. Mais je suis curieux de voir si cela peut être fait avec MySQL sans un impact significatif sur les performances. – HyderA

+0

tout d'abord vous devez calculer diff entre 2 lignes regarder: http://stackoverflow.com/questions/3017468 –

Répondre

35

Intuitivement, ce que vous demandez doit être équivalent à l'intervalle entre la première et la dernière date, divisé par le nombre de dates moins 1.

Permettez-moi de vous expliquer plus en profondeur. Imaginez les dates sont des points sur une ligne (+ sont les dates actuelles, - sont les dates manquantes, la première date est le 12, et j'ai changé la dernière date de 24 décembre à des fins d'illustration):

++----+---+-+ 

Maintenant, ce vous voulez vraiment faire, est espacer également vos dates entre ces lignes, et de trouver combien de temps il est entre chacun d'eux:

+--+--+--+--+ 

pour ce faire, vous prenez simplement le nombre de jours entre le dernier et le premier jours, dans ce cas 24 - 12 = 12, et le diviser par le nombre d'intervalles que vous devez espacer, dans ce cas 4: 12/4 = 3.

Avec une requête MySQL

SELECT DATEDIFF(MAX(dt), MIN(dt))/(COUNT(dt) - 1) FROM a; 

Cela fonctionne sur cette table (avec vos valeurs renvoyées 2.75):

CREATE TABLE IF NOT EXISTS `a` (
    `dt` date NOT NULL 
) ENGINE=MyISAM DEFAULT CHARSET=latin1; 

INSERT INTO `a` (`dt`) VALUES 
('2010-12-12'), 
('2010-12-13'), 
('2010-12-18'), 
('2010-12-22'), 
('2010-12-24'); 
+2

D'oh, tu as raison! Si vous avez seulement des timestamps et pas des paires start/end, il n'y a pas besoin de shenanigans d'agrégation. – Dmitri

+4

+1 pour ne pas suivre un motif et voir le problème pour ce qu'il est vraiment. : D – Unreason

+1

Vous monsieur, êtes un génie! Cette solution est l'exemple parfait de la simplicité en sortant des sentiers battus. – HyderA

0

Vous devez faire jointure réflexive et d'obtenir des différences en utilisant la fonction DATEDIFF et obtenir la moyenne.

+0

Il n'y a pas de clé primaire sur la table. Donc, si je fais moi-même, comment calculer en utilisant la ligne suivante ou précédente? – HyderA

+0

pas de domaine unique? utiliser la requête interne –

+0

Yup! Ne me demandez pas, je ne l'ai pas conçu. – HyderA

2

Si les ids sont uniformément incrémentés sans lacunes, se joindre à la table se sur id + 1:

SELECT d.id, d.date, n.date, datediff(d.date, n.date) 
FROM dates d 
JOIN dates n ON(n.id = d.id + 1) 

ensuite GROUP BY et moyenne au besoin.

Si les ID ne sont pas uniformes, effectuez une requête interne pour affecter les ID ordonnés en premier.

Je suppose que vous devrez également ajouter une sous-requête pour obtenir le nombre total de lignes.

Vous pouvez également

Créer une fonction d'agrégation qui garde la trace de la date précédente, et une somme en cours d'exécution et compter. Vous aurez toujours besoin de sélectionner dans une sous-requête pour forcer le classement par date (en fait, je ne suis pas sûr que cela soit garanti dans MySQL). En y pensant, c'est une bien meilleure façon de le faire.

Et encore plus simple

Tout en notant que la solution de Vegard est beaucoup mieux.

+0

L'alternative est un bon début, laissez-moi voir ce que je peux trouver. – HyderA

1

La requête suivante renvoie le résultat correct

SELECT AVG(
     DATEDIFF(i.date, (SELECT MAX(date) 
          FROM intervals WHERE date < i.date) 
       ) 
      ) 
FROM intervals i 

mais il dirige une sous-requête dépendante qui pourrait être vraiment inefficace sans index et sur un plus grand nombre de lignes.

+1

Assez inefficace, a pris environ 2 secondes pour fonctionner sur 100 dossiers. Mais fait exactement ce que c'est censé faire. Pouvons-nous optimiser cela? – HyderA

+0

largeur sous les requêtes là je serai toujours le problème de la lenteur. –

Questions connexes