2009-03-11 7 views
44

I ont un tableau comme suit:Comment obtenir une différence entre deux lignes pour un champ de colonne?

rowInt Value 
2  23 
3  45 
17  10 
9  0 
.... 

Les valeurs de rowInt de colonne sont des nombres entiers, mais pas dans une séquence de même increament. Je peux utiliser le sql suivant pour lister les valeurs par rowInt:

SELECT * FROM myTable ORDER BY rowInt; 

Ceci affichera les valeurs par rowInt. Comment obtenir obtenir la différence de valeur entre les deux lignes avec le résultat comme celui-ci:

rowInt Value Diff 
2  23 22 --45-23 
3  45 -35 --10-45 
9  0  -45 --0-45 
17  10 10 -- 10-0 
.... 

Le tableau est dans SQL 2005 (Miscrosoft)

+0

Est-il prévu que vous ayez 10-45 dans la deuxième rangée? D'où prenez-vous un 10? – Quassnoi

+0

certains calculs ne sont pas cohérents ... row2 (45-23) est row3-row2, mais row9's (0-45) est row9-row3, ne devrait-il pas être (10-0) qui est row17-row9? – MatBailie

+0

Il semble que vous vouliez compter la différence entre les valeurs adjacentes dans votre jeu de lignes d'origine (2, 3, 17, 9). Ensuite, je vais devoir vous demander: quelle est la colonne sur laquelle votre ensemble de lignes ORIGINAL est trié? Rappelez-vous qu'il n'y a pas de «commande par défaut» dans SQL. – Quassnoi

Répondre

46
SELECT 
    [current].rowInt, 
    [current].Value, 
    ISNULL([next].Value, 0) - [current].Value 
FROM 
    sourceTable  AS [current] 
LEFT JOIN 
    sourceTable  AS [next] 
     ON [next].rowInt = (SELECT MIN(rowInt) FROM sourceTable WHERE rowInt > [current].rowInt) 

EDIT: En y repensant, en utilisant une sous-requête dans le select (réponse de ala Quassnoi) peut être plus efficace. Je voudrais essayer différentes versions, et regarder les plans d'exécution pour voir ce qui fonctionnerait mieux sur la taille de l'ensemble de données que vous avez ...

+0

S'il a un index sur rowInt (ce que je pense qu'il fait) alors ma requête est plus efficace. S'il ne le fait pas, alors c'est le cas (s'il est possible de parler d'efficacité dans ce cas). Regardez ici pour plus de détails: http: // stackoverflow.com/questions/590079/pour-autoincrement-fields-maxid-vs-top-1-id-order-by-id-desc – Quassnoi

+0

J'ai créé une table fictive avec 1 million d'enregistrements créés au hasard et j'ai trouvé que les deux requêtes prenaient le même temps . En fait la seule différence dans les plans d'exécution était la position d'une fonction SORT (j'ai trié la sortie finale) – MatBailie

+0

J'aime votre méthode. Cela fonctionne bien avec mon cas. –

21
SELECT rowInt, Value, 
     COALESCE(
     (
     SELECT TOP 1 Value 
     FROM myTable mi 
     WHERE mi.rowInt > m.rowInt 
     ORDER BY 
      rowInt 
     ), 0) - Value AS diff 
FROM myTable m 
ORDER BY 
     rowInt 
10

Si vous voulez vraiment être sûr de commandes, utilisez "Row_Number()" et comparer l'enregistrement suivant des enregistrement en cours (regarder de près « sur » clause)

T1.ID + 1 = T2.ID 

Vous joindrez essentiellement la ligne suivante avec la ligne actuelle, sans spécifier « min » ou faire « top ». Si vous avez un petit nombre d'enregistrements, d'autres solutions par "Dems" ou "Quassanoi" fonctionneront bien.

with T2 as (
    select ID = ROW_NUMBER() over (order by rowInt), 
      rowInt, Value 
    from myTable 
) 
select T1.RowInt, T1.Value, Diff = IsNull(T2.Value, 0) - T1.Value 
from ( SELECT ID = ROW_NUMBER() over (order by rowInt), * 
      FROM myTable) T1 
     left join T2 on T1.ID + 1 = T2.ID 
ORDER BY T1.ID 
2

Est-ce que SQL Server prend en charge les fonctions analytiques?

select rowint, 
     value, 
     value - lag(value) over (order by rowint) diff 
from  myTable 
order by rowint 
/
+0

Msg 195, niveau 15, état 10, ligne 3 'lag' n'est pas un nom de fonction intégré reconnu. – Sung

+0

J'ai donné un point parce que oui Denali fait ... bien que peut-être le serveur SQL n'a pas quand cette réponse a été postée – Pixelated

+1

@FairFunk J'ai soustrait un point parce que la question est étiquetée 2005, donc la fonctionnalité Denali est hors de propos. –

0
select t1.rowInt,t1.Value,t2.Value-t1.Value as diff 
from (select * from myTable) as t1, 
    (select * from myTable where rowInt!=1 
     union all select top 1 rowInt=COUNT(*)+1,Value=0 from myTable) as t2 
where t1.rowInt=t2.rowInt-1 
0

Recherche de trouver la différence de date entre 2 lignes d'une seule colonne

SELECT 
Column name, 
DATEDIFF(
(SELECT MAX(date) FROM table name WHERE Column name < b. Column name), 
Column name) AS days_since_last 
FROM table name AS b 
+0

C'est une question très ancienne et votre réponse ne répond pas vraiment à la même question posée. – shawnt00

2

SQL Server 2012 et les fonctions le soutien LAG/LEAD pour accéder à la ligne précédente ou suivante. SQL Server 2005 ne supporte pas cela (dans SQL2005, vous avez besoin d'une jointure ou autre chose).

A SQL 2012 exemple sur ces données

/* Prepare */ 
select * into #tmp 
from 
(
    select 2 as rowint,  23 as Value 
    union select 3,  45 
    union select 17,  10 
    union select 9,  0 
) x 


/* The SQL 2012 query */ 
select rowInt, Value, LEAD(value) over (order by rowInt) - Value 
from #tmp 

LEAD (valeur) renvoie la valeur de la ligne suivante en ce qui concerne l'ordre donné dans « plus » clause.

+1

LAG. Pas de CONT. Il ne me laissera pas éditer parce que vous devez changer 6 caractères – danmiser

Questions connexes