Sql server查询以查明员工何时缺席5天或更长时间

时间:2013-05-10 18:18:25

标签: sql-server

我有一张名为timedetail的表,其中输入了工作时间(doecode w)或休假时间(doecode vac)。这是我到目前为止所做的,但它也正在恢复工作时间。

TimeDetail

empnum  tsdate     doecode
123     1/1/2013   VAC
123     1/2/2013   VAC
123     1/3/2013   VAC
123     1/4/2013   VAC
123     1/5/2013   VAC
123     1/6/2013   W
123     1/7/2013   W
123     1/8/2013   W
123     1/9/2013   VAC
111     1/1/2013   W
111     1/2/2013   VAC
111     1/3/2013   W
111     1/4/2013   VAC
111     1/5/2013   VAC

empnum 123应该返回但不是111

WITH R AS (
SELECT
   empnum, tsdate,
   ROW_NUMBER() OVER (PARTITION BY empnum ORDER BY tsdate)
   - ROW_NUMBER() OVER (PARTITION BY empnum ORDER BY tsdate, doecode) as grp
FROM
   timedetail t
WHERE
   doecode in ('VAC') 
--   and not exists (
--      select * from timedetail b where doecode < ' '
--      and b.tsdate = t.tsdate and b.empnum = t.empnum
--   )
)
SELECT empnum, MIN(tsdate) AS fdt, MAX(tsdate) AS tdt, COUNT(*) AS no_of_days
FROM R  
GROUP BY empnum, grp
HAVING COUNT(*) > 4
ORDER BY empnum, MIN(tsdate), MAX(tsdate)

1 个答案:

答案 0 :(得分:1)

鉴于忽略组(VACW)中的差距并容忍重复值的新要求,您提供的查询有两个问题。

  1. 仅按empnum分区两次。这不会返回有用的结果。相反,您需要第二个按empnum, doecode进行分区。

  2. 由于需要按doecode进行分区,因此您无法从派生表中排除任何doecode值,并且必须将WHERE doecode = 'VAC'移出到主查询中。

  3. 我已在以下查询中解决了这些问题:

    WITH R AS (
       SELECT
          T.*,
          Grp = 
             DENSE_RANK() OVER (PARTITION BY T.empnum ORDER BY T.tsdate)
             - DENSE_RANK() OVER (PARTITION BY T.empnum, T.doecode ORDER BY T.tsdate)
             -- the subtracted value has to partition by doecode
       FROM
          dbo.TimeDetail T
    )
    SELECT
       empnum,
       FromDate = MIN(tsdate),
       ToDate = MAX(tsdate),
       DayCount = COUNT(DISTINCT tsdate)
    FROM R
    WHERE doecode = 'VAC' -- must be out here
    GROUP BY empnum, grp
    HAVING COUNT(DISTINCT tsdate) >= 5 -- distinct dates
    ORDER BY
       empnum,
       FromDate
    ;
    

    See this working in a SQL Fiddle

    我使用>= 5而不是> 4,因为我认为它更清楚地表达了意图。

    使用以下“棘手”的测试数据:

    empnum tsdate     doecode
    ------ ---------- -------
    123    2013-01-01 VAC
    123    2013-01-02 VAC
    123    2013-01-03 VAC
    123    2013-01-03 VAC -- duplicate row
    123    2013-01-04 VAC
    123    2013-01-04 VAC -- duplicate row
    123    2013-01-07 VAC -- skipped a weekend
    111    2013-01-01 W
    111    2013-01-02 VAC
    111    2013-01-03 W
    111    2013-01-04 VAC
    111    2013-01-06 W
    111    2013-01-07 W
    111    2013-01-08 W
    111    2013-01-09 W
    111    2013-01-10 W
    

    这将返回:

    empnum FromDate   ToDate     DayCount
    ------ ---------- ---------- --------
    123    2013-01-01 2013-01-07 5
    

    对于记录,如果您的数据是连续的且无法复制,则只需要一个Row_number功能。对顺序项进行分组就像Itzik Ben-Gan的分组岛解决方案一样简单:

    WITH R AS (
       SELECT
          T.*,
          Grp = DateAdd(day, 
             -ROW_NUMBER() OVER (PARTITION BY T.empnum, T.doecode ORDER BY T.tsdate),
             T.tsdate
          )
       FROM
          dbo.TimeDetail T
       WHERE
          doecode in ('VAC') 
    )
    SELECT
       empnum,
       FromDate = MIN(tsdate),
       ToDate = MAX(tsdate),
       DayCount = COUNT(*)
    FROM R  
    GROUP BY empnum, grp
    HAVING COUNT(*) >= 5
    ORDER BY
       empnum,
       FromDate
    ;