T-SQL join to get both mated and non mated start and stop records

被刻印的时光 ゝ 提交于 2019-12-04 08:21:55

Here is a method which abuses the row_number function. Please check the comments for some explanation.

;with Seq as (
    -- Create a master sequence of events
    -- Trust the date column to be accurate (don't match a Begin to an earlier End)
    select id, activitytype, beginend
        , coalesce(businesskey, '') as businesskey -- Needed to match nulls as equal
        , [date], technician, note
        , row_number() over (partition by technician, businesskey, activitytype order by [date], beginend, id) as rownumber
    from TimeEntry
)
select b.id as BeginID
    , e.id as EndID
    , coalesce(b.technician, e.technician) as Technician
    , coalesce(b.businesskey, e.businesskey) as BusinessKey
    , coalesce(b.activitytype, e.activitytype) as ActivityType
    , coalesce(convert(char(10), b.[date], 103), 'Incomplete') as BeginDate
    , coalesce(convert(char(10), e.[date], 103), 'Incomplete') as EndDate
    , coalesce(convert(char(5), b.[date], 108), 'Incomplete') as BeginTime
    , coalesce(convert(char(5), e.[date], 108), 'Incomplete') as EndTime
    , b.note as BeginNote
    , e.note as EndNote
from (select * from Seq where beginend = 'Begin') b -- Get all Begins
    full outer join (select * from Seq where beginend = 'End') e -- Get all Ends
        on b.technician = e.technician
            and b.businesskey = e.businesskey
            and b.activitytype = e.activitytype
            and b.rownumber = e.rownumber - 1 -- Match a Begin with only the very next End of that type
order by coalesce(b.[date], e.[date])
    , coalesce(b.id, e.id)
    , coalesce(b.technician, e.technician)
    , coalesce(b.businesskey, e.businesskey)
    , coalesce(b.activitytype, e.activitytype)

And the SQL Fiddle should anyone want the DDL or demo.

Using CTE's and Row_Number() I think I can return what you are looking for. The key is to only perform your full outer by joining on adajacent rows based upon an ordering of technician, businesskey, activitytype. Anyway here it is:

WITH EventsCTE
AS
(
    select id, technician,businessKey,activityType, 
             CAST(date as date) As date, dateSubmitted,    
             beginEnd, note,
             ROW_NUMBER() OVER 
               (Partition BY technician, 
                businesskey, activityType 
                 ORDER BY dateSubmitted) as rowN
    from TimeEntry
),
BeginEventsCTE
AS
(
    select id, technician,businessKey,activityType, 
             CAST(date as date) As date, 
             dateSubmitted, note, rowN
      from EventsCTE
      WHERE beginEnd = 'Begin'
),
EndEventsCTE
AS
(
    select id, technician,businessKey,
             activityType, CAST(date as date) As date, 
             dateSubmitted, note, rowN
    from EventsCTE
    WHERE beginEnd = 'End'
)
SELECT  B.id, 
        E.id As EndId, 
    COALESCE(B.activityType ,E.activityType ,'Not Available') AS ActivityType,
    COALESCE(convert(VARCHAR(12), B.[date], 103), 'Incomplete') As EventDate, 
    COALESCE(convert(VARCHAR(12), E.[date], 103), 'Incomplete') As EndDate,
    COALESCE(CONVERT(VARCHAR(5) , B.dateSubmitted , 108) , 'Incomplete') As StartTime, 
    COALESCE(CONVERT(VARCHAR(5) , E.dateSubmitted , 108) , 'Incomplete') As EndTime, 
    COALESCE(B.Note, E.note, '') as Note, 
    COALESCE(B.technician, E.technician, 'Not Available') As Technician --, B.rowN, E.rowN
 FROM BeginEventsCTE B
 FULL OUTER join EndEventsCTE E
    ON B.technician = E.technician AND
       B.businessKey = E.businessKey AND
       B.activityType = E.activityType AND
       B.date = E.date AND
       B.rowN = E.rowN - 1
ORDER BY 
    COALESCE(B.Technician, E.Technician),
    COALESCE(b.id,E.id)

And here's the results:

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!