你们在点击代码方面非常好。我可以使用更好的SQL来告诉我每个员工一个月工作的天数。每个员工每天可以多次打卡和打卡,加上他们可以在午夜工作。如果他们在午夜工作,则计为工作2天。如果他们在午夜工作并在同一天晚些时候来到下一个午夜之前离开,那么那个时间就已经计算好了,因为它是在同一天。
这有效,但有更简单的方法吗?
IF OBJECT_ID ('dbo.ZTable1', 'U') IS NOT NULL
DROP TABLE dbo.ZTable1;
GO
CREATE TABLE dbo.ZTable1 ( [EmployeeId] Numeric (5,0), [TimeIn] datetime,
[TimeOut] datetime )
INSERT INTO dbo.ZTable1 ([EmployeeId],[TimeIn],[TimeOut]) SELECT 1,'2017-09-
13 12:19','2017-09-14 00:01'
INSERT INTO dbo.ZTable1 ([EmployeeId],[TimeIn],[TimeOut]) SELECT 1,'2017-09-
14 12:15','2017-09-15 00:01'
INSERT INTO dbo.ZTable1 ([EmployeeId],[TimeIn],[TimeOut]) SELECT 1,'2017-09-
15 12:35','2017-09-16 00:01'
INSERT INTO dbo.ZTable1 ([EmployeeId],[TimeIn],[TimeOut]) SELECT 1,'2017-09-
16 07:56','2017-09-16 10:31'
INSERT INTO dbo.ZTable1 ([EmployeeId],[TimeIn],[TimeOut]) SELECT 1,'2017-09-
16 11:56','2017-09-16 16:31'
INSERT INTO dbo.ZTable1 ([EmployeeId],[TimeIn],[TimeOut]) SELECT 2,'2017-09-
13 15:26','2017-09-14 00:00'
INSERT INTO dbo.ZTable1 ([EmployeeId],[TimeIn],[TimeOut]) SELECT 2,'2017-09-
14 15:29','2017-09-15 00:00'
INSERT INTO dbo.ZTable1 ([EmployeeId],[TimeIn],[TimeOut]) SELECT 2,'2017-09-
15 15:27','2017-09-16 00:01'
INSERT INTO dbo.ZTable1 ([EmployeeId],[TimeIn],[TimeOut]) SELECT 3,'2017-09-
13 15:25','2017-09-14 00:01'
INSERT INTO dbo.ZTable1 ([EmployeeId],[TimeIn],[TimeOut]) SELECT 3,'2017-09-
14 15:25','2017-09-15 00:00'
INSERT INTO dbo.ZTable1 ([EmployeeId],[TimeIn],[TimeOut]) SELECT 3,'2017-09-
15 15:26','2017-09-16 00:00'
INSERT INTO dbo.ZTable1 ([EmployeeId],[TimeIn],[TimeOut]) SELECT 3,'2017-09-
16 06:55','2017-09-16 15:27'
GO;
With Step1 as ( --< Build temp table of in punch days
Select [EmployeeId], DATEPART ( DAY ,[TimeIn] ) as WorkDay
from dbo.ZTable1
),
Step2 as ( --< Build temp table of out punch days
Select [EmployeeId], DATEPART ( DAY ,[TimeOut] ) as WorkDay
from dbo.ZTable1
),
Step3 as ( --< merges both in and put punch tables
Select
Case when s1.[EmployeeId] is NULL then s2.[EmployeeId] else s1.[EmployeeId] end as Employee,
case when s1.WorkDay is NULL then s2.WorkDay else s1.WorkDay end as WorkDate
from Step1 s1
full outer join Step2 s2 on s1.[EmployeeId] = s2.[EmployeeId] and s1.WorkDay = s2.WorkDay
),
Step4 as ( --< Organizes temp table
Select Distinct Employee, WorkDate
from Step3
group by Employee, WorkDate
)
Select Employee, Count (Employee) as NumDays
from Step4
Where Employee > 0
Group by Employee
Order by Employee
DROP TABLE dbo.ZTable1
Output (Result)
Employee NumDays
1 4
2 4
3 4
答案 0 :(得分:1)
试试这个,不需要CTE:
SELECT EmployeeID, COUNT(1) as NumDays
FROM (
SELECT EmployeeID, CONVERT(DATE,TimeIn) DistinctDays
FROM ZTable1
UNION
SELECT EmployeeID, CONVERT(DATE,TimeOut)
FROM ZTable1
) A
GROUP BY EmployeeID
我将DATEPART(Day, TimeIn/Out)
更改为CONVERT(DATE, TimeIn/Out)
以处理不同的月份/年份。根据您所说的内容,可能没有必要,但无论如何,性能与DATEPART()
大致相同。
此处的方法基本上是获取每个employeeID的不同天数列表,无论该日期是来自TimeIn
还是TimeOut
列。
UNION
非常适用于此,因为它可以合并两列,并从结果集中删除重复的结果,这会为我们留下不同的days / employeeID列表。然后,只需计算每个employeeID的行数。