【问题标题】:SQL getting datediff from same fieldSQL 从同一字段获取 datediff
【发布时间】:2014-10-17 15:05:22
【问题描述】:

我有问题。我需要在我的表中以小时为单位获取日期差异,但问题是它保存在同一个字段中。这是我的桌子的样子。

  RecNo.    Employeeno   recorddate   recordtime    recordval
   1           001        8/22/2014      8:15 AM         1
   2           001        8/22/2014      5:00 PM         2
   3           001        8/24/2014      8:01 AM         1
   4           001        8/24/2014      5:01 PM         2

1 表示进入,2 表示超时。现在,我将如何获得每天工作的小时数?我想得到的是这样的。

Date       hoursworked
8/22/2014       8
8/24/2014       8

我正在使用 VS 2010 和 SQL Server 2005

【问题讨论】:

  • 您的列数据类型是什么?您希望在 SQL 还是 VB 中执行此操作?
  • recno Empoloyeeno 都是 nvarchar,recorddate recordtime 都是日期时间字段,recordval 是整数。我真正想做的是底部示例,从上表中提取datehoursworked,将其保存到另一个表并从那里生成报告。
  • 到目前为止我所做的是设置一个范围startdate' and enddate`来循环遍历所有日期并调用2个SQL查询;查询 1 针对recordval=1 的条件,查询2 针对recordval = 2 的条件,从那里得到`recordtime',但是这种方法执行起来有点慢。在一周内计算 25 名员工的工作小时数大约需要 12 秒才能完成。

标签: sql vb.net visual-studio-2010 sql-server-2005


【解决方案1】:

您可以将每个“入”记录与其对应的“出”记录进行自我连接,并使用datediff 减去它们:

SELECT     time_in.employeeno AS "Employee No",
           time_in.recorddate AS "Date",
           DATEDIFF (hour, time_in.recordtime, time_out.recordtime) 
            AS "Hours Worked"
FROM       (SELECT *
            FROM   my_table
            WHERE  recordval = 1) time_in
INNER JOIN (SELECT *
            FROM   my_table
            WHERE  recordval = 2) time_out 
           ON time_in.employeeno = time_out.employeeno AND
              time_in.recorddate = time_out.recorddate

【讨论】:

  • 这假设午夜没有轮班,这是一个重大案例。
  • @PieterGeerkens 在我看来,OP 已经假设了这一点,因为班次没有唯一标识符。除非您假设每个“time_in”都必须跟随一个“time_out”并加入,否则请执行诸如加入 FLOOR(RecNo/2) 之类的操作
  • 如果这不是 OP 的要求,那么问题很简单,不是吗?您知道有多少组织支付小时工资而不是薪水并且绝对没有夜班?
  • 您好,很抱歉回复晚了。您的查询对我有用,因为我忘了提到还有另一种类型的 recordval=3 表示超时,4 表示超时。所以我只是修改你的查询并且对我很有用。关于午夜的轮班,我所做的是如果超时为负,我只需添加 24。感谢您帮助我。
【解决方案2】:

如果您总是记录每位员工的进出时间,并且每天只记录一个,那么使用自加入应该可行:

SELECT 
    t1.Employeeno, 
    t1.recorddate, 
    t1.recordtime AS [TimeIn], 
    t2.recordtime AS [TimeOut], 
    DATEDIFF(HOUR,t1.recordtime, t2.recordtime) AS [HoursWorked]
FROM Table1 t1
INNER JOIN Table1 t2 ON 
    t1.Employeeno = t2.Employeeno 
    AND t1.recorddate = t2.recorddate 
WHERE t1.recordval = 1 AND t2.recordval = 2

我将记录时间字段包括为时间,超时,如果您不希望它们删除它们。

请注意,这个 datediff 计算给出 9 小时,而不是您建议的 8 小时。

Sample SQL Fiddle

【讨论】:

    【解决方案3】:

    使用此示例数据:

    with table1 as (
        select * from ( values
             (1,'001', cast('20140822' as datetime),cast('08:15:00 am' as time),1)
            ,(2,'001', cast('20140822' as datetime),cast('05:00:00 pm' as time),2)
    
            ,(3,'001', cast('20140824' as datetime),cast('08:01:00 am' as time),1)
            ,(4,'001', cast('20140824' as datetime),cast('04:59:00 pm' as time),2)
    
            ,(5,'001', cast('20140825' as datetime),cast('10:01:00 pm' as time),1)
            ,(6,'001', cast('20140826' as datetime),cast('05:59:00 am' as time),2)
        )data(RecNo,EmployeeNo,recordDate,recordTime,recordVal)
    )
    

    这个查询

    SELECT
         Employeeno
        ,convert(char(10),recorddate,120) as DateStart
        ,convert(char(5),cast(TimeIn as time))  as TimeIn
        ,convert(char(5),cast(TimeOut as time)) as TimeOut
        ,DATEDIFF(minute,timeIn, timeOut) / 60 AS [HoursWorked]
        ,DATEDIFF(minute,timeIn, timeOut) % 60 AS [MinutesWorked]
    FROM (
        SELECT 
            tIn.Employeeno, 
            tIn.recorddate, 
            dateadd(minute, datediff(minute,0,tIn.recordTime), tIn.recordDate)
                 as TimeIn,             
            ( SELECT TOP 1 
                 dateadd(minute, datediff(minute,0,tOut.recordTime), tOut.recordDate)
                 as TimeOut
              FROM Table1 tOut
              WHERE tOut.RecordVal = 2
                AND tOut.EmployeeNo = tIn.EmployeeNo
                AND tOut.RecNo > tIn.RecNo
              ORDER BY tOut.EmployeeNo, tOut.RecNo
            ) as TimeOut
        FROM Table1 tIn
        WHERE tIn.recordval = 1
    ) T
    

    产量(根据需要)

    Employeeno DateStart  TimeIn TimeOut HoursWorked MinutesWorked
    ---------- ---------- ------ ------- ----------- -------------
    001        2014-08-22 08:15  17:00   8           45
    001        2014-08-24 08:01  16:59   8           58
    001        2014-08-25 22:01  05:59   7           58
    

    没有对不超过午夜的班次做出任何假设(参见案例 3)。

    这个特定的实现可能不是构造这个相关子查询的最高效的方式,所以如果有性能问题回来,我们可以再看一遍。然而,运行这些测试需要一个我现在不想构建的大型数据集。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-02-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-01-27
      相关资源
      最近更新 更多