【问题标题】:SQL - HAVING vs. WHERESQL - 拥有与在哪里
【发布时间】:2012-03-04 10:12:32
【问题描述】:

我有以下两张表:

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); 

是什么原因?谢谢。

【问题讨论】:

  • 您能否说明您使用的是哪个版本的 SQL(MySQL、MS SQL、PostgreSQL、Oracle 等)。另外,当您说“不起作用”时,您的意思是结果与您预期的不一样,还是存在编译/解析错误?
  • 为什么使用 ALL 而不是 MAX?有什么优势吗?

标签: sql where-clause having


【解决方案1】:

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

根据经验,在GROUP BY 之前使用WHERE,在GROUP BY 之后使用HAVING。这是一个相当原始的规则,但在超过 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)

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

【讨论】:

  • 如果在 group by 之后使用 where 会降低性能吗?
【解决方案2】:

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

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

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

【讨论】:

  • 总是使用这个操作顺序吗?如果查询优化器改变了顺序怎么办?
  • @MSIS 即使查询优化器更改了顺序,结果也应该与 就像 遵循此顺序一样。这是一个合乎逻辑的顺序。
【解决方案3】:

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

Here's 一些从 MSDN 阅读的关于聚合函数的内容。

【讨论】:

    【解决方案4】:
    1. WHERE 子句可以与 SELECT、INSERT 和 UPDATE 语句一起使用,而 HAVING 只能与 SELECT 语句一起使用。

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

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

    Source

    【讨论】:

      【解决方案5】:

      没有在一个查询中看到两者的示例。所以这个例子可能会有所帮助。

        /**
      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 country, city HAVING country = 'MX' ` to: ` WHERE companyId = 884501253109, country = 'MX' GROUP BY城市`
      • 如果只是将 [country] 过滤移动到您建议的 WHERE,则查询将从 SELECT [country] 出错,因为 [country] 不再包含在 GROUP BY 聚合中,因此无法选择。
      • 您在优化方面的观点是将 [country] 移至 WHERE,因为这将是一个较小的数据集,以便稍后进行 GROUP BY。当然,这只是说明可能用途的示例。我们可以将 HAVING sum(total) > 1000 更改为包含 WHERE 和 HAVING 的完全有效的情况。
      【解决方案6】:

      你不能将where子句与聚合函数一起使用,因为where根据条件获取记录,它会逐条记录进入表中,然后根据我们给出的条件获取记录。所以那个时候我们不能用where子句。虽然有子句适用于我们在运行查询后最终得到的结果集。

      查询示例:

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

      这会将结果集存储在临时内存中,然后有子句将执行其工作。所以我们可以在这里轻松地使用聚合函数。

      【讨论】:

      • 我认为我们不能在没有 GROUP BY 子句的情况下使用 HAVING 子句。 HAVING 子句的位置 - SELECT -> FROM ->WHERE ->GROUP BY -> HAVING -> ORDER BY
      • @Morez 如 MySQL 8.0 参考手册(dev.mysql.com/doc/refman/8.0/en/select.html) 中所述,可以在没有 GROUP BY 子句的情况下使用 HAVING。以下引用自参考手册链接: HAVING 子句指定组的条件,通常由 GROUP BY 子句形成。查询结果仅包括满足 HAVING 条件的组。 (如果不存在 GROUP BY,则所有行都会隐式形成一个聚合组。)
      【解决方案7】:

      1。 我们可以使用带有 HAVING 子句的聚合函数,而不是 WHERE 子句,例如最小值,最大值,平均值。

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

      当你有数据组时使用 HAVING,当你有行中的数据时使用 WHERE。

      【讨论】:

        【解决方案8】:

        WHERE子句用于消除关系中的元组,HAVING子句用于消除关系中的组。

        HAVING 子句用于聚合函数,例如 MIN,MAX,COUNT,SUM 。但始终在 HAVING 子句之前使用 GROUP BY 子句以尽量减少错误。

        【讨论】:

          猜你喜欢
          • 2011-02-23
          • 2010-09-24
          • 2022-01-08
          • 1970-01-01
          • 1970-01-01
          • 2018-12-11
          • 2020-12-25
          • 2021-12-14
          相关资源
          最近更新 更多