考勤总结报告
Attendance summarized report
由于公司政策,我无法给出我正在处理的实际查询,但这里是细分和总体思路。我们有一个考勤登记簿,记录员工每天是否上班以及员工在哪里工作。我正在尝试对此进行总结,以说明该员工在该日期和该日期之间工作了 5 个班次。我遇到的问题是,一名特定员工在工作场所 A 工作了 2 天,然后被调到工作场所 B。在工作场所 B 工作几天后,该员工又被调回工作场所 A。
我的尝试结果表明,该员工从 1 月 1 日开始在工作场所 A 工作,到 1 月 10 日结束,只有 2 个工作班次。我在工作地点有一个分组,开始和结束日期是最小和最大选择。
SELECT att.Employee, att.Workplace, dte.BeginDate, dte.EndDate, shf.WorkShift FROM
(SELECT * FROM Attendance WHERE WorkDate BETWEEN '1-Jan' AND '30-Jan') att
CROSS APPLY (SELECT COUNT(Shift) WorkShift FROM Attendance WHERE WorkDate BETWEEN '1-Jan' AND '30-Jan' AND Employee = att.Employee AND WorkPlace = att.WorkPlace AND Shift = 'Worked') shf
CROSS APPLY (SELECT MAX(WorkDate) BeginDate, MIN(WorkDate) EndDate FROM Attendance WHERE WorkDate BETWEEN '1-Jan' AND '30-Jan' AND Employee = att.Employee AND WorkPlace = att.WorkPlace) dte
所以这个员工记录应该是这样的(很抱歉网格非常糟糕,我不知道如何让它看起来漂亮,非常欢迎您对其进行编辑以使其看起来更好)
| Name | Workplace | beginDate | endDate | WorkShift |
| Jane | WorkPlaceA | 1-Jan | 2-Jan | 2 |
| Jane | WorkPlaceB | 3-Jan | 8-Jan | 5 |
| Jane | WorkPlaceA | 9-Jan | 10-Jan | 2 |
出席人数 table 看起来像这样
| Name | Workplace | Date | Shift |
| Jane | WorkplaceA | 1-Jan | Worked |
| Jane | WorkplaceA | 2-Jan | Worked |
| Jane | WorkplaceB | 3-Jan | Worked |
| Jane | WorkplaceB | 4-Jan | Worked |
| Jane | WorkplaceB | 5-Jan | Worked |
| Jane | WorkplaceA | 6-Jan | Absent |
| Jane | WorkplaceA | 7-Jan | Absent |
| Jane | WorkplaceA | 8-Jan | Worked |
| Jane | WorkplaceB | 9-Jan | Worked |
| Jane | WorkplaceB | 10-Jan | Worked |
我相信您可以使用 CTE 来完成此任务。这是显示您的预期值的示例工作代码。
;WITH CTE1 AS (
SELECT Employee, WorkPlace, TransactionDate,
ROW_NUMBER() OVER(PARTITION BY WorkPlace ORDER BY TransactionDate) AS WP,
ROW_NUMBER() OVER(ORDER BY TransactionDate) AS RN FROM Attendance WHERE Shift = 'Worked'),
CTE2 AS (SELECT Employee, WorkPlace, TransactionDate, WP, RN, WP-RN AS GB FROM CTE1),
CTE3 AS (SELECT Employee, WorkPlace, MIN(TransactionDate) AS TransactionDate, COUNT(1) AS Shifts FROM CTE2 GROUP BY Employee, WorkPlace, GB)
SELECT Employee, WorkPlace, TransactionDate AS [Start Date], DATEADD(DAY,Shifts - 1,TransactionDate) AS [End Date], Shifts FROM CTE3 ORDER BY TransactionDate ASC
我认为你给出的输出是错误的。
我认为你填充的方式 table 是错误的。
查看我的查询,可以进一步优化,不计缺席天数
declare @t table(Name varchar(100),Workplace varchar(100), AttnDate date ,Shifts varchar(100))
insert into @t values
('Jane','WorkplaceA',' 1-Jan-16','Worked')
,('Jane','WorkplaceA',' 2-Jan-16','Worked')
,('Jane','WorkplaceB',' 3-Jan-16','Worked')
,('Jane','WorkplaceB',' 4-Jan-16','Worked')
,('Jane','WorkplaceB',' 5-Jan-16','Worked')
,('Jane','WorkplaceA',' 6-Jan-16','Absent')
,('Jane','WorkplaceA',' 7-Jan-16','Absent')
,('Jane','WorkplaceA',' 8-Jan-16','Worked')
,('Jane','WorkplaceB',' 9-Jan-16','Worked')
,('Jane','WorkplaceB','10-Jan-16','Worked')
DECLARE @Name VARCHAR(100) = 'Jane'
DECLARE @FromDate DATE = '01-Jan-16'
DECLARE @ToDate DATE = '31-Jan-16';
WITH CTE
AS (
SELECT *
,row_number() OVER (
ORDER BY attndate
) rn
FROM @t
WHERE NAME = @Name
AND (
AttnDate BETWEEN @FromDate
AND @ToDate
)
)
,CTE1
AS (
SELECT A.NAME
,A.workplace
,A.AttnDate
,Shifts
,rn
,1 RN1
FROM cte A
WHERE rn = 1
UNION ALL
SELECT a.NAME
,a.workplace
,a.AttnDate
,a.Shifts
,CASE
WHEN a.workplace = b.workplace
THEN b.rn
ELSE b.rn + 1
END rn
,RN1 + 1
FROM CTE A
INNER JOIN CTE1 b ON a.attndate > b.attndate
WHERE a.rn = RN1 + 1
)
,CTE2
AS (
SELECT NAME
,Workplace
,AttnDate beginDate
,(
SELECT max(AttnDate)
FROM CTE1 b
WHERE b.rn = a.rn
) endDate
,(
SELECT count(*)
FROM CTE1 b
WHERE b.rn = a.rn
AND Shifts = 'Worked'
) WorkShift
,rn
,ROW_NUMBER() OVER (
PARTITION BY rn ORDER BY rn
) rn3
FROM cte1 a
)
SELECT NAME
,workplace
,beginDate
,endDate
,WorkShift
FROM cte2
WHERE rn3 = 1
由于公司政策,我无法给出我正在处理的实际查询,但这里是细分和总体思路。我们有一个考勤登记簿,记录员工每天是否上班以及员工在哪里工作。我正在尝试对此进行总结,以说明该员工在该日期和该日期之间工作了 5 个班次。我遇到的问题是,一名特定员工在工作场所 A 工作了 2 天,然后被调到工作场所 B。在工作场所 B 工作几天后,该员工又被调回工作场所 A。
我的尝试结果表明,该员工从 1 月 1 日开始在工作场所 A 工作,到 1 月 10 日结束,只有 2 个工作班次。我在工作地点有一个分组,开始和结束日期是最小和最大选择。
SELECT att.Employee, att.Workplace, dte.BeginDate, dte.EndDate, shf.WorkShift FROM
(SELECT * FROM Attendance WHERE WorkDate BETWEEN '1-Jan' AND '30-Jan') att
CROSS APPLY (SELECT COUNT(Shift) WorkShift FROM Attendance WHERE WorkDate BETWEEN '1-Jan' AND '30-Jan' AND Employee = att.Employee AND WorkPlace = att.WorkPlace AND Shift = 'Worked') shf
CROSS APPLY (SELECT MAX(WorkDate) BeginDate, MIN(WorkDate) EndDate FROM Attendance WHERE WorkDate BETWEEN '1-Jan' AND '30-Jan' AND Employee = att.Employee AND WorkPlace = att.WorkPlace) dte
所以这个员工记录应该是这样的(很抱歉网格非常糟糕,我不知道如何让它看起来漂亮,非常欢迎您对其进行编辑以使其看起来更好)
| Name | Workplace | beginDate | endDate | WorkShift |
| Jane | WorkPlaceA | 1-Jan | 2-Jan | 2 |
| Jane | WorkPlaceB | 3-Jan | 8-Jan | 5 |
| Jane | WorkPlaceA | 9-Jan | 10-Jan | 2 |
出席人数 table 看起来像这样
| Name | Workplace | Date | Shift |
| Jane | WorkplaceA | 1-Jan | Worked |
| Jane | WorkplaceA | 2-Jan | Worked |
| Jane | WorkplaceB | 3-Jan | Worked |
| Jane | WorkplaceB | 4-Jan | Worked |
| Jane | WorkplaceB | 5-Jan | Worked |
| Jane | WorkplaceA | 6-Jan | Absent |
| Jane | WorkplaceA | 7-Jan | Absent |
| Jane | WorkplaceA | 8-Jan | Worked |
| Jane | WorkplaceB | 9-Jan | Worked |
| Jane | WorkplaceB | 10-Jan | Worked |
我相信您可以使用 CTE 来完成此任务。这是显示您的预期值的示例工作代码。
;WITH CTE1 AS (
SELECT Employee, WorkPlace, TransactionDate,
ROW_NUMBER() OVER(PARTITION BY WorkPlace ORDER BY TransactionDate) AS WP,
ROW_NUMBER() OVER(ORDER BY TransactionDate) AS RN FROM Attendance WHERE Shift = 'Worked'),
CTE2 AS (SELECT Employee, WorkPlace, TransactionDate, WP, RN, WP-RN AS GB FROM CTE1),
CTE3 AS (SELECT Employee, WorkPlace, MIN(TransactionDate) AS TransactionDate, COUNT(1) AS Shifts FROM CTE2 GROUP BY Employee, WorkPlace, GB)
SELECT Employee, WorkPlace, TransactionDate AS [Start Date], DATEADD(DAY,Shifts - 1,TransactionDate) AS [End Date], Shifts FROM CTE3 ORDER BY TransactionDate ASC
我认为你给出的输出是错误的。
我认为你填充的方式 table 是错误的。
查看我的查询,可以进一步优化,不计缺席天数
declare @t table(Name varchar(100),Workplace varchar(100), AttnDate date ,Shifts varchar(100))
insert into @t values
('Jane','WorkplaceA',' 1-Jan-16','Worked')
,('Jane','WorkplaceA',' 2-Jan-16','Worked')
,('Jane','WorkplaceB',' 3-Jan-16','Worked')
,('Jane','WorkplaceB',' 4-Jan-16','Worked')
,('Jane','WorkplaceB',' 5-Jan-16','Worked')
,('Jane','WorkplaceA',' 6-Jan-16','Absent')
,('Jane','WorkplaceA',' 7-Jan-16','Absent')
,('Jane','WorkplaceA',' 8-Jan-16','Worked')
,('Jane','WorkplaceB',' 9-Jan-16','Worked')
,('Jane','WorkplaceB','10-Jan-16','Worked')
DECLARE @Name VARCHAR(100) = 'Jane'
DECLARE @FromDate DATE = '01-Jan-16'
DECLARE @ToDate DATE = '31-Jan-16';
WITH CTE
AS (
SELECT *
,row_number() OVER (
ORDER BY attndate
) rn
FROM @t
WHERE NAME = @Name
AND (
AttnDate BETWEEN @FromDate
AND @ToDate
)
)
,CTE1
AS (
SELECT A.NAME
,A.workplace
,A.AttnDate
,Shifts
,rn
,1 RN1
FROM cte A
WHERE rn = 1
UNION ALL
SELECT a.NAME
,a.workplace
,a.AttnDate
,a.Shifts
,CASE
WHEN a.workplace = b.workplace
THEN b.rn
ELSE b.rn + 1
END rn
,RN1 + 1
FROM CTE A
INNER JOIN CTE1 b ON a.attndate > b.attndate
WHERE a.rn = RN1 + 1
)
,CTE2
AS (
SELECT NAME
,Workplace
,AttnDate beginDate
,(
SELECT max(AttnDate)
FROM CTE1 b
WHERE b.rn = a.rn
) endDate
,(
SELECT count(*)
FROM CTE1 b
WHERE b.rn = a.rn
AND Shifts = 'Worked'
) WorkShift
,rn
,ROW_NUMBER() OVER (
PARTITION BY rn ORDER BY rn
) rn3
FROM cte1 a
)
SELECT NAME
,workplace
,beginDate
,endDate
,WorkShift
FROM cte2
WHERE rn3 = 1