如何使用HAVING MAX查询实际上是否正常工作?

时间:2013-04-16 21:09:46

标签: mysql sql select join having

我有两个简单的表:students(sno,sname,age)take(sno,cno)Take是学生与课程之间N-N关系的表格 我想找到不参加特定课程的学生。

以下查询完成了这项工作,但我不清楚它是如何工作的:

SELECT s.sno,s.sname,s.age  
FROM students s LEFT JOIN take t  
ON (s.sno = t.sno)  
GROUP BY s.sno,s.sname,s.age  
HAVING MAX(CASE WHEN t.cno = 'CS112' THEN 1 ELSE 0 END) = 0;  

是否与处理MAXHAVING的订单有关?

执行此操作的一个简单方法是使用子查询:

SELECT * FROM students  
WHERE sno NOT IN  
(SELECT sno FROM take WHERE cno = 'CS112');  

但我有兴趣使用JOIN

来理解版本

4 个答案:

答案 0 :(得分:1)

如果他们有课程,CASE内的MAX会产生1,否则会产生0。对每一行取MAX CASE,如果学生的任何行为1(意味着他们有类),则得1,否则为0。说他们必须HAVING MAX > 1,你说他们必须上课。以最复杂的方式。

答案 1 :(得分:1)

如果您将max()替换为sum(),这可能会更容易理解。

考虑这个select声明:

SELECT s.sno, s.sname,s.age, SUM(CASE WHEN t.cno = 'CS112' THEN 1 ELSE 0 END) as NumCS112

新专栏NumCS112具有学生参加课程的次数。接下来,将其放在having子句中:

HAVING NumCS112 = 0

嗯,这意味着学生参加该课程的次数是0 - 所以学生没有参加该课程。

你可以用max()做同样的事情,你得到一个标志而不是一个计数。所以:

SELECT s.sno, s.sname,s.age, MAX(CASE WHEN t.cno = 'CS112' THEN 1 ELSE 0 END) as HasTaken_CS112
. . .
HAVING HasTaken_CS112 = 0

但是,您没有select子句中的表达式,因此您无法使用HasTaken_CS112。相反,您必须使用完整的表达式。

答案 2 :(得分:0)

MAX确保如果学生只选择其中一个班级是CS112,那么它将失败HAVING语句并且不会返回该学生。

答案 3 :(得分:0)

您可以在JOIN条件中添加cno过滤器而不是where,并在连接的RIGHT部分中查找NULL值(表示不匹配)。

SELECT s.sno, s.sname, s.age
FROM students s LEFT JOIN take t
ON s.sno = t.sno AND t.cno = 'CS112'
WHERE t.cno IS NULL

由于cno上的过滤器处于JOIN状态,因此它实际上不会过滤掉学生(而不是WHERE子句中的过滤器)。如果不匹配,则连接的Take部分将包含NULL,然后我们会过滤掉(过滤掉学生确实参加课程的情况)。