如何从签入和签出列表中计算时间跨度?
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。该存储程序会快速查询您的最后一个操作,以确定您是打卡还是打卡,并自动执行所有操作。前端程序要做的就是调用它。以上是关于如何从签入和签出列表中计算时间跨度?的主要内容,如果未能解决你的问题,请参考以下文章
在没有 URL/Subversion 后端的情况下将 Fogbugz 与 TortoiseSVN 集成