Как я могу вычесть предыдущую строку в sql?

Что мне делать, если я хочу вычесть текущую строку в предыдущую строку. Я буду использовать его при циклировании в vb6. Что-то вроде этого:

Row
1
2
3
4
5

В первом цикле значение 1 не будет вычитаться из-за отсутствия предыдущей строки, что нормально. Затем следующее значение цикла 2 будет вычитаться предыдущей строкой, которая равна 1. И так далее до последней строки.

Как я могу достичь этой процедуры? С помощью SQL-запроса или кода VB6. Любой будет делать.

Ответ 1

Предполагая, что у вас есть столбец заказа - скажем id - тогда вы можете сделать следующее в SQL Server 2012:

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

В более ранних версиях SQL Server вы можете сделать почти то же самое, используя коррелированный подзапрос:

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

Это использует isnull() вместо coalesce() из-за "ошибки" в SQL Server, которая дважды оценивает первый аргумент при использовании coalesce().

Вы также можете сделать это с помощью 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;

Все это предполагает, что у вас есть столбец для указания порядка. Это может быть id, дата создания или что-то еще. SQL-таблицы по сути неупорядочены, поэтому нет такой вещи, как "предыдущая строка" без столбца, определяющего порядок.

Ответ 2

Использование курсора:

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;