【问题标题】:WHERE vs HAVING在哪里与拥有
【发布时间】:2011-02-23 17:16:37
【问题描述】:

在 MySQL 中,为什么需要将自己创建的列(例如 select 1 as "number")放在 HAVING 之后而不是 WHERE 之后?

除了WHERE 1(写整个定义而不是列名)还有什么缺点吗?

【问题讨论】:

    标签: mysql sql where-clause having-clause


    【解决方案1】:

    关于这个问题的所有其他答案都没有触及关键点。

    假设我们有一张桌子:

    CREATE TABLE `table` (
     `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
     `value` int(10) unsigned NOT NULL,
     PRIMARY KEY (`id`),
     KEY `value` (`value`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8
    

    并且有 10 行 id 和 value 从 1 到 10:

    INSERT INTO `table`(`id`, `value`) VALUES (1, 1),(2, 2),(3, 3),(4, 4),(5, 5),(6, 6),(7, 7),(8, 8),(9, 9),(10, 10);
    

    尝试以下 2 个查询:

    SELECT `value` v FROM `table` WHERE `value`>5; -- Get 5 rows
    SELECT `value` v FROM `table` HAVING `value`>5; -- Get 5 rows
    

    你会得到完全相同的结果,你可以看到HAVING 子句可以在没有 GROUP BY 子句的情况下工作。


    这就是区别:

    SELECT `value` v FROM `table` WHERE `v`>5;
    

    上述查询将引发错误:错误 #1054 - 'where 子句'中的未知列 'v'

    SELECT `value` v FROM `table` HAVING `v`>5; -- Get 5 rows
    

    WHERE 子句允许条件使用任何表列,但不能使用别名或聚合函数。 HAVING 子句允许条件使用选定 (!) 列、别名或聚合函数。

    这是因为WHERE 子句在选择之前过滤数据,而HAVING 子句在选择之后过滤结果数据。

    因此,如果表中有很多行,则将条件放在WHERE 子句中会更有效。

    试试EXPLAIN看看关键区别:

    EXPLAIN SELECT `value` v FROM `table` WHERE `value`>5;
    +----+-------------+-------+-------+---------------+-------+---------+------+------+--------------------------+
    | id | select_type | table | type  | possible_keys | key   | key_len | ref  | rows | Extra                    |
    +----+-------------+-------+-------+---------------+-------+---------+------+------+--------------------------+
    |  1 | SIMPLE      | table | range | value         | value | 4       | NULL |    5 | Using where; Using index |
    +----+-------------+-------+-------+---------------+-------+---------+------+------+--------------------------+
    
    EXPLAIN SELECT `value` v FROM `table` having `value`>5;
    +----+-------------+-------+-------+---------------+-------+---------+------+------+-------------+
    | id | select_type | table | type  | possible_keys | key   | key_len | ref  | rows | Extra       |
    +----+-------------+-------+-------+---------------+-------+---------+------+------+-------------+
    |  1 | SIMPLE      | table | index | NULL          | value | 4       | NULL |   10 | Using index |
    +----+-------------+-------+-------+---------------+-------+---------+------+------+-------------+
    

    您可以看到WHEREHAVING 使用索引,但行不同。

    【讨论】:

    • 感谢您提到 EXPLAIN!
    • 因为 HAVING 子句在 select 之后过滤数据,所以 WHERE 子句会更有效。所以如果这是真的,我们什么时候必须使用 HAVING 而不是 WHERE?
    • @grep 如果要在 select 后过滤数据,则需要 HAVING 子句,通常我们将其与 GROUP BY 子句一起使用,例如:SELECT value, COUNT(*) frequency FROM table GROUP BY value HAVING frequency > 10
    • 优秀的帖子。一些建议的澄清:将...HAVING clause can use both column and alias.更改为...HAVING clause can use either column or alias.并将...WHERE clause will be more effective更改为...WHERE clause will be more efficient
    • HAVING 子句被添加到 SQL 中,因为 WHERE 关键字不能与聚合函数一起使用。
    【解决方案2】:

    WHERE 在数据分组前过滤,HAVING 在数据分组后过滤。这是一个重要的区别;是的行 被 WHERE 子句消除的将不包含在组中。这 可以改变计算值,反过来(=作为结果)可能会影响 根据 HAVING 中这些值的使用情况过滤组 子句。

    然后继续,

    HAVINGWHERE 非常相似,以至于大多数 DBMS 将它们视为相同 如果没有指定 GROUP BY 的话。不过,你应该这样做 区分自己。 HAVING 仅与 GROUP BY 一起使用 条款。使用 WHERE 进行标准行级过滤。

    摘自: Forta, Ben. “Sams Teach Yourself SQL in 10 Minutes (5th Edition) (Sams Teach Yourself...).”.

    【讨论】:

      【解决方案3】:

      Having 仅与聚合一起使用,而 where 与非聚合语句一起使用 如果你有 where 词放在聚合之前(分组)

      【讨论】:

        【解决方案4】:

        这两个感觉和第一个一样,因为它们都用来表示过滤数据的条件。尽管在任何情况下我们都可以使用“have”代替“where”,但有些情况下我们不能使用“where”代替“have”。这是因为在选择查询中,“where”在“select”之前过滤数据,而“have”在“select”之后过滤数据。因此,当我们使用实际上不在数据库中的别名时,“where”无法识别它们,但“have”可以。

        例如:让表 Student 包含 student_id,name,birthday,address。假设生日是 date 类型。

        SELECT * FROM Student WHERE YEAR(birthday)>1993; /*this will work as birthday is in database.if we use having in place of where too this will work*/
        
        SELECT student_id,(YEAR(CurDate())-YEAR(birthday)) AS Age FROM Student HAVING Age>20; 
        /*this will not work if we use ‘where’ here, ‘where’ don’t know about age as age is defined in select part.*/
        

        【讨论】:

        • 这个真实的例子充分阐明了WHEREHAVING之间的区别。
        • 清楚地显示了Have 和where 之间的区别。谢谢。
        【解决方案5】:

        HAVING 用于过滤 GROUP BY 中的聚合。

        例如,检查重复名称:

        SELECT Name FROM Usernames
        GROUP BY Name
        HAVING COUNT(*) > 1
        

        【讨论】:

        【解决方案6】:

        主要区别在于WHERE 不能用于分组项目(例如SUM(number)),而HAVING 可以。

        原因是WHERE 在分组完成之前 完成,而HAVING 在分组完成之后完成。

        【讨论】:

          【解决方案7】:

          为什么您需要将自己创建的列(例如“选择 1 作为数字”)放在 HAVING 之后而不是 MySQL 中的 WHERE 之后?

          WHEREGROUP BY 之前应用,HAVING 在之后应用(并且可以过滤聚合)。

          一般来说,您不能在这两个子句中引用别名,但MySQL 允许在GROUP BYORDER BYHAVING 中引用SELECT 级别名。

          除了执行“WHERE 1”(写整个定义而不是列名)之外,还有什么缺点吗

          如果您的计算表达式不包含任何聚合,将其放入WHERE 子句很可能会更有效。

          【讨论】:

            猜你喜欢
            • 2012-03-04
            • 2010-09-24
            • 2022-01-08
            • 1970-01-01
            • 2018-12-11
            • 2011-01-19
            • 2011-05-20
            • 1970-01-01
            相关资源
            最近更新 更多