2016-07-22 11 views
0

Ich muss Paare von Zeilen aus einer Tabelle abhängig von Werten in einer Spalte auswählen. Dies ist meine Quelltabelle:Wählen Sie Paare von Zeilen in SQL (Sollte in SQL Server 2008 und 2012 funktionieren)

EntryID | Code 
----------------- 
11  | 40 
22  | 100 
23  | 80 
24  | 60 
35  | 90 
46  | 80 
47  | 30 
58  | 80 
69  | 20 
110  | 40 

ich nur die Zeilen extrahieren müssen, wo der Code 80 ist und die erste Zeile nach dem Code 80. Das ist also der Ausgang Ich suche:

Code 
------ 
80 
60 
80 
30 
80 
20 

Ich kann dies mit Cursors erreichen, aber meine tatsächliche Tabelle hat 1 Million + Datensätze. Cursor sind also definitiv keine Option.

ich bisher getan haben dies:

declare @currentCode int 
declare @rowPtr int 
declare @code80row bit 
declare @nextRowTaken bit 
declare @T1 table (RowNum int, Code int) 
declare @Final table (RowNum int, Code int) 

set @rowPtr = 1 
set @code80row = 0 
set @nextRowTaken = 0 

insert into @T1 select ROW_NUMBER() over (order by EntryID desc) RowNum, Code from Codes 
set @currentCode = (select code from @t1 where RowNum = @rowPtr) 
while @currentCode > 0 
begin 
    if @currentCode = 80 
    begin 
     set @code80row = 1 
     set @nextRowTaken = 0 
     insert into @Final(RowNum, Code) values (@rowPtr, @currentCode) 
    end 
    else if (@code80row = 1 and @nextRowTaken = 0) 
    begin 
     set @code80row = 0 
     set @nextRowTaken = 1 
     insert into @Final(RowNum, Code) values (@rowPtr, @currentCode) 
    end 
    set @rowPtr = @rowPtr + 1 
    set @currentCode = (select code from @t1 where RowNum = @rowPtr) 
end 
select * from @Final 

einen besseren Weg, um dieses Ergebnis zu erhalten, ist es?

EDIT: Nach @ Serg Antwort unten, bevor er die letzte Zeile hinzugefügt, habe ich versucht, diese auch .... Dieses jemand helfen kann mit unterschiedlichen Bedürfnissen:

;with cte as (
    select Row_Number() over (order by EntryID) RowNum, entryid, Code from Codes 
) 
select ft.RowNum, st.RowNum, ft.entryid, st.entryid, ft.Code, st.Code 
from cte as ft join cte as st 
on ft.code = 80 and ft.RowNum = st.RowNum-1 

die gibt:

RowNum |RowNum |entryid |entryid |Code |Code 
-------------------------------------------- 
3  |4  |23  |24  |80 |60 
6  |7  |46  |47  |80 |30 
8  |9  |58  |69  |80 |20 

Antwort

1

Wenn Sie auf 2008 sind und kein Blei/hinken

with cte as (
    select rn=ROW_NUMBER() over (order by EntryID desc), EntryID, Code 
    from Codes 
) 
select t2.* 
from cte c1 
cross apply ( 
     select EntryID, Code 
     from cte c2 
     where c1.rn between c2.rn and c2.rn+1 
) t2 
where c1.Code=80; 
+0

Gutes Auge, sah nicht die "2008" dort. Aber Sie müssen fügen Sie die "80" Bedingung –

+0

Korrigiert. Danke @Juan – Serg

+0

Vielen Dank @Serg – KSK

0

Dies wird Ihnen aktuelle und die nächste geben:

SELECT EntryID , 
    Code, 
    LAG(Code, 1,0) OVER (ORDER BY EntryID) AS NextCode 
FROM Codes 
WHERE Code = 80 
ORDER BY EntryID 


EntryID | Code | NextCode 
--------------------- 
23  | 80 | 60 
46  | 80 | 30 
58  | 80 | 20 
+1

führt Sie nicht geben nächste und LAG geben Ihnen vor? – Hogan

+0

@ Jonathan, ich muss dies in SqlServer2008 und SqlServer2012 ausführen. Lead and Lag arbeiten nur im Jahr 2012 :( – KSK

+0

Warum benutzen Sie eine Datenbank, die das Ende ihres Lebens überschritten hat? Sie müssen so schnell wie möglich aussteigen. –

2

Ja, Sie können die Verzögerungsfunktion, um den vorherigen Wert eines Feldes zu sehen.

SELECT * 
FROM (
    SELECT *, LAG(Code) OVER (ORDER BY EntryID) AS LAST_CODE 
    FROM tablename 
) 
WHERE Code = 80 OR LAST_CODE = 80 

Ziemlich sicher, dass Sie es in einem where auf SQL-Server verwenden können, aber ich habe keine Zeit, jetzt zu testen und ich weiß, dass Code arbeiten.

+1

Zuerst nur, weil ich die [DEMO] machte (http://rextester.com/BLJHF16167);) –

+0

Nice @JuanCarlosOropeza das ist hilfreich! – Hogan

+0

Und ja, Sie brauchen eine Unterabfrage, und nur realisieren ** kann ** die Windows-Funktion in einem 'wo' –