2013-07-10 17 views
10

Cosa dovrei richiedere se volessi sottrarre la riga corrente alla riga precedente. Lo userò su loop in vb6. qualcosa di simile:Come posso sottrarre una riga precedente in sql?

Row 
1 
2 
3 
4 
5 

Sul primo valore loop 1 non verranno detratti perché non ha nessuna riga precedente, che è ok. Il valore del ciclo successivo 2 verrà quindi detratto dalla riga precedente che è il valore 1. E così via fino all'ultima riga.

Come posso ottenere questa routine? Da query SQL o codice VB6. Qualsiasi cosa succederà.

+1

Tenete a mente non c'è alcuna cosa come "riga precedente" in un risultato SQL imposta a meno che non si utilizza un "ORDER BY" clausola per definire l'ordine. Inoltre, dovresti provare a pensare in termini di set con database relazionali, quindi spero che qualcuno ti dia una risposta settata (devo andarmene ora). –

+0

., Sì. Ma come posso definirlo in ordine per clausola? Grazie ... – Nemesis

+0

Struttura (scusate devo eseguire): definire un CTE che utilizza ORDER BY per scegliere un ordine e quindi utilizza [ROW_NUMBER] (http : //technet.microsoft.com/en-us/library/ms186734.aspx) per aggiungere una colonna che definisce l'ordine. Quindi unire il CTE a se stesso su x.ROWNUM = y.ROWNUM + 1 e includere x.value-y.value. –

risposta

17

Supponendo di avere una colonna ordinamento - dice id - allora si può fare quanto segue in SQL Server 2012:

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

Nelle versioni precedenti di SQL Server, si può fare quasi la stessa cosa con un subquery correlata:

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

Questo utilizza isnull() invece di coalesce() a causa di un "bug" in SQL Server che valuta il primo argomento due volte quando si utilizza coalesce().

Si può anche fare questo con 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; 

Tutti questi supporre che avete un po 'di colonna per specificare l'ordinamento. Potrebbe essere un id, una data di creazione o qualcos'altro. Le tabelle SQL sono intrinsecamente non ordinate, quindi non esiste una "riga precedente" senza una colonna che specifica l'ordine.

+0

Cosa succede se non ha una colonna di ordinazione? ROW_NUMBER? –

+0

C'è un motivo particolare per usare COALESCE sul LAG, piuttosto che l'argomento 'default' per la funzione LAG? – v010dya

+0

@Volodya. . . Abitudine. 'lag()' e 'lead()' accettano diversi argomenti. Ricordo facilmente i primi due: la colonna e l'offset. –

0

con il cursore:

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; 
Problemi correlati