Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/26.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql server 如何选择2个日期时间,并在两个日期时间内获得每个日期的小时数?_Sql Server_Sql Server 2008 R2 - Fatal编程技术网

Sql server 如何选择2个日期时间,并在两个日期时间内获得每个日期的小时数?

Sql server 如何选择2个日期时间,并在两个日期时间内获得每个日期的小时数?,sql-server,sql-server-2008-r2,Sql Server,Sql Server 2008 R2,我在数据库中有以下数据: Job ClockInDateTime ClockOutDateTime MM00151509 2013-11-19 07:01 2013-11-19 09:20 MM00151800 2013-11-09 09:08 2013-11-20 11:36 MM00153591 2013-12-01 08:20 2013-12-03 08:15 MM00154121 2013-12-05 08:19 2013-12-0

我在数据库中有以下数据:

Job         ClockInDateTime     ClockOutDateTime
MM00151509  2013-11-19 07:01    2013-11-19 09:20
MM00151800  2013-11-09 09:08    2013-11-20 11:36
MM00153591  2013-12-01 08:20    2013-12-03 08:15
MM00154121  2013-12-05 08:19    2013-12-05 10:32
我想采取每一行,并显示该日期以及相关的时间为该日期。正如您在上面的结果中所看到的,许多记录跨越ClockInDateTime和ClockOutDateTime之间的天数。这是数千个作业(行)

sql查询将如何执行此操作

上述一个作业的输出示例-MM00153591:

Job         ClockInDateTime     ClockOutDateTime    Date        Hours
MM00153591  2013-12-01 08:20    2013-12-03 08:26    12/1/2013   15.3333
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

这里的诀窍是,您希望得到一个行爆炸,在指定日期之间的每一天产生一行

这可以通过几种方法实现,但一种方法是在一个简单的日期表上进行联接,该表中包含所有可能的日期(在合理的范围内),其中联接条件在一个范围内。根据您的性能需求,可以动态构建,也可以提前构建,然后存储以备将来使用

下面是一个示例,假设源3列位于名为Job的表中:

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]
注意:我在上面使用的构建日期表的方法是生成“数字表”的简单方法,但也有其他可能更可靠的方法:

编辑:下面是针对提供的示例数据的完整脚本,以及一个替代方法,该方法不使用日期表,而是在集合中每天循环。每种方法的完整结果也不变:

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]
请注意,在第二种方法中,我引入了一些UDF,只是为了使小时数计算看起来更清晰一些

还请注意,这两种方法产生相同的结果(这次我在SQLServer2012 express上运行了示例,但我没有使用任何2012特定的功能)


最后,关于您最初的预期结果和这些小时的结果之间的一个差异。我相信你预期的结果是错误的。08:20到午夜之间的时间是15小时40分钟,这是15.6667小时,而不是15.333小时。

半重复:这不是一个真正的重复,因为上面的一个没有显示如何获取时间和日期。有没有一种不使用日期表的方法?怎么做?我不相信这会奏效。为了让它工作,我已经累了好几次了,但是我没有得到正确的数据。你能描述一下你在查询中遇到的问题吗?在SQLServer2008R2上的一个小测试集上使用上面的示例数据,我看到了您所要求的内容。或者我在请求中遗漏了什么。出于好奇,您的sys.objects表中有多少对象?您是对的。。。那15.333是错的。只想说你很棒!谢谢
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