SQL 查询对同一行中的类似值进行分组并对其他值进行连接和排序

问题描述 投票:0回答:2

使用 SQL 版本 15.0.2000.5

我有一个包含这些数据的表格:

学生时间表ID 星期一 星期二 周三 星期四 周五 周一开始时间 周一结束时间 周二开始时间 周二结束时间 周三开始时间 周三结束时间 周四开始时间 周四结束时间 周五开始时间 周五结束时间
15 1 1 1 1 9:00 11:00 11:00 12:30 9:00 11:00 11:00 12:30
31 1 1 0 2:00 3:15 2:00 3:15

我想实现这种格式:

学生时间表ID 日程 开始时间 结束时间
15 T/Th 11:00 12:30
15 M/W 9:00 11:00
31 M 9:00 11:00

我能够使用此查询来做到这一点:

Select s.StudentScheduleId, 
    STRING_AGG(s.[Day], '/') AS Schedule, 
    s.StartTime, 
    s.EndTime
From
(
(Select s.StudentScheduleId, 'M' As [Day], s.MondayStartTime As StartTime, s.MondayEndTime As EndTime
From StudentSchedule s
Where s.Monday = 1)
UNION
(Select s.StudentScheduleId, 'T' As [Day], s.TuesDayStartTime As StartTime, s.TuesdayEndTime As EndTime
From StudentSchedule s
Where s.Tuesday = 1)
UNION
(Select s.StudentScheduleId, 'W' As [Day], s.WednesdayStartTime As StartTime, s.WednesdayEndTime As EndTime
From StudentSchedule s
Where s.Wednesday = 1)
UNION
(Select s.StudentScheduleId, 'Th' As [Day], s.ThursdayStartTime As StartTime, s.ThursdayEndTime As EndTime
From StudentSchedule s
Where s.Thursday = 1)
UNION
(Select s.StudentScheduleId, 'F' As [Day], s.FridayStartTime As StartTime, s.FridayEndTime As EndTime
From StudentSchedule s
Where s.Friday = 1)
) As s
Group By s.StudentScheduleId, s.StartTime, s.EndTime

但是,我对结果有一个担忧和一个问题。

  1. 考虑到性能或者只是更简洁,是否有更好、更熟练的方法来做到这一点?我预计该表不会达到数百万条记录,但我可以看到它最终会增长到数百条记录。
  2. 我使用一周中更多天具有相同的开始和结束时间来测试其他场景,并且时间表列结果可以按任何顺序出现。 (例如:F/M/T/Th/W)。我希望这按逻辑顺序 M/T/W/Th/F 出现。我知道 STRING_AGG 的WITHIN GROUP 排序,但没有什么可排序的,或者我需要添加一个排序列,有什么想法吗?

感谢您的帮助!

sql sql-server group-by concatenation aggregate
2个回答
0
投票

我弄清楚了如何使用WITHIN GROUP和case语句对聚合计划进行排序,该语句适用于一组已知的值。 您可以在这里找到更多信息:STRING_AGG

Select s.StudentScheduleId, 
    STRING_AGG(s.[Day], '/') WITHIN GROUP (Order By CASE
                                                      WHEN [Day] = 'M' THEN 1
                                                      WHEN [Day] = 'T' THEN 2
                                                      WHEN [Day] = 'W' THEN 3
                                                      WHEN [Day] = 'Th' THEN 4
                                                      WHEN [Day] = 'F' THEN 5
                                                 END ASC) AS Schedule, 
    s.StartTime, 
    s.EndTime
From
(
(Select s.StudentScheduleId, 'M' As [Day], s.MondayStartTime As StartTime, s.MondayEndTime As EndTime
From StudentSchedule s
Where s.Monday = 1)
UNION
(Select s.StudentScheduleId, 'T' As [Day], s.TuesDayStartTime As StartTime, s.TuesdayEndTime As EndTime
From StudentSchedule s
Where s.Tuesday = 1)
UNION
(Select s.StudentScheduleId, 'W' As [Day], s.WednesdayStartTime As StartTime, s.WednesdayEndTime As EndTime
From StudentSchedule s
Where s.Wednesday = 1)
UNION
(Select s.StudentScheduleId, 'Th' As [Day], s.ThursdayStartTime As StartTime, s.ThursdayEndTime As EndTime
From StudentSchedule s
Where s.Thursday = 1)
UNION
(Select s.StudentScheduleId, 'F' As [Day], s.FridayStartTime As StartTime, s.FridayEndTime As EndTime
From StudentSchedule s
Where s.Friday = 1)
) As s
Group By s.StudentScheduleId, s.StartTime, s.EndTime

0
投票

我会对数据集进行工作日和排序顺序的联接。这样您只需解析一次源表,而不是每个工作日解析一次。

我当天加入,然后按计划聚合,并按sortcolumn排序聚合天数:

WITH tab
AS
(SELECT
        *
    FROM (VALUES
    (15, 1, 1, 1, 1, NULL, '9:00', '11:00', '11:00', '12:30', '9:00', '11:00', '11:00', '12:30', NULL, NULL)
    , (31, 1, NULL, NULL, 1, 0, '2:00', '3:15', 'NULL', 'NULL', 'NULL', 'NULL', '2:00', '3:15', NULL, NULL)
    ) a (StudentScheduleId, Monday, Tuesday, Wednesday, Thursday, Friday, MondayStartTime, MondayEndTime, TuesdayStartTime, TuesdayEndTime, WednesdayStartTime, WednesdayEndTime, ThursdayStartTime, ThursdayEndTime, FridayStartTime, FridayEndTime))
,cte AS(
SELECT
    a.StudentScheduleId
    ,b.DayNm
    ,b.DayNum
   ,CASE
        WHEN DayNm = 'M' THEN a.MondayStartTime
        WHEN DayNm = 'T' THEN a.TuesdayStartTime
        WHEN DayNm = 'W' THEN a.WednesdayStartTime
        WHEN DayNm = 'Th' THEN a.ThursdayStartTime
        WHEN DayNm = 'F' THEN a.FridayStartTime
    END Starttime
   ,CASE
        WHEN b.DayNm = 'M' THEN a.MondayEndTime
        WHEN b.DayNm = 'T' THEN a.TuesdayEndTime
        WHEN b.DayNm = 'W' THEN a.WednesdayEndTime
        WHEN b.DayNm = 'Th' THEN a.ThursdayEndTime
        WHEN b.DayNm = 'F' THEN a.FridayEndTime
    END EndTime
FROM tab a
inner JOIN (VALUES ('M',1),('T',2),('W',3),('Th',4),('F',5))b(DayNm,DayNum)
ON
(   b.DayNm = 'M' AND a.Monday = 1)
OR( b.DayNm = 'T' AND a.Tuesday = 1 )
OR( b.DayNm = 'W' AND a.Wednesday = 1)
OR( b.DayNm = 'Th' AND a.Thursday = 1)
OR( b.DayNm = 'F' AND a.Friday = 1 )
)
SELECT StudentScheduleId
,STRING_AGG(DayNm,',') WITHIN GROUP (ORDER BY daynum)
      ,Starttime
      ,EndTime 
      FROM cte
GROUP BY StudentScheduleId
    ,Starttime
      ,EndTime 
© www.soinside.com 2019 - 2024. All rights reserved.