文中涉及的数据表见文章:SQL DML 语句简介
HAVING
是针对查询得到的结果集进行进一步的过滤筛选。因此:HAVING
条件涉及的列一定是在 SELECT
临时结果集中出现的列。
注意:如果 SELECT
的列使用了 AS
命名了别名,那么 HAVING
做筛选时候也需要使用别名!
以商品表-goods
表为例,要求:查询 goods
表中商品比市场价低出至少 200 的商品。如下:
- 结合列是变量,可以进行计算,查询
goods
表中商品比市场价低出多少?
SELECT goods_id, goods_name, (market_price - shop_price) as diff_price FROM `goods` WHERE market_price > shop_price;
注意:MySQL 8
的数据库模式默认是严格模式,若计算列及其结果超出了列类型所定义的数据类型范围,会报错:(1690, "XXX value is out of range in 'xxxx'
,详细可阅读官方文档:《11.1.7 Out-of-Range and Overflow Handling》。
测试表 goods
中,market_price
和 shop_price
都是非负小数:DECIMAL UNSIGNED
,而 (market_price - shop_price)
可能会出现负数,因此在数据库严格模式下这个运算可能会出现报错,如下图:
解决方法有如下几种:
-
在查询时候需要加上 ` WHERE market_price > shop_price` 确保计算结果范围正确!(推荐:养成书写严格模式的 SQL 是一个好习惯,兼容性也比较高)
-
给
sql_mode
增加设置NO_UNSIGNED_SUBTRACTION
,允许计算结果与计算列数据类型不同
- 通过
CAST()
函数改变计算列的取值范围
SELECT goods_id, goods_name, (CAST(market_price as SIGNED) - CAST(shop_price AS SIGNED)) AS diff_price FROM `goods`;
- 查询
goods
表中商品比市场价低出至少 200 的商品?
- 利用
WHERE
子句实现:
SELECT goods_id, goods_name, (market_price - shop_price) as diff_price FROM `goods` WHERE market_price > shop_price and (market_price - shop_price) >= 200;
- 利用
HAVING
子句实现:
SELECT goods_id, goods_name, (market_price - shop_price) as diff_price FROM `goods` WHERE market_price > shop_price HAVING diff_price >= 200;
!!!注意:如果同时写了 WHERE
和 HAVING
子句, WHERE
子句一定要写在 HAVING
子句前面,因为:WHERE
子句针对的是磁盘中的数据集进行过滤筛选,而 HAVING
子句是针对 WHERE
子句查询放到内存中的临时结果集来操作的!