Search code examples
sqlpivotssms

SQL Pivot Half of table


I have a table that consists of time information. It's basically:

Employee, Date, Seq, Time In, Time Out.

They can clock out multiple times a day, so I'm trying to get all of the clock outs in a day on one row. My result would be something like:

Employee, Date, TimeIn1, TimeOut1, TimeIn2, TimeOut2, TimeIn3, TimeOut3....

Where the 1, 2, and 3 are the sequence numbers. I know I could just do a bunch of left joins to the table itself based on employee=employee, date=date, and seq=seq+1, but is there a way to do it in a pivot? I don't want to pivot the employee and date fields, just the time in and time out.


Solution

  • The short answer is: Yes, it's possible.

    The exact code will be updated if/when you provide sample data to clarify some points, but you can absolutely pivot the times out while leaving the employee/work date alone.

    Sorry for the wall of code; none of the fiddle sites are working from my current computer

    
    declare @test table (
        pk int,
        workdate date,
        seq int,
        tIN time,
        tOUT time
    )
    
    insert into @test values 
    (1, '2020-11-25', 1, '08:00', null),
    (1, '2020-11-25', 2, null, '11:00'),
    (1, '2020-11-25', 3, '11:32', null),
    (1, '2020-11-25', 4, null, '17:00'),
    (2, '2020-11-25', 5, '08:00', null),
    (2, '2020-11-25', 6, null, '09:00'),
    (2, '2020-11-25', 7, '09:15', null),
    -- new date
    (1, '2020-11-27', 8, '08:00', null),
    (1, '2020-11-27', 9, null, '08:22'),
    (1, '2020-11-27', 10, '09:14', null),
    (1, '2020-11-27', 11, null, '12:08'),
    (1, '2020-11-27', 12, '01:08', null),
    (1, '2020-11-27', 13, null, '14:40'),
    (1, '2020-11-27', 14, '14:55', null),
    (1, '2020-11-27', 15, null, '17:00')
     
    select * 
    from (
    
      /* this just sets the column header names and condenses their values */
      select 
        pk,
        workdate,
        colName = case when tin is not null then 'TimeIn' + cast(empDaySEQ as varchar) else 'TimeOut' + cast(empDaySEQ as varchar) end,
        colValue = coalesce(tin, tout)
      from (
    
          /* main query */
          select 
            pk,
            workdate, 
            /* grab what pair # this clock in or out is; reset by employee & date */
            empDaySEQ = (row_number() over (partition by pk, workdate order by seq) / 2) + (row_number() over (partition by pk, workdate order by seq) % 2),
            tin,
            tout
          from @test
      ) i
    ) a 
    PIVOT (
     max(colValue) 
     for colName
     IN ( /* replace w/ dynamic if you don't know upper boundary of max in/out pairs */
       [TimeIn1],
       [TimeOut1],
       [TimeIn2],
       [TimeOut2],
       [TimeIn3],
       [TimeOut3],
       [TimeIn4],
       [TimeOut4]
     )
    ) mypivotTable 
    
    
    

    generates these results.

    (I would provide a fiddle demo but they're not working for me today)