SQL-在哪里拥有VS


202

我有以下两个表:

1. Lecturers (LectID, Fname, Lname, degree).
2. Lecturers_Specialization (LectID, Expertise).

我想找到最专业的讲师。当我尝试此操作时,它不起作用:

SELECT
  L.LectID, 
  Fname, 
  Lname 
FROM Lecturers L, 
     Lecturers_Specialization S
WHERE L.LectID = S.LectID
AND COUNT(S.Expertise) >= ALL (SELECT
  COUNT(Expertise)
FROM Lecturers_Specialization
GROUP BY LectID);

但是当我尝试这样做时,它会起作用:

SELECT
  L.LectID,
  Fname,
  Lname 
FROM Lecturers L,
     Lecturers_Specialization S
WHERE L.LectID = S.LectID
GROUP BY L.LectID,
         Fname,
         Lname 
HAVING COUNT(S.Expertise) >= ALL (SELECT
  COUNT(Expertise)
FROM Lecturers_Specialization
GROUP BY LectID); 

是什么原因?谢谢。


2
您能否说明您使用的是哪个SQL版本(MySQL,MS SQL,PostgreSQL,Oracle等)。另外,当您说“不起作用”时,是否表示结果不符合您的预期,或者存在编译/解析错误?
jklemmack 2012年

2
为什么使用ALL而不是MAX?有什么好处吗?
skan 2014年

Answers:


351

WHERE子句在各个行上引入条件; HAVING子句引入了聚合条件,即选择结果,其中已从多个行中产生单个结果,例如计数,平均值,最小值,最大值或总和。您的查询需要第二种条件(即聚合条件),因此HAVING可以正常工作。

根据经验,请WHERE在之前GROUP BYHAVING之后使用GROUP BY。这是一个比较原始的规则,但在90%以上的情况下很有用。

在使用它时,您可能希望使用ANSI版本的联接来重写查询:

SELECT  L.LectID, Fname, Lname
FROM Lecturers L
JOIN Lecturers_Specialization S ON L.LectID=S.LectID
GROUP BY L.LectID, Fname, Lname
HAVING COUNT(S.Expertise)>=ALL
(SELECT COUNT(Expertise) FROM Lecturers_Specialization GROUP BY LectID)

这将消除WHERE用作θ连接条件的条件


39

HAVING对聚合进行操作。由于COUNT是聚合函数,因此不能在WHERE子句中使用它。

这是 MSDN上有关聚合函数一些读物。


30

首先,我们应该知道子句的执行顺序,即 FROM> WHERE> GROUP BY> HAVING> DISTINCT> SELECT> ORDER BY。 由于WHERE子句被执行之前GROUP BY子句中的记录无法通过应用过滤WHEREGROUP BY应用的记录。

“ HAVING与WHERE子句相同,但应用于分组记录”。

首先,WHERE子句根据条件获取记录,然后GROUP BY子句对它们进行相应的分组,然后HAVING子句根据具有条件获取组记录。


是否始终使用此操作顺序?如果查询优化器更改顺序怎么办?
MSIS

1
@MSIS即使查询优化器会改变顺序,结果应该是一样的,就好像这个命令之后。这是一个逻辑顺序。
Stephen

18
  1. WHERE子句可以与SELECT,INSERT和UPDATE语句一起使用,而HAVING只能与SELECT语句一起使用。

  2. WHERE在聚合之前过滤行(GROUP BY),而在聚合之后执行HAVING过滤器组。

  3. 聚合函数不能在WHERE子句中使用,除非它在HAVING子句中包含的子查询中,而聚合函数可以在HAVING子句中使用。

资源


11

在一个查询中没有看到两者的示例。因此,此示例可能会有所帮助。

  /**
INTERNATIONAL_ORDERS - table of orders by company by location by day
companyId, country, city, total, date
**/

SELECT country, city, sum(total) totalCityOrders 
FROM INTERNATIONAL_ORDERS with (nolock)
WHERE companyId = 884501253109
GROUP BY country, city
HAVING country = 'MX'
ORDER BY sum(total) DESC

这将首先按companyId过滤表,然后将其分组(按国家和城市),并进一步将其过滤为仅墨西哥的城市汇总。聚合中不需要companyId,但是在使用GROUP BY之前,我们能够使用WHERE仅过滤出所需的行。


这不是一个好例子,因为您可以将以下代码转换为:`WHERE companyId = 884501253109 GROUP BY国家,城市HAVING country ='MX'`到:'WHERE companyId = 884501253109,country ='MX'GROUP BY城市`
艾蒂安·赫劳特

如果您建议仅将[country]过滤移至WHERE,则查询将因SELECT [country]而出错,因为[country]不再包含在GROUP BY聚合中,因此无法选择。
Nhan

您在优化上的重点是将[国家/地区]移至WHERE,因为这是稍后向GROUP BY设置的较小数据集。当然,这仅仅是说明可能用途的一个例子。我们可以将HAVING sum(total)> 1000更改为包含WHERE和HAVING的完全有效的情况。
Nhan

9

您不能在聚合函数中使用where子句,因为where根据条件获取记录,它将根据记录进入表记录,然后根据我们给出的条件获取记录。这样的时候我们不能在where子句中。虽然having子句适用于resultSet,但在运行查询后我们最终得到了该结果。

查询示例:

select empName, sum(Bonus) 
from employees 
order by empName 
having sum(Bonus) > 5000;

这会将resultSet存储在一个临时内存中,然后haveting子句将执行其工作。因此,我们可以在此处轻松使用聚合函数。


2
我认为没有GROUP BY子句就不能使用HAVING子句。HAVING子句的位置-选择->从->位置->分组->
HAVING-

4

1.我们可以将聚合函数与HAVING子句一起使用,而不能与WHERE子句一起使用,例如min,max,avg。

2. WHERE子句通过元组消除记录元组HAVING子句从组集合中消除整个组

通常,当您有数据组时使用HAVING,而在行中有数据时使用WHERE。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.