這裏的技巧是要想得到導致1行指定的日期之間每天連續爆炸。
這可以通過幾種方式來實現,但一種方法是加入一個簡單的日期表,其中包含所有可能的日期(在合理的範圍內),其中連接標準在範圍內。根據您的性能需求,可以實時構建或預先構建並存儲以備後用。
下面是一個例子,假設你的源3列是一個名爲作業表:
DECLARE @MinDate DATETIME
DECLARE @TotalDays INT
SELECT @MinDate = DATEADD(dd,-1, CONVERT(DATE,MIN(ClockInDateTime))),
@TotalDays = DATEDIFF(dd, CONVERT(DATE,MIN(ClockInDateTime)), CONVERT(DATE,MAX(ClockOutDateTime))) + 2
FROM Job
SELECT J.Job, J.ClockInDateTime, J.ClockOutDateTime,
CONVERT(DATE, Dt) as [Date],
CASE WHEN ClockInDateTime < Dt AND ClockOutDateTime >= DATEADD(dd, 1, Dt) THEN 24*60
WHEN ClockInDateTime >= Dt AND ClockOutDateTime >= DATEADD(dd, 1, Dt)
THEN DATEDIFF(mi, ClockInDateTime, DATEADD(dd, 1, Dt))
WHEN ClockInDateTime < Dt AND ClockOutDateTime < DATEADD(dd, 1, Dt)
THEN DATEDIFF(mi, Dt, ClockOutDateTime)
ELSE DATEDIFF(mi, ClockInDateTime, ClockOutDateTime)
END/60.0 as Hours
FROM Job J
INNER JOIN (SELECT TOP (@TotalDays) DATEADD(dd, ROW_NUMBER() OVER (ORDER BY s1.object_id), @MinDate) as Dt
FROM sys.objects s1
CROSS JOIN sys.objects s2) as DateTable
ON Dt BETWEEN CONVERT(DATE,J.ClockInDateTime) AND CONVERT(DATE,J.ClockOutDateTime)
ORDER BY Job, [Date]
與樣本數據的一些簡單的測試得到什麼似乎是正確的結果,但對於工作,你叫了我並得到略微不同的答案第一天的總時數:
Job ClockInDateTime ClockOutDateTime Date Hours
MM00153591 2013-12-01 08:20 2013-12-03 08:26 12/1/2013 15.6666
MM00153591 2013-12-01 08:20 2013-12-03 08:26 12/2/2013 24
MM00153591 2013-12-01 08:20 2013-12-03 08:15 12/3/2013 8.25
注:我使用上面建立的日期表的方法是產生一個「數字表」一個簡單的方法,但也有其他的,也許更可靠的方法:What is the best way to create and populate a numbers table?
編輯:這裏是對所提供的示例數據的完整腳本,以及不使用日期表的替代方法,而是在整個集合中的每一天循環。提供了每種方法的全部結果不變也:
SET NOCOUNT ON
IF OBJECT_ID('tempdb..#Table') IS NOT NULL DROP TABLE #Table
CREATE TABLE #Table (Job NVARCHAR(256), ClockInDateTime DATETIME, ClockOutDateTime DATETIME)
INSERT INTO #Table (Job, ClockInDateTime, ClockOutDateTime)
SELECT N'MM00151509', '2013-11-19 07:01', '2013-11-19 09:20'
UNION ALL SELECT N'MM00151800','2013-11-09 09:08','2013-11-20 11:36'
UNION ALL SELECT N'MM00153591','2013-12-01 08:20','2013-12-03 08:15'
UNION ALL SELECT N'MM00154121','2013-12-05 08:19','2013-12-05 10:32'
PRINT 'Method 1: Calculate as a subset of all possible days'
DECLARE @MinDate DATETIME
DECLARE @TotalDays INT
SELECT @MinDate = DATEADD(dd,-1, CONVERT(DATE,MIN(ClockInDateTime))),
@TotalDays = DATEDIFF(dd, CONVERT(DATE,MIN(ClockInDateTime)), CONVERT(DATE,MAX(ClockOutDateTime))) + 2
FROM #Table
SELECT J.Job, J.ClockInDateTime, J.ClockOutDateTime,
CONVERT(DATE, Dt) as [Date],
CASE WHEN ClockInDateTime < Dt AND ClockOutDateTime >= DATEADD(dd, 1, Dt) THEN 24*60
WHEN ClockInDateTime >= Dt AND ClockOutDateTime >= DATEADD(dd, 1, Dt)
THEN DATEDIFF(mi, ClockInDateTime, DATEADD(dd, 1, Dt))
WHEN ClockInDateTime < Dt AND ClockOutDateTime < DATEADD(dd, 1, Dt)
THEN DATEDIFF(mi, Dt, ClockOutDateTime)
ELSE DATEDIFF(mi, ClockInDateTime, ClockOutDateTime)
END/60.0 as Hours
FROM #Table J
INNER JOIN (SELECT TOP (@TotalDays) DATEADD(dd, ROW_NUMBER() OVER (ORDER BY s1.object_id), @MinDate) as Dt
FROM sys.objects s1
CROSS JOIN sys.objects s2) as DateTable
ON Dt BETWEEN CONVERT(DATE,J.ClockInDateTime) AND CONVERT(DATE,J.ClockOutDateTime)
ORDER BY Job, [Date]
PRINT 'Method 2: Loop 1 day at a time'
GO
IF OBJECT_ID('dbo.udf_MinDate') IS NOT NULL DROP FUNCTION dbo.udf_MinDate
GO
IF OBJECT_ID('dbo.udf_MaxDate') IS NOT NULL DROP FUNCTION dbo.udf_MaxDate
GO
CREATE FUNCTION dbo.udf_MinDate(@Date1 DATETIME, @Date2 DATETIME)
RETURNS DATETIME
AS
BEGIN
RETURN CASE WHEN @Date1 < @Date2 THEN @Date1 ELSE @Date2 END
END
GO
CREATE FUNCTION dbo.udf_MaxDate(@Date1 DATETIME, @Date2 DATETIME)
RETURNS DATETIME
AS
BEGIN
RETURN CASE WHEN @Date1 > @Date2 THEN @Date1 ELSE @Date2 END
END
GO
IF OBJECT_ID('tempdb..#TempResult') IS NOT NULL
DROP TABLE #TempResult
CREATE TABLE #TempResult (Job NVARCHAR(256), ClockInDateTime DATETIME, ClockOutDateTime DATETIME, [Date] DATE, [Hours] DECIMAL(18,6))
DECLARE @MaxDaysDifferent INT, @CurDayOffset INT
SELECT @MaxDaysDifferent = MAX(DATEDIFF(dd, ClockInDateTime, ClockOutDateTime))
FROM #Table
SET @CurDayoffset = 0
WHILE (@CurDayOffset <= @MaxDaysDifferent)
BEGIN
INSERT INTO #TempResult (Job, ClockInDateTime, ClockOutDateTime, [Date], Hours)
SELECT T.Job, T.ClockInDateTime, T.ClockOutDateTime,
DATEADD(dd, @CurDayOffset, CONVERT(DATE,T.ClockInDateTime)),
DATEDIFF(mi, dbo.udf_MaxDate(T.ClockInDateTime, DATEADD(dd, @CurDayOffset, CONVERT(DATE,T.ClockInDateTime))),
dbo.udf_MinDate(T.ClockOutDateTime, DATEADD(dd, @CurDayOffset + 1, CONVERT(DATE,T.ClockInDateTime))))/60.0 as [Hours]
FROM #Table T
WHERE DATEADD(dd, @CurDayOffset, CONVERT(DATE,T.ClockInDateTime)) <= T.ClockOutDateTime
SET @CurDayOffset = @CurDayOffset + 1
END
SELECT * FROM #TempResult
ORDER BY Job, [Date]
此查詢的全部結果是:
Method 1: Calculate as a subset of all possible days
Job ClockInDateTime ClockOutDateTime Date Hours
------------------------------ ----------------------- ----------------------- ---------- ------------------------------
MM00151509 2013-11-19 07:01:00.000 2013-11-19 09:20:00.000 2013-11-19 2.316666
MM00151800 2013-11-09 09:08:00.000 2013-11-20 11:36:00.000 2013-11-09 14.866666
MM00151800 2013-11-09 09:08:00.000 2013-11-20 11:36:00.000 2013-11-10 24.000000
MM00151800 2013-11-09 09:08:00.000 2013-11-20 11:36:00.000 2013-11-11 24.000000
MM00151800 2013-11-09 09:08:00.000 2013-11-20 11:36:00.000 2013-11-12 24.000000
MM00151800 2013-11-09 09:08:00.000 2013-11-20 11:36:00.000 2013-11-13 24.000000
MM00151800 2013-11-09 09:08:00.000 2013-11-20 11:36:00.000 2013-11-14 24.000000
MM00151800 2013-11-09 09:08:00.000 2013-11-20 11:36:00.000 2013-11-15 24.000000
MM00151800 2013-11-09 09:08:00.000 2013-11-20 11:36:00.000 2013-11-16 24.000000
MM00151800 2013-11-09 09:08:00.000 2013-11-20 11:36:00.000 2013-11-17 24.000000
MM00151800 2013-11-09 09:08:00.000 2013-11-20 11:36:00.000 2013-11-18 24.000000
MM00151800 2013-11-09 09:08:00.000 2013-11-20 11:36:00.000 2013-11-19 24.000000
MM00151800 2013-11-09 09:08:00.000 2013-11-20 11:36:00.000 2013-11-20 11.600000
MM00153591 2013-12-01 08:20:00.000 2013-12-03 08:15:00.000 2013-12-01 15.666666
MM00153591 2013-12-01 08:20:00.000 2013-12-03 08:15:00.000 2013-12-02 24.000000
MM00153591 2013-12-01 08:20:00.000 2013-12-03 08:15:00.000 2013-12-03 8.250000
MM00154121 2013-12-05 08:19:00.000 2013-12-05 10:32:00.000 2013-12-05 2.216666
Method 2: Loop 1 day at a time
Job ClockInDateTime ClockOutDateTime Date Hours
------------------------------ ----------------------- ----------------------- ---------- ------------------------------
MM00151509 2013-11-19 07:01:00.000 2013-11-19 09:20:00.000 2013-11-19 2.316666
MM00151800 2013-11-09 09:08:00.000 2013-11-20 11:36:00.000 2013-11-09 14.866666
MM00151800 2013-11-09 09:08:00.000 2013-11-20 11:36:00.000 2013-11-10 24.000000
MM00151800 2013-11-09 09:08:00.000 2013-11-20 11:36:00.000 2013-11-11 24.000000
MM00151800 2013-11-09 09:08:00.000 2013-11-20 11:36:00.000 2013-11-12 24.000000
MM00151800 2013-11-09 09:08:00.000 2013-11-20 11:36:00.000 2013-11-13 24.000000
MM00151800 2013-11-09 09:08:00.000 2013-11-20 11:36:00.000 2013-11-14 24.000000
MM00151800 2013-11-09 09:08:00.000 2013-11-20 11:36:00.000 2013-11-15 24.000000
MM00151800 2013-11-09 09:08:00.000 2013-11-20 11:36:00.000 2013-11-16 24.000000
MM00151800 2013-11-09 09:08:00.000 2013-11-20 11:36:00.000 2013-11-17 24.000000
MM00151800 2013-11-09 09:08:00.000 2013-11-20 11:36:00.000 2013-11-18 24.000000
MM00151800 2013-11-09 09:08:00.000 2013-11-20 11:36:00.000 2013-11-19 24.000000
MM00151800 2013-11-09 09:08:00.000 2013-11-20 11:36:00.000 2013-11-20 11.600000
MM00153591 2013-12-01 08:20:00.000 2013-12-03 08:15:00.000 2013-12-01 15.666666
MM00153591 2013-12-01 08:20:00.000 2013-12-03 08:15:00.000 2013-12-02 24.000000
MM00153591 2013-12-01 08:20:00.000 2013-12-03 08:15:00.000 2013-12-03 8.250000
MM00154121 2013-12-05 08:19:00.000 2013-12-05 10:32:00.000 2013-12-05 2.216666
注意的是,在第二個方法我介紹了一些UDF的只是爲了讓小時計算出現一點清潔劑。另外請注意,兩種方法產生相同的結果(這次我在Sql Server 2012 express上運行示例,但我沒有使用任何2012特定功能)。
最後,關於您最初的預期結果與這些小時結果之間的差異。我相信你的預期結果是不正確的。 08:20和午夜之間的時間爲15小時40分,即15.6667小時,而不是15.333小時。
semi-dupe:http://stackoverflow.com/questions/14119277/subtract-two-dates-in-sql-and-get-days-of-the-result – 2014-12-04 21:52:32
這不是真正的重複,因爲上面的一個不顯示如何獲得小時和日期。 – Kevin 2014-12-04 21:55:20