计算工作天数

时间:2017-10-19 19:00:05

标签: sql sql-server tsql count

你们在点击代码方面非常好。我可以使用更好的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

1 个答案:

答案 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的行数。