对于模糊的标题感到抱歉(我只是不知道如何描述这个难题)
为教室提供以下计划表:
╔═══════════╦════════════╦═══════════╦═══════════╦═════════╗
║ Classroom ║ CourseName ║ Lesson ║ StartTime ║ EndTime ║
╠═══════════╬════════════╬═══════════╬═══════════╬═════════╣
║ 1001 ║ Course 1 ║ Lesson 1 ║ 0800 ║ 0900 ║
║ 1001 ║ Course 1 ║ Lesson 2 ║ 0900 ║ 1000 ║
║ 1001 ║ Course 1 ║ Lesson 3 ║ 1000 ║ 1100 ║
║ 1001 ║ Course 2 ║ Lesson 10 ║ 1100 ║ 1200 ║
║ 1001 ║ Course 2 ║ Lesson 11 ║ 1200 ║ 1300 ║
║ 1001 ║ Course 1 ║ Lesson 4 ║ 1300 ║ 1400 ║
║ 1001 ║ Course 1 ║ Lesson 5 ║ 1400 ║ 1500 ║
╚═══════════╩════════════╩═══════════╩═══════════╩═════════╝
我想将表格分组以显示:
╔═══════════╦════════════╦═══════════╦═════════╗
║ Classroom ║ CourseName ║ StartTime ║ EndTime ║
╠═══════════╬════════════╬═══════════╬═════════╣
║ 1001 ║ Course 1 ║ 0800 ║ 1100 ║
║ 1001 ║ Course 2 ║ 1100 ║ 1300 ║
║ 1001 ║ Course 1 ║ 1300 ║ 1500 ║
╚═══════════╩════════════╩═══════════╩═════════╝
基本上我们正在查看一个时间表,显示在某个时间段内哪个教室正在使用什么教室......
我最初的想法是:
按Classroom
和CourseName
分组,Max
和Min
start\end
Classroom
时间,但这不会给我时间跨度,就像课程1一样使用{{1}}从08:00到16:00,中间没有休息。
答案 0 :(得分:8)
查询使用EndTime
确定每一行NOT EXISTS
,以确保在课程范围StartTime
和EndTime
之间没有安排其他类别或课程。然后使用MIN
和GROUP BY
查找StartTime
。
NOT EXISTS
部分通过搜索StartTime
之间EndTime
的任何行,确保EndTime
和StartTime
范围之间没有“中断” }和EndTime
但属于不同的CourseName
或CourseRoom
。
SELECT
t0.ClassRoom,
t0.CourseName,
MIN(t0.StartTime),
t0.EndTime
FROM (
SELECT
t1.ClassRoom,
t1.CourseName,
t1.StartTime,
(
SELECT MAX(t2.EndTime)
FROM tableA t2
WHERE t2.CourseName = t1.CourseName
AND t2.ClassRoom = t1.ClassRoom
AND NOT EXISTS (SELECT 1 FROM tableA t3
WHERE t3.EndTime < t2.EndTime
AND t3.EndTime > t1.EndTime
AND (t3.CourseName <> t2.CourseName
OR t3.ClassRoom <> t2.ClassRoom)
)
) EndTime
FROM tableA t1
) t0 GROUP BY t0.ClassRoom, t0.CourseName, t0.EndTime
答案 1 :(得分:3)
如果您正在使用SQLServer 2012或更高版本,则可以使用LAG
获取列的先前值,然后使用SUM() OVER (ORDER BY ...)
创建滚动总和,在这种情况下,可以计算更改CourseName,可以用作GROUP BY
锚点
With A AS (
SELECT ClassRoom
, CourseName
, StartTime
, EndTime
, PrevCourse = LAG(CourseName, 1, CourseName) OVER (ORDER BY StartTime)
FROM Table1
), B AS (
SELECT ClassRoom
, CourseName
, StartTime
, EndTime
, Ranker = SUM(CASE WHEN CourseName = PrevCourse THEN 0 ELSE 1 END)
OVER (ORDER BY StartTime, CourseName)
FROM A
)
SELECT ClassRoom
, CourseName
, MIN(StartTime) StartTime
, MAX(EndTime) EndTime
FROM B
GROUP BY ClassRoom, CourseName, Ranker
ORDER BY StartTime
答案 2 :(得分:1)
CREATE TABLE Classroom(Classroom VARCHAR(100), CourseName VARCHAR(100), Lesson VARCHAR(100), StartTime VARCHAR(100), EndTime VARCHAR(100))
INSERT INTO Classroom
SELECT '1001','Course 1','Lesson 1 ','0800','0900'
UNION SELECT '1001','Course 1','Lesson 2 ','0900','1000'
UNION SELECT '1001','Course 1','Lesson 3 ','1000','1100'
UNION SELECT '1001','Course 2','Lesson 10','1100','1200'
UNION SELECT '1001','Course 2','Lesson 11','1200','1300'
UNION SELECT '1001','Course 1','Lesson 4 ','1300','1400'
UNION SELECT '1001','Course 1','Lesson 5 ','1400','1500'
SELECT * FROM Classroom
;WITH CTE_ClassRooms AS (
SELECT *,ROW_NUMBER() over(partition by classroom,CourseName order by StartTime) AS R FROM Classroom A
WHERE NOT EXISTS(SELECT 1 FROM Classroom B WHERE B.Classroom = A.Classroom AND B.CourseName = A.CourseName AND B.StartTime = A.EndTime)
UNION ALL
SELECT B.*,R fROM CTE_ClassRooms A JOIN Classroom B ON B.Classroom = A.Classroom AND B.CourseName = A.CourseName AND A.StartTime = B.EndTime
)
--SELECT * FROM CTE_ClassRooms order by Classroom,CourseName,R
SELECT Classroom,CourseName,MIN(StartTime),MAX(EndTime)
FROM CTE_ClassRooms
GROUP BY Classroom,CourseName,R