Mysql 怎么正确使用 WHERE 和 HAVING?

第一个区别是,如果需要通过连接从关联表中获取需要的数据,WHERE 是先筛选后连接,而 HAVING 是先连接后筛选。

这一点,就决定了在关联查询中,WHERE 比 HAVING 更高效。因为 WHERE 可以先筛选,用一个筛选后的较小数据集和关联表进行连接,这样占用的资源比较

少,执行效率也就比较高。HAVING 则需要先把结果集准备好,也就是用未被筛选的数据集进行关联,然后对这个大的数据集进行筛选,这样占用的资源就比较

多,执行效率也较低。

第二个区别是,WHERE 可以直接使用表中的字段作为筛选条件,但不能使用分组中的计算函数作为筛选条件;HAVING 必须要与 GROUP BY 配合使用,可以把分

组计算的函数和分组字段作为筛选条件。

这决定了,在需要对数据进行分组统计的时候,HAVING 可以完成 WHERE 不能完成的任务。这是因为,在查询语法结构中,WHERE 在 GROUP BY 之前,所以

无法对分组结果进行筛选。HAVING 在 GROUP BY 之后,可以使用分组字段和分组中的计算函数,对分组的结果集进行筛选,这个功能是 WHERE 无法完成的。

这么说你可能不太好理解,我来举个小例子。假如超市经营者提出,要查询一下是哪个收银员、在哪天卖了 2 单商品。这种必须先分组才能筛选的查询,用

WHERE 语句实现就比较难,我们可能要分好几步,通过把中间结果存储起来,才能搞定。但是用 HAVING,则很轻松,代码如下:

mysql> SELECT
    ->   a.transdate, c.operatorname
    -> FROM
    ->   demo.transactionhead AS a
    -> JOIN
    ->   demo.transactiondetails AS b ON (a.transactionid = b.transactionid)
    -> JOIN
    ->   demo.operator AS c ON (a.operatorid = c.operatorid)
    -> GROUP BY a.transdate,c.operatorname
    -> HAVING count(*)=2;  -- 销售了2单
+---------------------+--------------+
| transdate           | operatorname |
+---------------------+--------------+
| 2020-12-10 00:00:00 | 张静         |
+---------------------+--------------+
1 row in set (0.01 sec)

我汇总了 WHERE 和 HAVING 各自的优缺点,如下图所示:
在这里插入图片描述
不过,需要注意的是,WHERE 和 HAVING 也不是互相排斥的,我们可以在一个查询里面同时使用 WHERE 和 HAVING。

举个例子,假设现在我们有一组销售数据,包括交易时间、收银员、商品名称、销售数量、价格和销售金额等信息,超市的经营者要查询“2020-12-10”和“2020-

12-11”这两天收银金额超过 100 元的销售日期、收银员名称、销售数量和销售金额。

mysql> SELECT
    ->     a.transdate,
    ->    c.operatorname,
    ->     d.goodsname,
    ->     b.quantity,
    ->     b.price,
    ->     b.salesvalue
    -> FROM
    ->     demo.transactionhead AS a
    ->         JOIN
    ->     demo.transactiondetails AS b ON (a.transactionid = b.transactionid)
    ->        JOIN
    ->     demo.operator AS c ON (a.operatorid = c.operatorid)
    ->        JOIN
    ->    demo.goodsmaster as d on (b.itemnumber=d.itemnumber);
+---------------------+--------------+-----------+----------+-------+------------+
| transdate           | operatorname | goodsname | quantity | price | salesvalue |
+---------------------+--------------+-----------+----------+-------+------------+
| 2020-12-10 00:00:00 | 张静         ||    1.000 | 89.00 |      89.00 |
| 2020-12-10 00:00:00 | 张静         ||    2.000 |  5.00 |      10.00 |
| 2020-12-11 00:00:00 | 李强         ||    2.000 | 89.00 |     178.00 |
| 2020-12-12 00:00:00 | 李强         ||   10.000 |  5.00 |      50.00 |
+---------------------+--------------+-----------+----------+-------+------------+
4 rows in set (0.00 sec)

如果你仔细看 HAVING 后面的筛选条件,就会发现,条件 a.transdate IN (‘2020-12-10’ , ‘2020-12-11’),其实可以用 WHERE 来限定。我们把查询改一下试试:

 mysql> SELECT
    ->     a.transdate,
    ->     c.operatorname,
    ->     SUM(b.quantity),
    ->     SUM(b.salesvalue)
    -> FROM
    ->     demo.transactionhead AS a
    ->         JOIN
    ->     demo.transactiondetails AS b ON (a.transactionid = b.transactionid)
    ->         JOIN
    ->     demo.operator AS c ON (a.operatorid = c.operatorid)
    -> WHERE a.transdate in ('2020-12-12','2020-12-11') -- 先按日期筛选
    -> GROUP BY a.transdate , operatorname
    -> HAVING SUM(b.salesvalue)>100;  -- 后按金额筛选
+---------------------+--------------+-----------------+-------------------+
| transdate           | operatorname | SUM(b.quantity) | SUM(b.salesvalue) |
+---------------------+--------------+-----------------+-------------------+
| 2020-12-11 00:00:00 | 李强         |           2.000 |            178.00 |
+---------------------+--------------+-----------------+-------------------+
1 row in set (0.00 sec)

很显然,我们同样得到了需要的结果。这是因为我们把条件拆分开,包含分组统计函数的条件用 HAVING,普通条件用 WHERE。这样,我们就既利用了 WHERE

条件的高效快速,又发挥了 HAVING 可以使用包含分组统计函数的查询条件的优点。当数据量特别大的时候,运行效率会有很大的差别。

猜你喜欢

转载自blog.csdn.net/fd2025/article/details/125477511