SQL获取期间的状态

时间:2016-04-28 09:05:52

标签: sql sql-server

我正在寻找针对以下问题的SQL解决方案。 我想要一份超过14天连续生病的员工名单。

我有一个包含以下内容的SQL表:

First_name, Last_Name, INDIRECT_ID, SHIFT_DATE
John, Doe, Sick, 2016-01-01
John, Doe, Sick, 2016-01-02
John, Doe, working, 2016-01-03
John, Doe, Sick, 2016-01-04
John, Doe, Sick, 2016-01-05
etc.

我想通过观察他们是否在两周内生病10x(2x5个工作日)来做到这一点。但也许有一个更简单的解决方案。但现在我也得到了重复的答案。

  select FIRST_NAME, LAST_NAME
from (select t.*
             ,(select count(*)
              from LABOR_TICKET t2
              where t2.EMPLOYEE_ID = t.EMPLOYEE_ID and
                    t2.INDIRECT_ID = t.INDIRECT_ID and
                    t2.SHIFT_DATE >= t.SHIFT_DATE and 
                    t2.SHIFT_DATE < DATEADD(day, 14, t.SHIFT_DATE)) NumWithin14Days
      from LABOR_TICKET t 
      where SHIFT_DATE between '2016-01-01' and '2016-04-01'
     ) LABOR_TICKET 
    INNER JOIN
                      EMPLOYEE ON LABOR_TICKET.EMPLOYEE_ID = EMPLOYEE.ID

where NumWithin14Days >= 10 AND INDIRECT_ID = 'SICK'

4 个答案:

答案 0 :(得分:0)

试试这个, 首先在From Date和To Date之间创建所有14天的间隔。 然后检查每个员工每个时间间隔内“生病”的计数是14。

DECLARE @ST_DATE    DATE='2016-01-01'
        ,@ED_DATE   DATE='2016-04-01'
;WITH CTE_DATE AS (

    SELECT  @ST_DATE AS ST_DATE,DATEADD(DAY,13,@ST_DATE) AS ED_DATE
    UNION ALL
    SELECT  DATEADD(DAY,1,ED_DATE),DATEADD(DAY,14,ED_DATE)
    FROM    CTE_DATE
    WHERE   DATEADD(DAY,14,ED_DATE) <= @ED_DATE
)
SELECT  FIRST_NAME, LAST_NAME
FROM    CTE_DATE
    INNER JOIN LABOR_TICKET ON SHIFT_DATE BETWEEN ST_DATE AND ED_DATE
WHERE INDIRECT_ID = 'Sick'
GROUP BY FIRST_NAME, LAST_NAME
HAVING   COUNT(*) >= 14

答案 1 :(得分:0)

伪代码,为您提供所有员工的想法

如果你有一个如下所示的日历表

onSelectDate

现在你可以将你的主表连接到

create table dates
(
datetime date
)

insert into dates
select '2016-01-01'
union all
select '2016-01-02'

答案 2 :(得分:0)

你应该抛出更多样本数据。

试试这个,(我相信它可以与其他样本数据一起使用)很少有东西可以过滤数据。

declare @t table(First_name varchar(50), Last_Name varchar(50), INDIRECT_ID varchar(50), SHIFT_DATE date)
insert into @t values
('John', 'Doe', 'Sick', '2016-01-01')
,('John', 'Doe', 'Sick', '2016-01-02')
,('John','Doe','working','2016-01-03')
,('John', 'Doe', 'Sick', '2016-01-04')
,('John', 'Doe', 'Sick', '2016-01-05')

declare @name varchar(50)='John'
declare @month int=1
;With CTE as
(
  select top 1 First_name,Last_Name,SHIFT_DATE,1 rn  from @T where First_name=@name 
    and INDIRECT_ID='Sick' order by SHIFT_DATE
    union all
    select  t.First_name,t.Last_Name,t.SHIFT_DATE, rn+1  from @T t 
    inner join cte c on t.First_name=c.First_name
where  INDIRECT_ID='Sick' 
    and t.SHIFT_DATE=DATEADD(day,1,c.SHIFT_DATE)
    and t.SHIFT_DATE<='2016-01-31'
)

select * from CTE where rn>=14

答案 3 :(得分:0)

declare @t table(First_name varchar(50), Last_Name varchar(50), INDIRECT_ID varchar(50), SHIFT_DATE date)
insert into @t values
('John', 'Doe', 'Sick',  '2016-01-01')
,('John', 'Doe', 'Sick', '2016-01-02')
,('John','Doe','working','2016-01-03')
,('John', 'Doe', 'Sick', '2016-04-04')
,('John', 'Doe', 'Sick', '2016-05-05')

select  s.*
        ,u.* 
        ,Sickdays = 
        case 
        when s.indirect_id = 'Sick' and u.indirect_id = 'Sick' then datediff(dd,u.shift_date,s.shift_date)
        else 0
        end
from 
(
select  t.*,
        row_number() over(partition by last_name,first_name order by shift_date desc)  rn
from    @t t
) s
join    
(select t.*,
        row_number() over(partition by last_name,first_name order by shift_date desc)  rn
from    @t t
) u on s.last_name = u.last_name and s.first_name = u.first_name  and s.rn = u.rn - 1
where 
        case 
        when s.indirect_id = 'Sick' and u.indirect_id = 'Sick' then datediff(dd,u.shift_date,s.shift_date)
        else 0
        end > 13