sql中的连续日期和约会

时间:2012-11-08 12:32:37

标签: sql sql-server-2008

我有一个包含工程师,appt_date和appt_slot的sql表。

engineer_id, visit_date, visit_slot

1,           20/10/12,   All Day
1,           21/10/12,   AM
2,           20/10/12,   All Day
2,           21/10/12,   All Day
2,           22/10/12,   All Day
3,           20/10/12,   PM
3,           21/10/12,   All Day
3,           22/10/12,   PM

我想展示的是

Engineer_id, start_visit,      end_visit

1,           20/10/12 All Day, 21/10/12 AM
2,           20/10/12 All Day, 22/10/12 All Day
3,           20/10/12 PM,      21/10/12 All Day
3,           22/10/12 PM,      22/10/12 PM

我正在努力与sql一起展示预订中的休息时间,我们将非常感谢任何帮助。 感谢

1 个答案:

答案 0 :(得分:1)

您要做的是在数据中查找序列。通常,这是几天的序列。你的情况比较困难,因为你有这些插槽,大概是半天。

解决方案的工作原理是将插槽转换为时间。我是早上6点和早上6点任意使用的。为了晚上。我使用cross join执行此操作,因为新行是为“所有日期”约会创建的。

使用此数据结构,您可以使用SQL技巧来识别属于一起的插槽。我们的想法是按日期时间计算每个工程师的插槽。然后从日期时间中减去半天的枚举值。当值按顺序时,这是一个常量。当存在间隙时会出现新值。

最后,通过engineer_id和组ID分组以获取所需的数据。

以下查询显示了此操作。它将最终结果保留为日期时间,而不是将它们转换回插槽。

with t as (
    select 1 as engineer_id, cast('2012-10-20' as date) as visit_date, 'All Day' as visit_slot union all
    select 1 as engineer_id, cast('2012-10-21' as date) as visit_date, 'AM' as visit_slot union all
    select 2 as engineer_id, cast('2012-10-20' as date) as visit_date, 'All Day' as visit_slot union all
    select 2 as engineer_id, cast('2012-10-21' as date) as visit_date, 'All Day' as visit_slot union all
    select 2 as engineer_id, cast('2012-10-22' as date) as visit_date, 'All Day' as visit_slot union all
    select 3 as engineer_id, cast('2012-10-20' as date) as visit_date, 'PM' as visit_slot union all
    select 3 as engineer_id, cast('2012-10-21' as date) as visit_date, 'All Day' as visit_slot union all
    select 3 as engineer_id, cast('2012-10-22' as date) as visit_date, 'PM' as visit_slot
   ),
   tslots as (
    select t2.*
    from (select t.engineer_id,
                 (CAST(visit_date as datetime) +
                      (case when t.visit_slot in ('All Day', const.slot) then const.hr/24.0 end)
                 ) as visit_datetime
          from t cross join
               (select 'AM' as slot, 6 as hr union all select 'PM', 18) const
         ) t2
    where visit_datetime is not null
    group by engineer_id, visit_datetime
   )
select engineer_id, MIN(visit_datetime) as min_datetime, MAX(visit_datetime) as max_datetime
from (select ts.*,
             ROW_NUMBER() over (partition by engineer_id order by visit_datetime) as seqnum,
             visit_datetime - 0.5*(ROW_NUMBER() over (partition by engineer_id order by visit_datetime)) as groupid
      from tslots ts
     ) ts1
group by engineer_id, groupid
order by 1, 2