Question Comment puis-je soustraire une ligne précédente dans sql?


Que dois-je demander si je voulais soustraire la ligne actuelle à la ligne précédente. Je vais l'utiliser en boucle dans vb6. Quelque chose comme ça:

Row
1
2
3
4
5

Sur la première boucle, la valeur 1 ne sera pas déduite car il n'y a pas de ligne précédente, ce qui est correct. La prochaine valeur de la boucle 2 sera alors déduite par la ligne précédente qui est la valeur 1. Et ainsi de suite jusqu'à la dernière ligne.

Comment puis-je accomplir cette routine? Par requête SQL ou code VB6.


11
2017-07-10 01:04


origine


Réponses:


En supposant que vous avez une colonne de commande - dites id - alors vous pouvez faire ce qui suit dans SQL Server 2012:

select col,
       col - coalesce(lag(col) over (order by id), 0) as diff
from t;

Dans les versions antérieures de SQL Server, vous pouvez faire presque la même chose en utilisant une sous-requête corrélée:

select col,
       col - isnull((select top 1 col
                     from t t2
                     where t2.id < t.id
                     order by id desc
                    ), 0)
from t

Cela utilise isnull() au lieu de coalesce() en raison d'un "bug" dans SQL Server qui évalue le premier argument deux fois lors de l'utilisation coalesce().

Vous pouvez aussi le faire avec row_number():

with cte as (
      select col, row_number() over (order by id) as seqnum
      from t
     )
select t.col, t.col - coalesce(tprev.col, 0) as diff
from cte t left outer join
     cte tprev
     on t.seqnum = tprev.seqnum + 1;

Tous supposent que vous avez une colonne pour spécifier le classement. Ce pourrait être un id, ou une date de création ou autre chose. Les tables SQL sont intrinsèquement non ordonnées, il n'y a donc pas de "ligne précédente" sans colonne spécifiant le classement.


18
2017-07-10 01:16



Utilisation du curseur:

CREATE TABLE t (id int)
INSERT INTO t
VALUES(1)

INSERT INTO t
VALUES(2)

INSERT INTO t
VALUES(3)

INSERT INTO t
VALUES(4) 

DECLARE @actual int; 
DECLARE @last int;
DECLARE @sub int; 

SET @last = 0; 

DECLARE sub_cursor CURSOR FOR
    SELECT *
    FROM t OPEN sub_cursor 
    FETCH NEXT
    FROM sub_cursor INTO @actual; 

WHILE @@FETCH_STATUS = 0 BEGIN
    SELECT @sub = @actual - @last print cast(@actual AS nvarchar) + '-' + cast(@last AS nvarchar) + '=' + cast(@sub AS nvarchar)
    SET @last = @actual 
    FETCH NEXT FROM sub_cursor INTO @actual; 
END

DROP TABLE t 
CLOSE sub_cursor; DEALLOCATE sub_cursor;

2
2018-01-09 17:50