2009-07-01 9 views
3

Comment obtenir une valeur de la ligne de résultat précédente d'une instruction SELECTCOMMENT CHOISIR LA VALEUR DE LA RANGÉE PRÉCÉDENTE?

Si nous avons une table appelée cardevent et a des lignes [ID (int), Value (Money)] et nous avons quelques lignes dedans, par exemple

ID --Value 

1------70 
1------90 
2------100 
2------150 
2------300 
3------150 
3------200 
3-----250 
3-----280 

ainsi de suite ...

Comment faire une requête qui recevez chaque ID de ligne, la valeur et la valeur précédente de la ligne dans laquelle les données apparaissent comme suit

ID --- Value ---Prev_Value 

1 ----- 70 ---------- 0 
1 ----- 90 ---------- 70 
2 ----- 100 -------- 90 
2 ------150 -------- 100 
2 ------300 -------- 150 
3 ----- 150 -------- 300 
3 ----- 200 -------- 150 
3 ---- 250 -------- 200 
3 ---- 280 -------- 250 

ainsi de suite.

i faire la requête suivante, mais il est si mauvais dans la performance en énorme quantité de données

SELECT cardevent.ID, cardevent.Value, 
     (SELECT F1.Value 
     FROM cardevent as F1 
     where F1.ID = (SELECT Max(F2.ID) 
         FROM cardevent as F2 
         WHERE F2.ID < cardevent.ID) 
    ) AS Prev_Value 
FROM cardevent 

Alors quelqu'un peut me aider à obtenir la meilleure solution pour un tel problème?

+2

pourquoi avez-vous marqués avec 2 différents SGBDR? –

+0

Dupliquer vers celui-ci (autre utilisateur, autre nom de table): http://stackoverflow.com/questions/742226/how-to-get-a-value-from-previous-result-row-of-a-select- déclaration – MicSim

+1

doit être une question de devoirs .... –

Répondre

5

Celui-ci devrait fonctionner correctement pour les deux bases de données:

SELECT cardevent.ID, cardevent.Value, 
    (SELECT TOP 1 F1.Value 
    FROM cardevent as F1 
    WHERE F1.ID < cardevent.ID 
    ORDER BY F1.ID DESC 
    ) AS Prev_Value 
FROM cardevent 

Mise à jour: En supposant que ID est pas unique, mais que la combinaison d'ID et La valeur est unique (vous devez spécifier ce qui impose votre commande sur la table, donc on sait quelle est la ligne précédente), vous devez utiliser cette requête:

select cardevent.ID, cardevent.Value, 
    (select TOP 1 F1.Value from cardevent as F1 
    where (F1.ID < cardevent.ID) or (F1.ID = cardevent.ID and F1.Value < cardevent.Value) 
    order by F1.ID DESC, F1.Value DESC 
    ) AS Prev_Value 
from cardevent 
+0

@MicSim - je votre requête, mais il affiche l'erreur « au plus un enregistrement peut être renvoyé par la sous-requête » affichage rien dans le champ prev_value – Gopal

+0

sortie Affichage comme celui-ci .... PERSONID \t CARDEVENTDATE \t Expr1002 \t Prev_Value #Name ? \t #Nom? \t #Nom?\t #Nom? #Nom? \t #Nom? \t #Nom? \t #Nom? #Nom? \t #Nom? \t #Nom? \t #Nom? #Nom? \t #Nom? \t #Nom? \t #Nom? – Gopal

+0

Juste testé ci-dessus requête avec Access 2000 (ne pas avoir 2003 ici) et ça fonctionne. Peut-être avez-vous prolongé/modifié la requête? – MicSim

2

Essayez quelque chose comme ceci:

SELECT C.ID, C.Value, COALESCE(C1.Value, 0) 
FROM cardevent C 
    LEFT JOIN cardevent C1 
    ON C1.Id = (SELECT MAX(id) FROM cardevent C2 where C2.Id < C.Id) 
+0

+1. Cela semble être le fastes de toutes les solutions données. –

+0

Il semble se compiler au même plan d'exécution que la solution de MicSim - et cela a du sens si vous y regardez de plus près. Je dirais que les deux sont ok. –

+0

Je n'ai pas regardé assez près les plans d'exécution réels, seulement aux pourcentages donnés par SQL Server. Toutes les solutions fonctionnent afaik, la différence principale est le temps d'exécution et la lisibilité. Le vôtre est le plus rapide (ou aussi rapide que la solution de MicSim) et le plus lisible. Le mien est ... bon, pas si bon

0

Comment fonctionne la suite?

SELECT F1.ID, F1.Value, F3.Value 
FROM cardevent F1 
    INNER JOIN (
     SELECT F1.ID, mID = MAX(F2.ID) 
     FROM cardevent F1 
      INNER JOIN cardevent F2 ON F2.ID < F1.ID 
     GROUP BY F1.ID 
    ) F2 ON F2.id = F1.ID 
    INNER JOIN cardevent F3 ON F3.ID = F2.mID 
UNION ALL 
SELECT F1.ID, F1.Value, 0 
FROM cardevent F1 
    INNER JOIN (
     SELECT ID = MIN(ID) 
     FROM cardevent 
    ) F2 ON F2.ID = F1.ID 
ORDER BY 1 
0

Je préfère TOP 1 au lieu de MAX(...), qui à mon humble avis devrait être aussi plus rapide:

SELECT  C.ID, C.Value, COALESCE(C1.Value, 0) 
FROM  cardevent C 
LEFT JOIN cardevent C1 
     ON C1.ID = (SELECT TOP 1 C2.ID FROM cardevent C2 WHERE C2.ID < C.ID ORDER BY C2.ID) 
+0

Utilisation de la base de données Access 2003, n'accepte pas la fonction coalesce – Gopal

+0

@Gopal: Je ne suis pas sur l'efficacité du code dans MSAccess, mais IIF et ISNULL devraient aider: "IIF (ISNULL (C1.Value) , 0, C1.Valeur)) " – van

Questions connexes