【发布时间】:2011-02-23 17:16:37
【问题描述】:
在 MySQL 中,为什么需要将自己创建的列(例如 select 1 as "number")放在 HAVING 之后而不是 WHERE 之后?
除了WHERE 1(写整个定义而不是列名)还有什么缺点吗?
【问题讨论】:
标签: mysql sql where-clause having-clause
在 MySQL 中,为什么需要将自己创建的列(例如 select 1 as "number")放在 HAVING 之后而不是 WHERE 之后?
除了WHERE 1(写整个定义而不是列名)还有什么缺点吗?
【问题讨论】:
标签: mysql sql where-clause having-clause
关于这个问题的所有其他答案都没有触及关键点。
假设我们有一张桌子:
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 |
+----+-------------+-------+-------+---------------+-------+---------+------+------+-------------+
您可以看到WHERE 或HAVING 使用索引,但行不同。
【讨论】:
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
WHERE 在数据分组前过滤,HAVING 在数据分组后过滤。这是一个重要的区别;是的行 被 WHERE 子句消除的将不包含在组中。这 可以改变计算值,反过来(=作为结果)可能会影响 根据 HAVING 中这些值的使用情况过滤组 子句。
然后继续,
HAVING 与 WHERE 非常相似,以至于大多数 DBMS 将它们视为相同 如果没有指定 GROUP BY 的话。不过,你应该这样做 区分自己。 HAVING 仅与 GROUP BY 一起使用 条款。使用 WHERE 进行标准行级过滤。
摘自: Forta, Ben. “Sams Teach Yourself SQL in 10 Minutes (5th Edition) (Sams Teach Yourself...).”.
【讨论】:
Having 仅与聚合一起使用,而 where 与非聚合语句一起使用 如果你有 where 词放在聚合之前(分组)
【讨论】:
这两个感觉和第一个一样,因为它们都用来表示过滤数据的条件。尽管在任何情况下我们都可以使用“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.*/
【讨论】:
WHERE和HAVING之间的区别。
HAVING 用于过滤 GROUP BY 中的聚合。
例如,检查重复名称:
SELECT Name FROM Usernames
GROUP BY Name
HAVING COUNT(*) > 1
【讨论】:
主要区别在于WHERE 不能用于分组项目(例如SUM(number)),而HAVING 可以。
原因是WHERE 在分组完成之前 完成,而HAVING 在分组完成之后完成。
【讨论】:
为什么您需要将自己创建的列(例如“选择 1 作为数字”)放在 HAVING 之后而不是 MySQL 中的 WHERE 之后?
WHERE 在GROUP BY 之前应用,HAVING 在之后应用(并且可以过滤聚合)。
一般来说,您不能在这两个子句中引用别名,但MySQL 允许在GROUP BY、ORDER BY 和HAVING 中引用SELECT 级别名。
除了执行“WHERE 1”(写整个定义而不是列名)之外,还有什么缺点吗
如果您的计算表达式不包含任何聚合,将其放入WHERE 子句很可能会更有效。
【讨论】: