260

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

并且有什么缺点而不是做WHERE 1(写整个定义而不是列名)?

4

7 回答 7

334

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

WHERE在之前应用GROUP BYHAVING在之后应用(并且可以过滤聚合)。

通常,您不能在这两个子句中引用别名,但允许MySQL在和中引用SELECT级别别名。GROUP BYORDER BYHAVING

并且有什么缺点而不是做“WHERE 1”(写整个定义而不是列名)

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

于 2010-05-25T13:59:45.857 回答
324

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

假设我们有一张桌子:

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使用索引,但行不同。

于 2013-09-10T04:30:35.897 回答
65

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

原因是分组WHERE完成,分组完成完成。HAVING

于 2010-05-25T14:00:56.443 回答
41

HAVING用于过滤GROUP BY.

例如,要检查重复名称:

SELECT Name FROM Usernames
GROUP BY Name
HAVING COUNT(*) > 1
于 2010-05-25T14:01:56.590 回答
10

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

例如:让表学生包含学生ID、姓名、生日、地址。假设生日是日期类型。

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.*/
于 2015-06-21T12:03:43.283 回答
3

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

并继续,

HAVING与WHERE非常相似,以至于如果没有指定GROUP BY,大多数 DBMS 将它们视为同一事物。不过,您应该自己做出区分。仅将HAVINGGROUP BY 子句结合使用。使用WHERE进行标准行级过滤。

摘自: 福尔塔,本。“Sams 在 10 分钟内自学 SQL(第 5 版)(Sams 自学……)。”。

于 2018-01-05T11:56:50.467 回答
1

仅与聚合一起使用,但与非聚合语句一起使用如果你有 where 单词将它放在聚合之前(分组依据)

于 2015-11-09T19:22:17.307 回答