简体   繁体   中英

consecutive dates and appointments in sql

I've got a sql table that holds engineer, appt_date and appt_slot.

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

What I'd like to show is

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

I'm struggling with the sql to show the breaks in the bookings, any help would be greatly appreciated. Thanks

What you want to do is find sequences in the data. Normally, this is sequences of days. Your case is harder because you have these slots, which are presumably half a day.

The solution works by converting the slots to times. I am arbitrarily using 6:00 am for the morning and 6 pm for the evening. I do this using a cross join , because the new rows are created for the "All Days" appointments.

With this data strcture, you can use a SQL trick to identify the slots that belong together. The idea is to enumerate the slots for each engineer by the datetime. Then subtract half a day tiems the enumerated value from the datetime. This is a constant when the values are in order. A new value appears when there are gaps.

Finally, group by the engineer_id and the group id to get the data you want.

The following query shows this in action. It leaves the final results as datetimes, rather than converting them back to slots.

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   

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM