SQL Query to group by time and roll up and concatenate string values

373 views Asked by At

I am trying to get a particular format from a group of times and days between two tables.

Database: MeetingTime table has a relationship from MeetingTime.DayOfWeekId (foreign key) to table DayOfWeek.Id (Primary Key). Example Query:

select t.ClassId, d.Name, t.StartTime, t.EndTime
From MeetingTime t
Inner Join DaysOfWeek d on d.Id = t.DayOfWeekId
Where t.classId = 8

Results:

enter image description here

My desired results for this set of data would be one row, because the start and end times are the same.

09:00-15:35 M/T/W/Th/F

NOTE, the start and end time above, can be separate columns above, the main goal is display the days of the week for each grouped time.

The monkey wrench is that the times can be completely different or the same. For example this data set: enter image description here

I would want displayed in 2 rows:

07:35-14:15 M/T/W

08:00-14:15 Th/F

And finally, this dataset where all times are different:

enter image description here

Would display in 5 rows:

13:48-14:48 M

15:48-16:48 T

05:49-23:53 W

14:49-16:49 Th

13:49-16:49 F

I haven't had much success with grouping the times. I did figure out how to concatenate the days of the week rolling the days up into one column using the 'Stuff' Operator, but didn't get anywhere with the grouping of the start and end time coupled with this yet.

Concatenating and rolling up days:

   STUFF((SELECT '/ ' + 
      (CASE
            WHEN d.[Name] = 'Thursday' THEN SUBSTRING(d.[Name], 1, 2)
            WHEN d.[Name] = 'Sunday' THEN 'U'
            WHEN d.[Name] != '' THEN SUBSTRING(d.[Name], 1, 1)
            ELSE NULL
        END)
      FROM MeetingTime m
        Inner Join [DayOfWeek] d on d.Id = m.DayOfWeekId
        Where m.ClassId = class.Id
      FOR XML PATH('')), 1, 1, '') [ClassSchedule]

I'm also not opposed to just returning the rows and handling the data manipulation in C# code, but wanted to see if SQL could handle it.

1

There are 1 answers

0
cmartin On BEST ANSWER

I was able to get this working. Here is the query:

select 
t.ClassId, 
t.StartTime, 
t.EndTime,
STUFF((SELECT '/' + (CASE
                        WHEN w.[Name] = 'Thursday' THEN SUBSTRING(w.[Name], 1, 2)
                        WHEN w.[Name] = 'Sunday' THEN 'U'
                        WHEN w.[Name] != '' THEN SUBSTRING(w.[Name], 1, 1)
                        ELSE NULL
                    END)
      From MeetingTime s
      Inner Join DayOfWeek w on w.Id = s.DayOfWeekId
      Where s.classId = 7 and s.DayOfWeekId > 0 
      and s.StartTime = t.StartTime 
      and s.EndTime = t.EndTime
      FOR XML PATH('')), 1, 1, '') [ClassSchedule]
From MeetingTime t
Inner Join DayOfWeek d on d.Id = t.DayOfWeekId
Where t.classId = 7 and t.DayOfWeekId > 0
Group by t.StartTime, t.EndTime, t.ClassId

Obviously hardcoded Id you would want to create a variable.

Results where the start and end time are all the same: enter image description here

Some times the same and some different: enter image description here

Some times the same and some different with days not in order: enter image description here

Times all different:

enter image description here

Times with only Mon/Wed/Fri.

enter image description here

I feel pretty good about this, except I'd like to fix the order of the above result image where all times are different and the days are not in chronological order.