查找类似连续记录的开始日期

时间:2016-11-23 03:37:25

标签: sql sql-server-2008

我有一个名为activities的表,用于存储员工正在进行的活动。它存储简单的信息,例如它们是否正在工作或者它们是否处于各种类型的休假中,例如年假,病假,同情假等。该表存储员工编号,活动类型和活动日期。一天只能进行一种类型的活动,只有正常工作的天数才会有归因于它们的活动。例如,如果员工是星期一到星期五的工作人员并且休假一周,那么周末日期不包括在表中,因为他们不是员工正常工作的日子。

下面是一个示例表:


╔══════════╦════════════╦══════════════╗
║ Employee ║    Date    ║   Activity   ║
╠══════════╬════════════╬══════════════╣
║    12345 ║ 25/11/2016 ║ Work         ║
║    12345 ║ 24/11/2016 ║ Work         ║
║    12345 ║ 23/11/2016 ║ Work         ║
║    12345 ║ 22/11/2016 ║ Work         ║
║    12345 ║ 21/11/2016 ║ Work         ║
║    12345 ║ 18/11/2016 ║ Work         ║
║    12345 ║ 17/11/2016 ║ Work         ║
║    12345 ║ 16/11/2016 ║ Work         ║
║    12345 ║ 15/11/2016 ║ Sick Leave   ║
║    12345 ║ 14/11/2016 ║ Sick Leave   ║
║    12345 ║ 11/11/2016 ║ Sick Leave   ║
║    12345 ║ 10/11/2016 ║ Work         ║
║    12345 ║ 9/11/2016  ║ Work         ║
║    12345 ║ 8/11/2016  ║ Work         ║
║    12345 ║ 7/11/2016  ║ Work         ║
║    12345 ║ 4/11/2016  ║ Work         ║
║    12345 ║ 3/11/2016  ║ Sick Leave   ║
║    12345 ║ 2/11/2016  ║ Sick Leave   ║
║    12345 ║ 1/11/2016  ║ Work         ║
║    12345 ║ 31/10/2016 ║ Work         ║
║    67890 ║ 25/11/2016 ║ Annual Leave ║
║    67890 ║ 24/11/2016 ║ Annual Leave ║
║    67890 ║ 23/11/2016 ║ Annual Leave ║
║    67890 ║ 22/11/2016 ║ Annual Leave ║
║    67890 ║ 21/11/2016 ║ Annual Leave ║
║    67890 ║ 18/11/2016 ║ Work         ║
║    67890 ║ 17/11/2016 ║ Work         ║
║    67890 ║ 16/11/2016 ║ Work         ║
║    67890 ║ 15/11/2016 ║ Sick Leave   ║
║    67890 ║ 14/11/2016 ║ Sick Leave   ║
║    67890 ║ 11/11/2016 ║ Sick Leave   ║
║    67890 ║ 10/11/2016 ║ Work         ║
║    67890 ║ 9/11/2016  ║ Work         ║
║    67890 ║ 8/11/2016  ║ Work         ║
║    67890 ║ 7/11/2016  ║ Work         ║
║    67890 ║ 4/11/2016  ║ Work         ║
║    67890 ║ 3/11/2016  ║ Annual Leave ║
║    67890 ║ 2/11/2016  ║ Annual Leave ║
║    67890 ║ 1/11/2016  ║ Work         ║
║    67890 ║ 31/10/2016 ║ Work         ║
╚══════════╩════════════╩══════════════╝

对于给定的员工,日期和活动,我需要从该日期开始向后工作,并找到该给定活动的最新块的开始日期。 A'块'是同一活动的任何组,因此可能是1天或许多天。

例如,使用上表,让我们说我需要找到最近“病假”的开始日期'员工12345从2016年11月20日起倒退。在这种情况下,我希望获得“2016年11月11日”的价值。因为这是最近一段病假的开始日期。

另一个例子,使用上面的表格,我们要说我需要找到最近的年假的开始日期'员工67890从2016年11月20日起倒退。在这种情况下,我希望获得“2016年11月21日”的价值。因为这是最近年假的开始日期。

1 个答案:

答案 0 :(得分:1)

这是一个" gap-and-islands"问题。您可以使用行号方法的差异来获取员工的活动周期:

select employee, activity, min(date), max(date)
from (select t.*,
             row_number() over (partition by employee order by date) as seqnum_e,
             row_number() over (partition by employee, activity order by date) as seqnum_ea
      from t
     ) t
group by employee, activity, (seqnum_e - seqnum_ea);

然后您可以使用它来回答您的问题。例如:

with ea as (
      select employee, activity, min(date) as date_from, max(date) as date_to
      from (select t.*,
                   row_number() over (partition by employee order by date) as seqnum_e,
                   row_number() over (partition by employee, activity order by date) as seqnum_ea
            from t
           ) t
      group by employee, activity, (seqnum_e - seqnum_ea)
     )
select top 1 ea.*
from ea
where employee = 12345 and activity = 'Sick Leave'
order by date_from desc;

对于特定问题还有其他解决方案,但这可能是最常见的。

相关问题