我在下面的結果中包含了所有中介計算來說明它是如何工作的。
這個想法是最初將原始時間戳移位-8小時(ShiftedStartDT
,ShiftedEndDT
)。
然後,您可以使用簡單的DATEDIFF
(DiffDays
)計算它們之間的天數。
您需要檢查開始時間戳是否恰好在08:00,並將結果調整爲+ - 1(DiffAdjustment
)。
那些從未交叉的行08:00
邊界有0 DiffDays
,所以它們可以在WHERE
子句中被過濾掉。
樣本數據
DECLARE @T TABLE(Ref int, StartDT datetime2(0), EndDT datetime2(0));
INSERT INTO @T(Ref, StartDT, EndDT) VALUES
(1, '2016-11-26 08:02:00', '2016-11-26 09:00:00'),
(2, '2016-11-27 08:00:00', '2016-11-28 07:00:00'),
(3, '2016-11-27 08:05:00', '2016-11-28 11:00:00'),
(4, '2016-11-28 07:00:00', '2016-11-29 11:00:00'),
(5, '2016-11-28 08:45:00', '2016-11-29 06:30:00'),
(6, '2016-11-25 09:00:00', NULL);
查詢
DECLARE @CurrentDT datetime2(0) = '2016-11-30 11:00:00';
SELECT
Ref
,NewStartDT
,DiffDays
,StartDT
,EndDT
,ShiftedStartDT
,ShiftedEndDT
,DiffAdjustment
FROM
@T
CROSS APPLY
(
SELECT
DATEADD(hour, -8, StartDT) AS ShiftedStartDT
,DATEADD(hour, -8, ISNULL(EndDT, @CurrentDT)) AS ShiftedEndDT
) AS Shifted
CROSS APPLY
(
SELECT
CASE WHEN ShiftedStartDT = CAST(ShiftedStartDT as date)
THEN 1 ELSE 0 END AS DiffAdjustment
) AS Adj
CROSS APPLY
(
SELECT
DATEDIFF(day, ShiftedStartDT, ShiftedEndDT)
+ DiffAdjustment AS DiffDays
) AS Diff
CROSS APPLY
(
SELECT
DATEADD(day, 1-DiffAdjustment, CAST(ShiftedStartDT as date)) AS NewStartDT
) AS NewStart
WHERE
DiffDays > 0
;
結果
+-----+------------+----------+---------------------+---------------------+---------------------+---------------------+----------------+
| Ref | NewStartDT | DiffDays | StartDT | EndDT | ShiftedStartDT | ShiftedEndDT | DiffAdjustment |
+-----+------------+----------+---------------------+---------------------+---------------------+---------------------+----------------+
| 2 | 2016-11-27 | 1 | 2016-11-27 08:00:00 | 2016-11-28 07:00:00 | 2016-11-27 00:00:00 | 2016-11-27 23:00:00 | 1 |
| 3 | 2016-11-28 | 1 | 2016-11-27 08:05:00 | 2016-11-28 11:00:00 | 2016-11-27 00:05:00 | 2016-11-28 03:00:00 | 0 |
| 4 | 2016-11-28 | 2 | 2016-11-28 07:00:00 | 2016-11-29 11:00:00 | 2016-11-27 23:00:00 | 2016-11-29 03:00:00 | 0 |
| 6 | 2016-11-26 | 5 | 2016-11-25 09:00:00 | NULL | 2016-11-25 01:00:00 | 2016-11-30 03:00:00 | 0 |
+-----+------------+----------+---------------------+---------------------+---------------------+---------------------+----------------+
如果您確實需要有Ref=4
的2行和Ref=6
的6行,您可以通過將此結果與一個數字表連接起來。
在我的數據庫中,我有一個名爲Numbers
的表,它有一個int
列,名爲Number
,值爲1到100,000。它在許多疑問是有用的,它可以在此查詢中使用這樣的:
SELECT
Ref
,NewStartDT
,Num
,DiffDays
,StartDT
,EndDT
,ShiftedStartDT
,ShiftedEndDT
,DiffAdjustment
FROM
@T
CROSS APPLY
(
SELECT
DATEADD(hour, -8, StartDT) AS ShiftedStartDT
,DATEADD(hour, -8, ISNULL(EndDT, @CurrentDT)) AS ShiftedEndDT
) AS Shifted
CROSS APPLY
(
SELECT
CASE WHEN ShiftedStartDT = CAST(ShiftedStartDT as date)
THEN 1 ELSE 0 END AS DiffAdjustment
) AS Adj
CROSS APPLY
(
SELECT
DATEDIFF(day, ShiftedStartDT, ShiftedEndDT)
+ DiffAdjustment AS DiffDays
) AS Diff
CROSS APPLY
(
SELECT
DATEADD(day, 1-DiffAdjustment, CAST(ShiftedStartDT as date)) AS BaseStartDT
) AS NewStart
CROSS APPLY
(
SELECT
1 AS Num
,DATEADD(day, dbo.Numbers.Number-1, BaseStartDT) AS NewStartDT
FROM dbo.Numbers
WHERE dbo.Numbers.Number <= DiffDays
) AS CA
ORDER BY Ref, NewStartDT;
結果
+-----+------------+-----+----------+---------------------+---------------------+---------------------+---------------------+----------------+
| Ref | NewStartDT | Num | DiffDays | StartDT | EndDT | ShiftedStartDT | ShiftedEndDT | DiffAdjustment |
+-----+------------+-----+----------+---------------------+---------------------+---------------------+---------------------+----------------+
| 2 | 2016-11-27 | 1 | 1 | 2016-11-27 08:00:00 | 2016-11-28 07:00:00 | 2016-11-27 00:00:00 | 2016-11-27 23:00:00 | 1 |
| 3 | 2016-11-28 | 1 | 1 | 2016-11-27 08:05:00 | 2016-11-28 11:00:00 | 2016-11-27 00:05:00 | 2016-11-28 03:00:00 | 0 |
| 4 | 2016-11-28 | 1 | 2 | 2016-11-28 07:00:00 | 2016-11-29 11:00:00 | 2016-11-27 23:00:00 | 2016-11-29 03:00:00 | 0 |
| 4 | 2016-11-29 | 1 | 2 | 2016-11-28 07:00:00 | 2016-11-29 11:00:00 | 2016-11-27 23:00:00 | 2016-11-29 03:00:00 | 0 |
| 6 | 2016-11-26 | 1 | 5 | 2016-11-25 09:00:00 | NULL | 2016-11-25 01:00:00 | 2016-11-30 03:00:00 | 0 |
| 6 | 2016-11-27 | 1 | 5 | 2016-11-25 09:00:00 | NULL | 2016-11-25 01:00:00 | 2016-11-30 03:00:00 | 0 |
| 6 | 2016-11-28 | 1 | 5 | 2016-11-25 09:00:00 | NULL | 2016-11-25 01:00:00 | 2016-11-30 03:00:00 | 0 |
| 6 | 2016-11-29 | 1 | 5 | 2016-11-25 09:00:00 | NULL | 2016-11-25 01:00:00 | 2016-11-30 03:00:00 | 0 |
| 6 | 2016-11-30 | 1 | 5 | 2016-11-25 09:00:00 | NULL | 2016-11-25 01:00:00 | 2016-11-30 03:00:00 | 0 |
+-----+------------+-----+----------+---------------------+---------------------+---------------------+---------------------+----------------+
謝謝您的回答。我會馬上看看。 – Mally
太棒了。謝謝你。但正如你所說,我確實需要在每天08:00穿越一天。我已經從數據中排除了Ref,因爲我剛剛包含了這個數據以匹配輸出表 – Mally
@Mally,我添加了第二個變體,它根據需要使用數字表根據「Ref」生成多行。 –