2016-10-11 19 views
8

Ich arbeite mit SQL Server 2016 und ich kann nicht herausfinden, wie diese Abfrage erstellt wird.SQL Server: Daten zwischen Zeilen vergleichen

Lassen Sie uns sagen, dass ich eine Tabelle wie folgt aus:

ID EntryTime    ResultTime 
1 2016-05-02 13:30:00  2016-05-02 21:50:00 
2 2016-05-02 14:45:00  2016-05-02 22:00:00 
3 2016-05-02 16:30:00  2016-05-02 22:21:00 
4 2016-05-03 01:00:00  2016-05-03 03:33:00 
5 2016-05-03 10:30:00  2016-05-04 07:47:00 
6 2016-05-03 12:30:00  2016-05-03 22:45:00 
7 2016-05-04 11:30:00  2016-05-05 21:30:00 
8 2016-05-04 12:30:00  2016-05-04 22:58:00 
9 2016-05-04 13:30:00  2016-05-04 23:04:00 
10 2016-05-04 13:45:00  2016-05-04 22:59:00 
11 2016-05-04 14:00:00  2016-05-04 22:59:00 
12 2016-05-04 14:15:00  2016-05-04 23:04:00 
13 2016-05-04 17:45:00  2016-05-04 21:47:00 
14 2016-05-05 23:30:00  2016-05-06 03:25:00 
15 2016-05-05 23:45:00  2016-05-06 03:30:00 
16 2016-05-06 00:00:00  2016-05-06 03:32:00 
17 2016-05-06 00:15:00  2016-05-06 03:31:00 
18 2016-05-06 00:30:00  2016-05-06 03:25:00 
19 2016-05-06 00:45:00  2016-05-06 02:50:00 
20 2016-05-06 01:00:00  2016-05-06 03:25:00 

ich nur die Zeilen auswählen möchten, dass der Eintrag Datumzeit nach dem letzten gewählten Ergebnis Datetime ist.

Zum Beispiel: Die Ergebniszeit für Zeile 1 ist "2016-05-02 21:50:00", also wird die nächste Zeile Zeile 4 sein, weil dies die erste Zeile ist, die die Eingabezeit nach der Ergebniszeit ist wurde zuletzt ausgewählt, die nächste Zeile soll nach der Ergebniszeit von Zeile 4 liegen (nach "2016-05-03 03:33:00"), so dass die nächste Zeile die Zeile 5 ist.

Das angeforderte Ergebnis lautet:

+0

Ihre gewünschte Ausgabe ist unklar .. können Sie aufwendiger sein ... – Teja

+0

Ich denke, Sie sind der einzige weiß das Ergebnis –

+0

Interessant ... Definitiv kann es in WHILE-Schleife, aber als einzelne SELECT, nicht getan werden Sicher ... – Anton

Antwort

2

Eine Möglichkeit, dies zu tun, ist die Verwendung eines rekursiven CTE, um die nächste Zeile zu erhalten. Zum Beispiel

EDIT: Für mehrere "Symbole", hier ist eine Methode, die funktionieren würde (mit Beispieldaten).

DECLARE @myTable TABLE (Symbol CHAR(3), EntryTime DATETIME, ResultTime DATETIME) 
INSERT @myTable VALUES ('AAA','2016-05-02 13:30:00','2016-05-02 21:50:00') 
,('AAA','2016-05-02 14:45:00','2016-05-02 22:00:00') 
,('AAA','2016-05-02 16:30:00','2016-05-02 22:21:00') 
,('AAA','2016-05-03 01:00:00','2016-05-03 03:33:00') 
,('AAA','2016-05-03 10:30:00','2016-05-04 07:47:00') 
,('AAA','2016-05-03 12:30:00','2016-05-03 22:45:00') 
,('AAA','2016-05-04 11:30:00','2016-05-05 21:30:00') 
,('AAA','2016-05-04 12:30:00','2016-05-04 22:58:00') 
,('AAA','2016-05-04 13:30:00','2016-05-04 23:04:00') 
,('AAA','2016-05-04 13:45:00','2016-05-04 22:59:00') 
,('AAA','2016-05-04 14:00:00','2016-05-04 22:59:00') 
,('AAA','2016-05-04 14:15:00','2016-05-04 23:04:00') 
,('AAA','2016-05-04 17:45:00','2016-05-04 21:47:00') 
,('AAA','2016-05-05 23:30:00','2016-05-06 03:25:00') 
,('AAA','2016-05-05 23:45:00','2016-05-06 03:30:00') 
,('AAA','2016-05-06 00:00:00','2016-05-06 03:32:00') 
,('AAA','2016-05-06 00:15:00','2016-05-06 03:31:00') 
,('AAA','2016-05-06 00:30:00','2016-05-06 03:25:00') 
,('AAA','2016-05-06 00:45:00','2016-05-06 02:50:00') 
,('AAA','2016-05-06 01:00:00','2016-05-06 03:25:00') 
,('BBB','2016-05-02 01:00:00','2016-05-02 03:01:00') 
,('BBB','2016-05-02 02:00:00','2016-05-02 03:05:00') 
,('BBB','2016-05-02 03:00:00','2016-05-02 03:40:00') 
,('BBB','2016-05-02 04:00:00','2016-05-02 04:01:00') 
,('BBB','2016-05-02 05:00:00','2016-05-03 07:00:00') 
,('BBB','2016-05-02 06:00:00','2016-05-02 07:00:00') 
,('BBB','2016-05-03 06:00:00','2016-05-03 07:05:00') 
,('BBB','2016-05-04 06:01:00','2016-05-04 07:08:00') 
,('BBB','2016-05-04 06:07:00','2016-05-04 07:52:00') 
,('BBB','2016-05-05 06:00:00','2016-05-05 07:49:00') 
,('CCC','2016-05-05 06:00:00','2016-05-05 07:04:00') 
,('CCC','2016-05-05 06:05:00','2016-05-05 06:55:00') 
,('CCC','2016-05-05 07:00:00','2016-05-05 07:10:00') 
,('CCC','2016-05-05 07:06:00','2016-05-05 08:05:00') 
,('CCC','2016-05-05 08:00:00','2016-05-05 08:15:00') 
,('CCC','2016-05-05 08:09:00','2016-05-05 09:00:00'); 

WITH myTable AS (
    SELECT Symbol, EntryTime, ResultTime, ROW_NUMBER() OVER (PARTITION BY Symbol ORDER BY EntryTime) RN 
    FROM @myTable) 
, CTE AS (
    SELECT * 
    FROM myTable 
    WHERE RN = 1 
    UNION ALL 
    SELECT T.* 
    FROM CTE 
    CROSS APPLY (
     SELECT Symbol, EntryTime, ResultTime, RN 
     FROM (
      SELECT *, ROW_NUMBER() OVER (ORDER BY EntryTime) RN2 
      FROM myTable 
      WHERE Symbol = CTE.Symbol 
      AND EntryTime > CTE.ResultTime) Z 
     WHERE RN2 = 1) T 
    ) 
SELECT Symbol, EntryTime, ResultTime--, RN [ID?] 
FROM CTE 
ORDER BY Symbol; 
+0

+1, um zu zeigen, wie man es mit rekursivem CTE macht, obwohl ein einfacher Cursor, der einmal durch jede Zeile schaut, wahrscheinlich effizienter ist als Self-Joins. –

+0

MAXRECURSION mit Nullwert sollte angegeben werden, oder? Der Standardwert ist 100. – Anton

+0

Perfekte Antwort, schnell und effizient, ich habe gerade "Reihenfolge nach ID" in Zeile 12 in "Reihenfolge nach EntryTime" geändert, weil die ID nicht immer in der Reihenfolge der Eintrittszeiten ist. ** Aber ich habe ein anderes Problem **. In dieser Tabelle habe ich 50 verschiedene Symbole, damit ich mit dem ersten Symbol arbeiten kann. Wie kann ich über alle 50 Symbole hinweglaufen (jedes Symbol muss von der ersten Eingabezeit neu beginnen) – TVC

1

können Sie diese Abfrage verwenden:

select * 
from @t t1 
where not exists (
    select 1 
    from @t t2 
    where t2.id < t1.id and t2.resultDate > t1.entryDate 
) 
+0

Danke für die Antwort, aber es ist nicht ganz gut. Es berücksichtigt die letzte Ergebniszeit in der Tabelle, auch wenn sie nicht ausgewählt ist. – TVC

+0

Zum Beispiel: Wenn die Ergebniszeit in einer Zeile 10:00:00 ist und die nächste Zeile die Eingabezeit 9:00:00 ist und die Ergebniszeit 11:00 ist, wird angenommen, dass diese Zeile übersprungen wird und ihre Ergebniszeit nicht verwendet wird weil die Eintrittszeit vor der letzten Ergebniszeit liegt. Ihre Antwort wird nun nach 11:00:00 Uhr und nicht nach 10:00:00 Uhr nach der nächsten Eingabezeit suchen. – TVC

1

Ich denke manchmal Cursor die Antwort

CREATE FUNCTION getSelected 
( 
) 
RETURNS @res TABLE 
(
    id int, EntryTime DATETIME, ResultTime DATETIME 
) 
AS 
BEGIN 
    declare @idC int; 
    declare @ResultTimeC DATETIME; 
    declare @EntryTimeC DATETIME; 
    declare @lastNextDate DATETIME; 

    DECLARE Iterator CURSOR LOCAL FAST_FORWARD 
    FOR SELECT id, EntryTime, ResultTime FROM dbo.tt1 order by EntryTime, id 
    OPEN Iterator 
    WHILE 1=1 BEGIN 
     FETCH NEXT FROM Iterator INTO @idC, @EntryTimeC, @ResultTimeC 
     IF @@FETCH_STATUS < 0 BREAK 

     if(@lastNextDate is null or @lastNextDate < @EntryTimeC) begin 
      set @lastNextDate = @ResultTimeC; 
      insert into @res (id, EntryTime, ResultTime) values (@idC, @EntryTimeC, @ResultTimeC); 
     end;    
    END 
    CLOSE Iterator 
    DEALLOCATE Iterator; 

    RETURN 
END 

EDIT

Und die mehrere Symbol Version

CREATE FUNCTION getSelected2 
( 
) 
RETURNS @res TABLE 
(
    id int, EntryTime DATETIME, ResultTime DATETIME, Symbol char(3) 
) 
AS 
BEGIN 
    declare @idC int; 
    declare @ResultTimeC DATETIME; 
    declare @EntryTimeC DATETIME; 
    declare @SymbolC char(3); 
    declare @lastNextDate DATETIME; 
    declare @lastSymbol char(3); 

    DECLARE Iterator CURSOR FAST_FORWARD 
    FOR SELECT id, EntryTime, ResultTime, Symbol FROM dbo.tt2 order by Symbol, EntryTime, id 
    OPEN Iterator 
    WHILE 1=1 BEGIN 
     FETCH NEXT FROM Iterator INTO @idC, @EntryTimeC, @ResultTimeC, @SymbolC 
     IF @@FETCH_STATUS < 0 BREAK 

     if(@lastSymbol is null or @lastSymbol <> @SymbolC) begin 
      set @lastSymbol = @SymbolC; 
      set @lastNextDate = null; 
     end; 
     if(@lastNextDate is null or @lastNextDate < @EntryTimeC) begin 
      set @lastNextDate = @ResultTimeC; 
      insert into @res (id, EntryTime, ResultTime, Symbol) values (@idC, @EntryTimeC, @ResultTimeC, @SymbolC); 
     end;    
    END 
    CLOSE Iterator 
    DEALLOCATE Iterator; 

    RETURN 
END 
+0

Wie kann ich diese Funktion ausführen? – TVC

+0

SELECT * FROM getSelected() –

+0

Sehr schön, funktioniert perfekt für einzelne Symbol, aber ich füge ein weiteres Problem, das ich für mehrere Symbole habe, Blick auf den Kommentar, wo ZLK antwortete. Wie kann ich das für mehrere Symbole machen, die jeweils neu beginnen? – TVC

Verwandte Themen