2017-04-02 5 views
5

ich eine Eingabe in folgendes Format haben: Input ImageZeilensummierung auf Basis der aktuellen und der nächsten Zeile

Ich habe den Unterschied der Stopp der aktuellen Zeile und dem Beginn der nächsten Zeile zu finden, und wenn die Differenz weniger als 25, muss ich die Werte in [TimeDiff_Start_Stop] summieren. Wenn der Unterschied mehr als 25 ist, muss ich die Summe nicht machen.

Wie in der obigen Bild, Differenz

zwischen Stopp der Zeile 1 und dem Beginn der Zeile 2 13 ist, zwischen Stopp der Reihe 2 und dem Beginn der Zeile 3 gleich 2 ist, zwischen Stopp der Reihe 3 und Start von Zeile 4 ist 1, zwischen Stop von Zeile 4 und Start von Zeile 5 ist 3, zwischen Stop von Zeile 5 und Start von Zeile 6 ist 8,
aber der Unterschied zwischen Stop von Zeile 6 und Start von Zeile 7 ist 37, daher wird nur [TimeDiff_Start_Stop] der ersten 6 Zeilen summiert, wodurch die Zeile 1 in der Ausgabe erzeugt wird.

Der weitere Unterschied zwischen Stopp von Zeile 7 und Start von Zeile 8 ist 20, daher [TimeDiff_Start_Stop] von Zeile 7 und Zeile 8 wird summiert, wodurch die Zeile 2 in Ausgabe erzeugt wird.

Erforderliche Ausgabe

Output Image

Wie soll ich das erreichen?

Hier finden Sie Skripte für die Ein- und Ausgabe:

Eingang:

select 'Sample' as COL1,'1' AS COL2,1 as 'RN','2016-05-09 02:45:18.239669' AS Start,'2016-05-09 02:45:25.837316' as Stop,7 as TimeDiff_Start_Stop 
union 
select 'Sample' as COL1,'1' AS COL2,2 as 'RN','2016-05-09 02:45:38.809919' AS Start,'2016-05-09 02:46:59.856081' as Stop,81 as TimeDiff_Start_Stop 
union 
select 'Sample' as COL1,'1' AS COL2,3 as 'RN','2016-05-09 02:47:01.831128' AS Start,'2016-05-09 02:48:55.211807' as Stop,114 as TimeDiff_Start_Stop 
union 
select 'Sample' as COL1,'1' AS COL2,4 as 'RN','2016-05-09 02:48:56.305736' AS Start,'2016-05-09 02:50:06.107262' as Stop,70 as TimeDiff_Start_Stop 
union 
select 'Sample' as COL1,'1' AS COL2,5 as 'RN','2016-05-09 02:50:09.269354' AS Start,'2016-05-09 02:50:16.081159' as Stop,7 as TimeDiff_Start_Stop 
union 
select 'Sample' as COL1,'1' AS COL2,6 as 'RN','2016-05-09 02:50:24.819440' AS Start,'2016-05-09 02:51:04.736300' as Stop,40 as TimeDiff_Start_Stop 
union 
select 'Sample' as COL1,'1' AS COL2,7 as 'RN','2016-05-09 02:51:41.029165' AS Start,'2016-05-09 02:54:04.186215' as Stop,143 as TimeDiff_Start_Stop 
union 
select 'Sample' as COL1,'1' AS COL2,8 as 'RN','2016-05-09 02:54:24.537167' AS Start,'2016-05-09 02:55:26.926029' as Stop,62 as TimeDiff_Start_Stop 

Ausgang:

select 'Sample' as COL1,'1' AS COL2,'2016-05-09 02:45:18.239669' AS Start,'2016-05-09 02:51:04.736300' as Stop,319 as Time 
union 
select 'Sample' as COL1,'1' AS COL2,'2016-05-09 02:51:41.029165' AS Start,'2016-05-09 02:55:26.926029' as Stop,205 as Time 
+0

Immer hilft, DDL und Inserts für Beispieldaten anstelle von Screenshots hinzuzufügen. –

+0

Danke @MaxSzczurek. Die Skripte wurden aktualisiert. – Logical

+0

LAG und LEAD sind hier nützlich – Mihai

Antwort

3

Hier sind zwei verschiedene Ansätze - dafür habe ich eine Tabelle erstellt @t und nutzte Ihre Beispieldaten, um sie zu bevölkern - vielen Dank, dass Sie diese bewiesen haben. Hier ist die Tabelle Definition:

declare @t table (col1 varchar(10), col2 int, rn int, start datetime2, stop datetime2, timediff_start_stop int) 
insert into @t ... (from the OP) 

Hier ist ein Ansatz mit einem CTE. Zuerst wird ein CTE erstellt, der nur das Diff hinzufügt (indem LEAD verwendet wird, um den Unterschied zwischen dem aktuellen Zeilenstopp/dem nächsten Zeilenstart zu erhalten) als Spalte.

Beachten Sie, dass die isnull-Anweisung in der CTE-Abfrage einen Wert von 26 an Null gibt, wenn keine folgende Zeile vorhanden ist. Dies bedeutet, dass die letzte Zeile im Ergebnissatz den Wert 26 (> 25) erhält einer Zeile, die eine Endzeit in der Ergebnismenge sein sollte).

;with tdiff (col1, col2, rn, start, stop, timediff_start_stop, diff, timediff) 
as 
(
select col1, col2, rn, start, stop, timediff_start_stop, isnull(datediff(ss, stop, lead(start) over (order by rn)), 26) as diff, datediff(ss, start, stop) 
from @t 
) 
select t1.col1, t1.col2, t1.start, (select min(stop) from tdiff where stop > t1.start and diff > 25) as stop, 
    (select sum(timediff_start_stop) from tdiff where start >= t1.start and stop <= (select min(stop) from tdiff where stop > t1.start and diff > 25)) AS TIME 
from tdiff t1 
left join tdiff t2 on (t1.rn - 1) = t2.rn 
where t1.rn = 1 or t2.diff > 25 

Als nächstes ist hier eine völlig andere Lösung mit Cursors. Cursor sind ineffizient und nicht gut für häufig ausgeführte Aufgaben geeignet, aber ich finde sie als Entwickler leicht zu pflegen und zu befolgen und halte sie für nützlich, wenn sie seltene oder einmalige Aufgaben ausführen müssen, die für Cursor geeignet sind:

declare @outputtable table (start datetime, stop datetime) 
declare @curstart datetime, @curstop datetime, @curdiff int 
declare @outputstart datetime 

DECLARE cur CURSOR FOR 
select start, stop, datediff(ss, stop, LEAD(start) over (order by rn)) 
from @t 
OPEN cur 

FETCH NEXT FROM cur 
INTO @curstart, @curstop, @curdiff 

WHILE @@FETCH_STATUS = 0 
BEGIN  
    if (@outputstart is null) 
     set @outputstart = @curstart 

    if (@curdiff > 25) 
    begin 
     insert into @outputtable values (@outputstart, @curstop) 
     set @outputstart = null 
    end 

    FETCH NEXT FROM cur 
    INTO @curstart, @curstop, @curdiff 
END 
CLOSE cur; 
DEALLOCATE cur; 

insert into @outputtable values (@outputstart, @curstop) 

select * from @outputtable 
+0

Vielen Dank @MaxSzczurek. Es funktionierte. Aber ich möchte wirklich auf Cursor verzichten. Die tatsächlichen Daten, die ich habe, sind in Millionen. Können wir das anders machen? CTE oder etwas anderes verwenden. – Logical

+0

Ja, arbeite jetzt an einer Lösung ohne einen Cursor! Cursor sind der letzte Ausweg, aber manchmal nützlich in einmaligen/seltenen/seltenen Prozessen, weil die Code-Logik einfach zu folgen ist, IMO. –

+0

Ja. Ich stimme zu. In der Zwischenzeit versuche ich datediff (ss, stop, LEAD (start) über (order by rn)) Teil in meinen Code zu integrieren. Dies wird wahrscheinlich die Verwendung von Self-Join entfernen. Vielen Dank. – Logical

Verwandte Themen