2009-10-22 7 views
1

Compte tenu de la définition de la table:fonction globale en comparaison de 2 lignes dans la même table (SQL)

create table mytable (
    id integer, 
    mydate datetime, 
    myvalue integer) 

Je veux obtenir la réponse suivante par une seule requête SQL:

id date_actual value_actual date_previous value_previous 

où :

date_previous is the maximum of all the dates preceeding date_actual 
for each id and values correspond with the two dates 
{max(date_previous) < date_actual ?} 

Comment puis-je y parvenir?

Merci pour vos conseils

Répondre

1

Ceci est une variante de la commune requête « le plus grand groupe N par » qui vient chaque semaine sur StackOverflow.

SELECT m1.id, m1.mydate AS date_actual, m1.myvalue AS value_actual, 
    m2.mydate AS date_previous, m2.myvalue AS value_previous 
FROM mytable m1 
LEFT OUTER JOIN mytable m2 
    ON (m1.id = m2.id AND m1.mydate > m2.mydate) 
LEFT OUTER JOIN mytable m3 
    ON (m1.id = m3.id AND m1.mydate > m3.mydate AND m3.mydate > m2.mydate) 
WHERE m3.id IS NULL; 

En d'autres termes, est m2 toutes les lignes avec le même id et une moindre mydate, mais nous voulons que celui de sorte qu'il n'y a pas de ligne m3 avec une date entre m1 et m2. En supposant que les dates sont uniques, il n'y aura qu'une seule ligne dans m2 où cela est vrai.

+1

@Bill: une idée de la façon dont cette implémentation fonctionne par rapport à '... = MAX (...)'? – van

+0

Dans mon expérience, il fonctionne mieux, mais j'utilise MySQL plus que SQL Server. Je sais que MySQL n'exécute pas les requêtes group-by aussi efficacement que SQL Server. Vous devriez donc tester les deux requêtes et voir comment elles se comparent dans votre environnement. –

0

En supposant que j'ai bien compris vos besoins, voici quelque chose que vous pouvez essayer.

select a.id, 
     a.mydate as date_actual, 
     a.value as value_actual, 
     b.date as date_previous, 
     b.value as value_previous 
from mytable a, mytable b 
where a.id = b.id and 
     a.mydate > b.mydate and 
     b.mydate = (select max(mydate) from mytable c where c.id = a.id and c.mydate < a.mydate) 

Toutes les excuses pour le SQL moche. Je suis sûr qu'il y a de meilleures façons de le faire.

+0

Fonctionne si LEFT JOIN a été utilisé. Comme c'est le cas maintenant, il ne retournera pas les lignes qui n'ont pas de valeurs précédentes. – van

+0

@van, merci de le signaler. tu as raison. Je vais modifier la requête pour utiliser les jointures à gauche. – Rahul