Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/78.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 午夜时分的分时记录_Sql_Sql Server 2008 - Fatal编程技术网

Sql 午夜时分的分时记录

Sql 午夜时分的分时记录,sql,sql-server-2008,Sql,Sql Server 2008,我正在试着做一些报告,并且不得不处理员工工作时间跨越午夜的整个问题。但我突然想到,我可以将跨越午夜的记录拆分为两个记录,就像员工在午夜打卡下班,同时在午夜打卡回来一样,从而完全避免了午夜问题 因此,如果我有: EmployeeId InTime OutTime --- ----------------------- ----------------------- 1 2012-01-18 19:50:04.

我正在试着做一些报告,并且不得不处理员工工作时间跨越午夜的整个问题。但我突然想到,我可以将跨越午夜的记录拆分为两个记录,就像员工在午夜打卡下班,同时在午夜打卡回来一样,从而完全避免了午夜问题

因此,如果我有:

EmployeeId   InTime                     OutTime
---          -----------------------    -----------------------
1            2012-01-18 19:50:04.437    2012-01-19 03:30:02.433
你认为这样分割这张唱片最优雅的方式是什么

EmployeeId   InTime                     OutTime
---          -----------------------    -----------------------
1            2012-01-18 19:50:04.437    2012-01-19 00:00:00.000
1            2012-01-19 00:00:00.000    2012-01-19 03:30:02.433

是的,我已经仔细考虑了这可能会对现有功能产生什么影响。。。这就是为什么我选择在不影响现有功能的临时表中执行此操作的原因。

尝试此操作,因为您可以在select中执行插入操作,并且在select中可以将要使用的值设置为不同的日期

要添加新行,请执行以下操作:

insert into table ("EMPLOYEE_ID","INTIME","OUTTIME") values
SELECT EMPLOYEE_ID,date(INTIME),OUTTIME
FROM table
where date(intime) < date(outtime)
这可能有助于:

DECLARE @tbl TABLE 
    (
        EmployeeId INT,
        InTime DATETIME,
        OutTime DATETIME
    )

INSERT INTO @tbl(EmployeeId,InTime,OutTime) VALUES (1,'2012-01-18 19:50:04.437','2012-01-19 03:30:02.433')
INSERT INTO @tbl(EmployeeId,InTime,OutTime) VALUES (2,'2012-01-18 19:50:04.437','2012-01-18 20:30:02.433')
INSERT INTO @tbl(EmployeeID,InTime,OutTime) VALUES (3,'2012-01-18 16:15:00.000','2012-01-19 00:00:00.000')
INSERT INTO @tbl(EmployeeID,InTime,OutTime) VALUES (4,'2012-01-18 00:00:00.000','2012-01-18 08:15:00.000')
SELECT
    tbl.EmployeeId,
    tbl.InTime,
    DATEADD(dd, DATEDIFF(dd, 0, tbl.OutTime), 0) AS OutTime
FROM
    @tbl AS tbl
WHERE
    DATEDIFF(dd,tbl.InTime,tbl.OutTime)=1
UNION ALL
SELECT
    tbl.EmployeeId,
    CASE WHEN DATEDIFF(dd,tbl.InTime,tbl.OutTime)=1
        THEN DATEADD(dd, DATEDIFF(dd, 0, tbl.OutTime), 0)
        ELSE tbl.InTime
    END AS InTime,
    tbl.OutTime
FROM @tbl AS tbl
ORDER BY EmployeeId

如果是报告,那么您应该能够执行查询/合并,从原始记录开始,在这些条件下提供两条记录。。。如果没有SQL Server 2008,我只能为您提供一个伪代码查询

的第一部分根据要显示的范围条件获取所有记录。OutTime的值是有条件的。。。如果是在同一天,那么没有交叉,只是利用休息时间。如果是在第二天,则使用casting动态构建“YYYY-MM-DD”日期,该日期将默认为00:00:00时间,如您所需

工会只会抓取那些在第一次会议上获得资格的记录,这些记录的输入/输出日期是不同的。因此,我们知道,我们希望任何超时时间都作为起始时间,但基于00:00:00时间,因此执行与日期/时间字段完全相同的强制转换,对于这些记录,只需按原样使用最终的超时值

TimeSplit“1”或“2”的额外列用于确保我们仍然可以按员工ID分组,但从这一点出发,确保开始轮班的“1”条目位于第一位,之后是同一个人的任何条目,在他们轮班的当天重叠处有一个“2”条目

select
      tc.EmployeeID,
      '1' as TimeSplit,
      tc.InTime,
      case when datepart( dd, tc.InTime ) = datepart( dd, tc.OutTime )
         then tc.OutTime 
         else CAST( CAST( datepart(yyyy, tc.OutTime ) AS varchar) 
              +'-'+ CAST( datepart( mm, tc.OutTime ) AS varchar) 
              +'-'+ CAST( datepart( dd, tc.OutTime ) AS varchar) AS DATETIME)
         end as OutTime
   from 
      TimeCard tc
   where
      YourDateRangeConditions...
   ORDER BY
      tc.EmployeeID, 
      TimeSplit
UNION ALL
select
      tc.EmployeeID,
      '2' as TimeSplit,
      CAST(    CAST( datepart(yyyy, tc.OutTime ) AS varchar) 
         +'-'+ CAST( datepart( mm, tc.OutTime ) AS varchar) 
         +'-'+ CAST( datepart( dd, tc.OutTime ) AS varchar) AS DATETIME)
         end as InTime
      tc.OutTime
   from 
      TimeCard tc
   where
      YourDateRangeConditions...
      AND NOT datepart( dd, tc.InTime ) = datepart( dd, tc.OutTime )

以下解决方案使用系统表子集形式的数字表来分割时间范围。它可以使用spt_值分割从2048年到2048年的任意天数范围,但使用您自己的数字表,您可以设置不同的最大值。这里不讨论1天和2天跨度范围的具体情况,但我相信该方法足够轻量级,您可以尝试:

;
WITH LaborHours (EmployeeId, InTime, OutTime) AS (
  SELECT
    1,
    CAST('2012-01-18 19:50:04.437' AS datetime),
    CAST('2012-01-18 03:30:02.433' AS datetime)
),
HoursSplit AS (
  SELECT
    h.*,
    SubInTime  = DATEADD(DAY, DATEDIFF(DAY, 0, h.InTime) + v.number + 0, 0),
    SubOutTime = DATEADD(DAY, DATEDIFF(DAY, 0, h.InTime) + v.number + 1, 0)
  FROM LaborHours h
    INNER JOIN master..spt_values v
      ON number BETWEEN 0 AND DATEDIFF(DAY, h.InTime, h.OutTime)
  WHERE v.type = 'P'
),
HoursSubstituted AS (
  SELECT
    EmployeeId,
    InTime  = CASE WHEN InTime  > SubInTime  THEN InTime  ELSE SubInTime  END,
    OutTime = CASE WHEN OutTime < SubOutTime THEN OutTime ELSE SubOutTime END
  FROM HoursSplit
)
SELECT *
FROM HoursSubstituted
基本上,这是一个两步的方法

首先,我们使用数字表复制每一行,复制次数取决于范围所跨越的天数,并准备从午夜开始到下一个午夜结束的“标准”子范围


接下来,我们比较子范围的开始和范围的开始,以查看它是否是第一个子范围,在这种情况下,我们使用InTime作为其开始。类似地,我们比较结尾,看看是应该使用OutTime还是仅使用午夜作为该子范围的结尾。

看看它是否完全相似。更多关于其基于SQL2K的解决方案。但我希望它能给你一些提示。所以现在是午夜时分。。。问题是什么。。。给定班次的总工作小时数?或者,如果它跨越了两个日期,那么在“本”报告中,它应该出现在?@DRapp中的哪个日期,尽管并非所有的劳动力都应该出现在它实际所属的日期上。。。不一定是员工开始轮班的日期。所以这就是为什么我认为这是以数据最有意义的方式实现这一目标的最佳解决方案。这里有什么舍入问题需要关注吗?例如,如果你把工作时间四舍五入到最接近的半小时,他们在23:40打卡,在00:20打卡,你将把两个工作时间四舍五入到零,而他们本应被记为半小时。@Damien_不信者不,它永远不会被四舍五入。
;
WITH LaborHours (EmployeeId, InTime, OutTime) AS (
  SELECT
    1,
    CAST('2012-01-18 19:50:04.437' AS datetime),
    CAST('2012-01-18 03:30:02.433' AS datetime)
),
HoursSplit AS (
  SELECT
    h.*,
    SubInTime  = DATEADD(DAY, DATEDIFF(DAY, 0, h.InTime) + v.number + 0, 0),
    SubOutTime = DATEADD(DAY, DATEDIFF(DAY, 0, h.InTime) + v.number + 1, 0)
  FROM LaborHours h
    INNER JOIN master..spt_values v
      ON number BETWEEN 0 AND DATEDIFF(DAY, h.InTime, h.OutTime)
  WHERE v.type = 'P'
),
HoursSubstituted AS (
  SELECT
    EmployeeId,
    InTime  = CASE WHEN InTime  > SubInTime  THEN InTime  ELSE SubInTime  END,
    OutTime = CASE WHEN OutTime < SubOutTime THEN OutTime ELSE SubOutTime END
  FROM HoursSplit
)
SELECT *
FROM HoursSubstituted