2013-07-10 15 views
10

O czym powinienem zapytać, jeśli chcę odjąć bieżący wiersz do poprzedniego wiersza. Użyję go na pętli w vb6. coś takiego:Jak mogę odjąć poprzedni wiersz w sql?

Row 
1 
2 
3 
4 
5 

Na pierwszej pętli wartość 1, nie zostaną odjęte, ponieważ nie ma poprzedni rząd, który jest OK. Następnie druga wartość pętli 2 zostanie odjęta przez poprzedni wiersz, który jest wartością 1. I tak dalej aż do ostatniego wiersza.

Jak mogę osiągnąć ten program? Za pomocą zapytania SQL lub kodu VB6. Każdy to zrobi.

+1

Należy pamiętać, że nie ma czegoś takiego jak „poprzedniego wiersza” w wyniku SQL ustawiony chyba użyć „BY” klauzuli aby określić kolejność. Powinieneś także spróbować myśleć w kategoriach zestawów z relacyjnymi bazami danych, więc mam nadzieję, że ktoś da ci pewną odpowiedź (muszę teraz wyjść). –

+0

., Tak.Ale mogę to zdefiniować w kolejności według? Dzięki ... – Nemesis

+0

Zarys (przepraszam muszę uruchomić): zdefiniuj WRT, który używa ORDER BY, aby wybrać zamówienie, a następnie używa [ROW_NUMBER] (http : //technet.microsoft.com/en-us/library/ms186734.aspx), aby dodać kolumnę definiującą zamówienie. Następnie połącz CTE ze sobą na x.ROWNUM = y.ROWNUM + 1 i dołącz wartość x.value-y.value. –

Odpowiedz

17

Zakładając masz kolumnę zamówień - mówią id - wtedy można wykonać następujące czynności w SQL Server 2012:

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

we wcześniejszych wersjach SQL Server, można zrobić prawie to samo za pomocą podzapytanie skorelowane:

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

używa isnull() zamiast coalesce() powodu „bug” w SQL Server, który ocenia pierwszy argument dwukrotnie podczas korzystania coalesce().

Można również zrobić to z 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; 

Wszystkie te zakładają, że masz jakąś kolumnę określającą kolejność. Może to być id lub data utworzenia lub coś innego. Tabele SQL są z natury nieuporządkowane, więc nie istnieje coś takiego jak "poprzedni wiersz" bez kolumny określającej kolejność.

+0

Co, jeśli nie ma kolumny do zamawiania? NUMER WIERSZA? –

+0

Czy istnieje konkretny powód, aby używać COALESCE na LGD, a nie "domyślny" argument funkcji LAG? – v010dya

+0

@Volodya. . . Nawyk. 'lag()' i 'lead()' pobierają kilka argumentów. Z łatwością pamiętam dwa pierwsze - kolumnę i przesunięcie. –

0

kursorem:

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;