出勤总结报告

时间:2016-04-04 10:28:41

标签: sql-server 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         |

出勤表看起来像这样

| 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 |

2 个答案:

答案 0 :(得分:1)

我相信你可以用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

答案 1 :(得分:0)

I think your given output is wrong.

I think the way you are populating table is wrong.

Check my query,it can be further optmize,it do not count absent days

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