如何从签入和签出列表中计算时间跨度?

Posted

技术标签:

【中文标题】如何从签入和签出列表中计算时间跨度?【英文标题】:How would I calculate timespans from a list of check in and check outs? 【发布时间】:2010-09-21 11:49:34 【问题描述】:

我正在编写一个简单的时间跟踪程序来管理我自己的项目。我非常喜欢将报告代码保存在数据库中,因此我一直在尝试创建一些生成发票和时间表等的存储过程。

我有一个表,其中包含时钟操作、IE“Punch In”和“Punch Out”。它还包含执行此操作的用户、与此操作关联的项目以及当前日期/时间。

我可以从此表中选择以获取特定时间/项目/和用户的上班时间,但我想将其汇总,以便每个上班时间和下班时间都从 2 行转换为包含总时间的单行。

例如,这是一个示例输出:

ClockActionID        ActionType DateTime
-------------------- ---------- -----------------------
17                   1          2008-11-08 18:33:56.000
18                   2          2008-11-08 18:33:59.587
19                   1          2008-11-08 18:34:01.023
20                   2          2008-11-08 18:34:02.037
21                   1          2008-11-08 18:45:06.317
22                   2          2008-11-08 18:46:14.597
23                   1          2008-11-08 18:46:16.283
24                   2          2008-11-08 18:46:17.173
25                   1          2008-11-08 18:50:37.830
26                   2          2008-11-08 18:50:39.737
27                   1          2008-11-08 18:50:40.547

(11 row(s) affected)

其中 ActionType 1 是“ClockIn”,ActionType 2 是“ClockOut”。为简洁起见,我还删除了 User、Project 和 Description 列。

我需要在纯 SQL 中生成如下结果集:

Description   |    Total Time

对于每个 ClockIn / ClockOut 对。

我认为这实际上是相当简单的,我只是不太确定采用哪种方法。

编辑:用户将能够同时进入多个项目,但首先将结果集缩小到单个项目,这对这里的逻辑没有任何影响。

【问题讨论】:

你想要的叫做时间连接操作。 您能否详细说明,或链接到一些信息? 【参考方案1】:

我同意这个设计并不是最棒的——一个基于事件的结构,单行开始-结束可能会为您节省大量时间。在这种情况下,您可以在某人打卡时创建一条结束日期为空的记录。然后,填写他们打卡时的结束日期。

但是,这不是你问的。这是您问题的解决方案:

DECLARE @clock TABLE (ClockActionID INT PRIMARY KEY IDENTITY, ActionType INT, ActionDateTime DATETIME)

INSERT INTO @clock (ActionType, ActionDateTime) VALUES (1,'20080101 00:00:00')
INSERT INTO @clock (ActionType, ActionDateTime) VALUES (2,'20080101 00:01:00')
INSERT INTO @clock (ActionType, ActionDateTime) VALUES (1,'20080101 00:02:00')
INSERT INTO @clock (ActionType, ActionDateTime) VALUES (2,'20080101 00:03:00')
INSERT INTO @clock (ActionType, ActionDateTime) VALUES (1,'20080101 00:04:00')
INSERT INTO @clock (ActionType, ActionDateTime) VALUES (2,'20080101 00:05:00')
INSERT INTO @clock (ActionType, ActionDateTime) VALUES (1,'20080101 00:06:00')
INSERT INTO @clock (ActionType, ActionDateTime) VALUES (2,'20080101 00:07:00')
INSERT INTO @clock (ActionType, ActionDateTime) VALUES (1,'20080101 00:08:12')
INSERT INTO @clock (ActionType, ActionDateTime) VALUES (2,'20080101 00:09:00')

-- Get the range
SELECT ActionDateTime CheckIn, 
  (SELECT TOP 1 ActionDateTime 
   FROM @clock C2 
   WHERE C2.ActionDateTime > C.ActionDateTime) CheckOut   
FROM @clock C
WHERE ActionType = 1

-- Get the duration
SELECT DATEDIFF(second, ActionDateTime, 
  (SELECT TOP 1 ActionDateTime 
   FROM @clock C2 
   WHERE C2.ActionDateTime > C.ActionDateTime)
  ) / 60.0 Duration_Minutes
FROM @clock C
WHERE ActionType = 1

请注意,我正在使用与 MS SQL Server 一起工作的表变量,仅用于测试。根据需要进行更改。另请注意,SQL Server 2000 在处理此类查询时表现不佳。以下是测试结果:

CheckIn                 CheckOut
2008-01-01 00:00:00.000 2008-01-01 00:01:00.000
2008-01-01 00:02:00.000 2008-01-01 00:03:00.000
2008-01-01 00:04:00.000 2008-01-01 00:05:00.000
2008-01-01 00:06:00.000 2008-01-01 00:07:00.000
2008-01-01 00:08:12.000 2008-01-01 00:09:00.000

Duration_Minutes
1.000000
1.000000
1.000000
1.000000
0.800000

【讨论】:

【参考方案2】:

我认为您的原始存储架构存在缺陷。你从时钟的角度来看它,因此是 ClockAction。为什么不从项目的角度来看?

TABLE ProjectAction(Projectid、Userid、类型、开始、结束)

那么一个简单的 GROUP BY 应该可以解决问题。

【讨论】:

【参考方案3】:

你有没有想过这样的事情:

有人忘记打卡,因此他们似乎打卡了两次? 有人忘记打卡,因此他们似乎打卡了两次?

在第一种情况下,简单地忽略第二次打卡是否正确?接受的答案会将两个时钟输入绑定到相同的时钟输出。对吗?

在第二种情况下,第二个时钟输出将被忽略。对吗?

【讨论】:

其实没有Clock Out/Clock In Sproc,只是一个ClockAction sproc。该存储程序会快速查询您的最后一个操作,以确定您是打卡还是打卡,并自动执行所有操作。前端程序要做的就是调用它。

以上是关于如何从签入和签出列表中计算时间跨度?的主要内容,如果未能解决你的问题,请参考以下文章

尝试使用 React 计算带有价格的日期

sql求时间差,精确到秒分时

在没有 URL/Subversion 后端的情况下将 Fogbugz 与 TortoiseSVN 集成

如何使用 curl 自动上传和签入文件到共享点?

如何使用 Visual Studio 2003 和 TFS?

用于更新文件和签入 TFS 的 Azure DevOps 管道任务