我正在尝试从时钟数据库计算工时。我提出的查询存在一些问题,我无法弄清楚。
1)如果用户当天没有时钟,那么它认为用户工作直到时钟进入。如果用户忘记输入时钟,则应该抛弃查询
2)查询非常慢。有没有更好的方法可以用来加速它?
WITH AUXILIERY_TBL AS (
SELECT [First Name],Checktime,ROW_NUMBER() OVER (ORDER BY CheckTime ASC) AS Ordr
From Clock_Data
LEFT JOIN Employees ON Employees.[ID Number] = Clock_Data.UserId
WHERE Employees.[First Name]='Hogen' AND Year(CheckTime) > YEAR(GetDate()) - 6
)
SELECT * FROM(
SELECT
A.Ordr Number,a.[First Name],A.Checktime ct ,B.Checktime ct2,(DATEDIFF(MINUTE ,A.Checktime ,B.Checktime)/60) AS Hours
FROM AUXILIERY_TBL AS A
LEFT JOIN AUXILIERY_TBL AS B
ON (A.Ordr=(B.Ordr-1))
)c
WHERE c.Number % 2 <> 0
原始数据看起来像这样:
HOGEN 2013-10-28 09:30:00
HOGEN 2013-10-28 13:30:00
HOGEN 2013-10-28 14:00:00
HOGEN 2013-10-28 18:00:00
HOGEN 2013-10-29 09:31:00
HOGEN 2013-10-29 14:17:00
HOGEN 2013-10-29 18:00:00
HOGEN 2013-10-30 09:59:00
HOGEN 2013-10-30 14:06:00
HOGEN 2013-10-30 14:37:00
HOGEN 2013-10-30 18:10:00
c.f。 SqlFiddle
答案 0 :(得分:1)
您实际需要的是类似于SQLServer 2012+中提供的LAG
或LEAD
分析函数,它根据指定的分区和相同的选择结果N行向上或向下获取一列。排序
在我的解决方案中,我循环遍历Clock_Data表,假设时间是检出时间,然后我模拟带有相关子查询的LAG
函数,以根据每个签出时间让员工检查时间。肯定不是所有的时间都签出,所以我在子查询中添加了一个HAVING
条件,以确定在同一天退房之前选择的入住时间是否是可用时间的奇数行。如果是,则返回时间,如果不返回null
,那么我们可以跳过这些行。
请参阅SQL,请尽量不要使用带空格字符的列名...至少使用下划线字符:
select
ep.[First Name],
z.CheckIn,
z.CheckTime as CheckOut,
DATEDIFF(MINUTE, z.CheckIn, z.CheckTime)/60 AS Hours
from
(
select
cd.*,
(
-- simulating a LAG(CheckTime, 1, null) with this subquery
select max(CheckTime)
from Clock_Data
where 1=1
-- select only times from the same employee
and UserID = cd.UserID
-- select only times before the checkout time (cd.CheckTime)
and CheckTime < cd.CheckTime
-- select only times from the same year/month/day
and CheckTime >= convert(date, cd.CheckTime)
group by UserID
-- as we're selecting the max(CheckTime) before a check out time
-- in the same day, we're selecting the immediatelly previous row/time
-- but this subquery must select an odd number of rows
-- to ensure the max(CheckTime) is a check in time
-- since the check in always occurs first, before a check out
-- if it's an even number of rows, null is returned
having count(*) % 2 = 1
) as checkIn
from Clock_Data cd
) z
inner join Employees ep on 1=1
and ep.[ID Number] = z.UserID
-- and ep.[First Name] = 'Hogen'
where 1=1
and z.checkIn is not null