2016-04-07 5 views
1

Ich habe eine Abfrage, die mir eine allgemeinen Informationen über eingehende Arbeit gibt:Erstellen von Zeitplan basierend auf Start- und Endzeiten und Wert pro Stunde

Start    End ToPack 
2016-04-07 10:00  14:00 40 
2016-04-07 16:00  20:00 80 
    ... 

Es ist leicht zu zählen, dass ich 10 Einheiten packen pro Stunden zwischen 10 - 14 und 20 Einheiten pro Stunde zwischen 16-20. Ich möchte in der Lage sein, es so in einer Tabelle darzustellen:

TIME  ToPack 
10:00 10 
11:00 10 
12:00 10 
... 
16:00 20 
17:00 20 
... 
etc 

Ich habe versucht, es mit CTE zu tun, aber bisher habe ich nicht ...

Antwort

3

Ich würde Verwenden Sie eine table of numbers und CROSS APPLY.

Die Tabelle der Zahlen ist einfach eine Tabelle, die eine Spalte mit ganzen Zahlen von 1 bis einige ausreichend große Zahl hat, sagen wir 100.000. Ich persönlich benutze Tabelle mit 100K-Nummern. Aaron Bertrand schrieb einen good article, der erklärt, wie man solche Tabelle erzeugt.

Beispieldaten

DECLARE @T TABLE (StartDT datetime2(0), EndDT datetime2(0), ToPack float); 
INSERT INTO @T (StartDT, EndDT, ToPack) VALUES 
('2016-04-07 10:00:00', '2016-04-07 14:00:00', 40), 
('2016-04-07 16:00:00', '2016-04-07 20:00:00', 80); 

Abfrage

SELECT * 
FROM 
    @T AS T 
    CROSS APPLY 
    (
     SELECT 
      DATEADD(hour, dbo.Numbers.Number-1, T.StartDT) AS HourDT 
      , T.ToPack/DATEDIFF(hour, T.StartDT, T.EndDT) AS ToPackPerHour 
     FROM dbo.Numbers 
     WHERE dbo.Numbers.Number <= DATEDIFF(hour, T.StartDT, T.EndDT) 
    ) AS CA 
ORDER BY HourDT; 

Ergebnis

+---------------------+---------------------+--------+---------------------+---------------+ 
|  StartDT  |  EndDT  | ToPack |  HourDT  | ToPackPerHour | 
+---------------------+---------------------+--------+---------------------+---------------+ 
| 2016-04-07 10:00:00 | 2016-04-07 14:00:00 |  40 | 2016-04-07 10:00:00 |   10 | 
| 2016-04-07 10:00:00 | 2016-04-07 14:00:00 |  40 | 2016-04-07 11:00:00 |   10 | 
| 2016-04-07 10:00:00 | 2016-04-07 14:00:00 |  40 | 2016-04-07 12:00:00 |   10 | 
| 2016-04-07 10:00:00 | 2016-04-07 14:00:00 |  40 | 2016-04-07 13:00:00 |   10 | 
| 2016-04-07 16:00:00 | 2016-04-07 20:00:00 |  80 | 2016-04-07 16:00:00 |   20 | 
| 2016-04-07 16:00:00 | 2016-04-07 20:00:00 |  80 | 2016-04-07 17:00:00 |   20 | 
| 2016-04-07 16:00:00 | 2016-04-07 20:00:00 |  80 | 2016-04-07 18:00:00 |   20 | 
| 2016-04-07 16:00:00 | 2016-04-07 20:00:00 |  80 | 2016-04-07 19:00:00 |   20 | 
+---------------------+---------------------+--------+---------------------+---------------+ 
+0

Brilliant! Ich habe angefangen, mit dem Erstellen von Loops zu experimentieren, aber diese Lösung ist so viel einfacher und schneller! – Yasskier

0

Als Variante @ ausgezeichnete solut Vladimir Ich kann einen mit der sehr praktischen Funktion generate_series vorschlagen.

Beispieldaten(Ihre Daten genau mit, im Textformat):

CREATE TABLE #ToPack (StartDT char(16), EndT char(5), ToPack int); 
INSERT INTO #ToPack VALUES ('2016-04-07 10:00', '14:00', 40); 
INSERT INTO #ToPack VALUES ('2016-04-07 16:00', '20:00', 80); 

Abfrage(Ergebnis, wie Sie vorgeschlagen):

SELECT SUBSTRING(tp.StartDT, 1, 10) AS [Date], 
     SUBSTRING(CONVERT(varchar(20), s.date_hour, 120), 12, 5) AS TimeSlot, 
     s.ToPackSlot 
FROM (
    SELECT *, CONVERT(datetime, StartDT) AS date_start, 
     CONVERT(datetime, convert(char(11), StartDT)+EndT) AS date_end 
    FROM #ToPack 
) tp 
CROSS APPLY (
    SELECT DATEADD(hour, g.IntValue, tp.date_start) AS date_hour, 
     tp.ToPack/DATEDIFF(hour, tp.date_start, tp.date_end) AS ToPackSlot 
    FROM generate_series(1, DATEDIFF(hour, tp.date_start, tp.date_end), 1) g) s 
+0

Die 'generate_series'-Funktion mag zwar praktisch sein, aber sie kann und sollte viel effizienter implementiert werden, als Zeile für Zeile in eine temporäre Tabelle in einer WHILE-Schleife einzufügen. –

+0

@Vladimir, die Ergebnisse von 'generate_series' sollen dynamisch sein, so dass sie letztendlich immer in einer Art Schleife erzeugt werden. Es stimmt, dass TSQL für umfangreiche Schleifen nicht sehr effizient ist. Es dauerte 14 Sekunden, um 'count (*) von generate_series (1, 1000000, 1)' auf meinem Server auszuführen, während es in PostgreSQL 0,3 Sekunden dauerte, da es in C codiert ist, obwohl der Code ziemlich gleich ist . Ich denke, der Komfort dieser Funktion für kleine Sets wie diese ist großartig, obwohl ihre Leistung über 'Numbers'-Tabelle erhöht werden kann (was mit generate_series() erzeugt werden kann ;-)). –

+0

[Dieser Artikel] (http://sqlperformance.com/2013/01/t-sql-queries/generate-a-set-1) von Aaron Bertrand zeigt mehrere Methoden zum Generieren einer Reihe von Zeilen. Es gibt definitiv Möglichkeiten, 1M Zeilen in einem Bruchteil einer Sekunde in T-SQL zu generieren. Die Zahlentabelle ist nur eine davon. –

Verwandte Themen