我有一个相当复杂的看似查询,它将构成在线课堂安排工具的基础。我的挑战是开发一种方法来识别用户在st_schedule表中注册的类,然后从类的整个表中推断出st_classes,哪些其他类是可用的,与用户的当前类不冲突。 / p>
例如,如果用户在st_schedule中有一个条目,从早上8点到早上9点将它们分配给一个班级,那么他们就没有资格参加上午8:00到9:00之间的任何班级。上午7:15 - 上午8:15运行的课程会使用户不合格。我将类的开始时间和结束时间分别存储在数据库中以进行比较。重要的是,这应该尽可能灵活,因此“阻塞”时间和为块分配时间的概念是不可能的。
以下是表格的摘录:
table st_classes (holds class information)
id
start_time
end_time
table st_schedule (holds schedule information)
id
user_id
class_id
我当然可以在服务器端的一系列循环中执行此操作,但我必须认为有一种MySQL方法可以一举完成这种类型的操作。
答案 0 :(得分:3)
您希望将两个表连接在一起以表示用户的类,然后查找未注册的类,其中开始时间和结束时间不在用户类的开始和结束时间之间。
像这样的东西。完全脱下袖口,未经测试:
SELECT
*
FROM
st_schedule s
INNER JOIN st_classes c ON c.id = s.class_id
INNER JOIN st_classes all_classes
ON all_classes.start_time NOT BETWEEN c.start_time AND c.end_time
AND all_classes.end_time NOT BETWEEN c.start_time AND c.end_time
WHERE
s.user_id = 1
编辑:尝试#2 我只有一点时间来看看这个。我想我颠倒了第二个连接条款。 all_classes别名表示完整的类列表,其中“c”别名表示学生注册的类。
SELECT DISTINCT
all_classes.*
FROM
st_schedule s
INNER JOIN st_classes c ON c.id = s.class_id
INNER JOIN st_classes all_classes
ON c.start_time NOT BETWEEN all_classes.start_time AND all_classes.end_time
AND c.end_time NOT BETWEEN all_classes.start_time AND all_classes.end_time
WHERE
s.user_id = 1
答案 1 :(得分:1)
这是在mssql中使用表变量,但是sql选择应该转换为mysql
首先是样本数据
DECLARE @st_classes TABLE
(
ID INT NOT NULL,
Title VARCHAR(40) NOT NULL,
StartTime DATETIME NOT NULL,
EndTime DATETIME NOT NULL
)
DECLARE @st_schedule TABLE
(
ID INT NOT NULL,
UserID INT NOT NULL,
ClassID INT NOT NULL
)
INSERT INTO @st_classes (ID, Title, StartTime, EndTime)
SELECT 1,'Class1','08:00:00','09:30:00' UNION
SELECT 2,'Class2','09:30:00','11:30:00' UNION
SELECT 3,'Class3','11:30:00','16:00:00' UNION
SELECT 4,'Class4','16:00:00','17:30:00' UNION
SELECT 5,'Class5','09:00:00','11:45:00' UNION
SELECT 6,'Class6','07:00:00','18:00:00'
INSERT INTO @st_schedule(ID, UserID, ClassID)
SELECT 1,1,1 UNION
SELECT 2,1,2 UNION
SELECT 3,2,6
接下来一点sql确认表加入OK(为ID为1的用户选择预定课程) - 返回1级和2级
SELECT *
FROM @st_schedule AS S INNER JOIN
@st_classes AS C ON S.ClassID = C.ID
WHERE S.UserID = 1
现在我们需要选择与时间明确重叠的课程的所有课程ID(包括预定课程) - 返回1,2,5,6
SELECT AC.ID
FROM @st_classes AS AC
INNER JOIN ( SELECT C.StartTime,
C.EndTime
FROM @st_schedule AS S
INNER JOIN @st_classes AS C ON S.ClassID = C.ID
WHERE S.UserID = 1
) AS UC ON ( AC.StartTime < DATEADD(ss, -1, UC.EndTime)
AND DATEADD(ss, -1, UC.EndTime) > UC.StartTime
)
GROUP BY AC.ID
现在我们需要选择课程ID不在重叠课程ID列表中的所有课程。 - 返回课程3和4
SELECT *
FROM @st_classes
WHERE ID NOT IN (
SELECT AC.ID
FROM @st_classes AS AC
INNER JOIN ( SELECT C.StartTime,
C.EndTime
FROM @st_schedule AS S
INNER JOIN @st_classes AS C ON S.ClassID = C.ID
WHERE S.UserID = 1
) AS UC ON ( AC.StartTime < DATEADD(ss, -1, UC.EndTime)
AND DATEADD(ss, -1, UC.EndTime) > UC.StartTime
)
GROUP BY AC.ID )
将用户ID过滤器更改为2,因为分配给该用户的课程与所有课程重叠,所以不应返回任何内容。