2013-07-10 3 views
10

Was soll ich abfragen, wenn ich die aktuelle Zeile von der vorherigen Zeile subtrahieren wollte. Ich werde es auf der Schleife in vb6 verwenden. etwas wie diese:Wie kann ich eine vorherige Zeile in SQL subtrahieren?

Row 
1 
2 
3 
4 
5 

Auf dem ersten Schleifenwert 1 wird nicht in Abzug gebracht werden, da es keine vorherige Zeile hat, was in Ordnung ist. Nächste Schleife Wert 2 wird dann von der vorherigen Zeile abgezogen, die Wert 1 ist. Und so weiter bis zur letzten Zeile.

Wie kann ich diese Routine erreichen? Durch SQL-Abfrage oder VB6-Code.Jeder wird tun.

+1

Denken Sie daran, es als „vorherige Zeile“ in einer SQL-Ergebnismenge nicht so etwas ist, wenn Sie ein „ORDER BY“ Klausel verwenden, um die Reihenfolge zu definieren. Außerdem sollten Sie versuchen, in Sets mit relationalen Datenbanken zu denken, also hoffe ich, dass Ihnen jemand eine satzweise Antwort gibt (ich muss jetzt gehen). –

+0

. Ja. Aber wie kann ich das in der by by-Klausel definieren? Danke ... – Nemesis

+0

Gliederung (Entschuldigung, ich muss ausführen): Definieren Sie eine CTE, die ORDER BY verwendet, um eine Reihenfolge auszuwählen, und verwendet dann [ROW_NUMBER] (http (http://technet.microsoft.com/en-us/library/ms186734.aspx), um eine Spalte hinzuzufügen, die die Reihenfolge definiert. Fügen Sie dann den CTE zu sich selbst auf x.ROWNUM = y.ROWNUM + 1 hinzu und schließen Sie x.value-y.value ein. –

Antwort

17

Angenommen, Sie eine Bestellung Spalte haben - sagen id - dann können Sie die folgenden in SQL Server tun 2012:

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

In früheren Versionen von SQL Server, können Sie fast die gleiche Sache eine mit korrelierte Unterabfrage:

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

Dies verwendet isnull() statt coalesce() wegen eines "Bug" in SQL Server, die zweimal das erste Argument auswertet, wenn coalesce() verwenden.

Sie können dies auch mit 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; 

Alle diese davon ausgehen, dass Sie eine Spalte für die Angabe der Bestellung haben. Es könnte ein id oder ein Erstellungsdatum oder etwas anderes sein. SQL-Tabellen sind inhärent ungeordnet, so dass es keine "vorherige Zeile" gibt, ohne dass eine Spalte die Reihenfolge angibt.

+0

Was ist, wenn er keine Bestellspalte hat? ZEILENNUMMER? –

+0

Gibt es einen besonderen Grund für die Verwendung von COALESCE für die LAG anstelle des Standardarguments für die LAG-Funktion? – v010dya

+0

@Volodya. . . Gewohnheit. 'lag()' und 'lead()' nehmen mehrere Argumente an. Ich kann mich leicht an die ersten beiden erinnern - die Spalte und den Offset. –

0

Cursor:

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;