web-dev-qa-db-fra.com

Comment faire la différence entre deux lignes pour un champ de colonne?

J'ai une table comme celle-ci:

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

Les valeurs de la colonne rowInt sont des entiers, mais pas dans une séquence avec le même incrément. Je peux utiliser le SQL suivant pour lister les valeurs par rowInt:

SELECT * FROM myTable ORDER BY rowInt;

Cela listera les valeurs par rowInt. Comment obtenir la différence de valeur entre deux lignes avec le résultat suivant:

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

La table est en SQL 2005 (Miscrosoft)

51
David.Chu.ca
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 réfléchissant, l’utilisation d’une sous-requête dans la sélection (la réponse d’Ala Quassnoi) peut être plus efficace. J'essayerais différentes versions et examinerais les plans d'exécution pour voir laquelle fonctionnerait le mieux avec la taille de l'ensemble de données que vous avez ...

54
MatBailie
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
24
Quassnoi

Si vous voulez vraiment être sûr des ordres, utilisez "Row_Number ()" et comparez l'enregistrement suivant de l'enregistrement en cours (examinez de près la clause "on")

T1.ID + 1 = T2.ID

Vous joignez essentiellement la ligne suivante à la ligne actuelle, sans spécifier "min" ni "top". Si vous avez un petit nombre d'enregistrements, d'autres solutions de "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
11
Sung M. Kim

SQL Server 2012 et versions ultérieures prennent en charge LAG / LEAD des fonctions permettant d’accéder à la ligne précédente ou suivante. SQL Server 2005 ne prend pas cela en charge (dans SQL2005, vous avez besoin d'une jointure ou de quelque chose d'autre).

Un exemple SQL 2012 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) renverra la valeur de la ligne suivante par rapport à l'ordre donné dans la clause "over". 

8
Ansonmus

SQL Server prend-il en charge les fonctions d'analyse?

select   rowint,
         value,
         value - lag(value) over (order by rowint) diff
from     myTable
order by rowint
/
2
David Aldridge

Requête pour 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
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
mns