SQL HAVING

时间:2018-11-15 17:45:26  来源:igfitidea点击:

在本教程中,我们将学习如何使用SQL HAVING子句为一组行或聚合指定搜索条件。

SQL HAVING子句介绍

HAVING子句通常与SELECT语句中的GROUP BY子句一起使用,用于根据指定的条件筛选行组。

下面是HAVING子句的语法:

SELECT 
    column1, column2, aggregate_function(expr)
FROM
    table
GROUP BY column1
HAVING condition;

如果HAVING子句没有与GROUP BY子句一起使用,那么它的工作原理与WHERE子句类似。
HAVING子句和WHERE子句的区别在于WHERE子句用于过滤行,而HAVING子句用于过滤行组。

使用SUM函数的SQL HAVING 例子

在这个例子中,我们将查找销售订单的总销售额大于$10000的。我们使用与GROUP BY子句的HAVING子句来完成如下查询:

SELECT 
    orderid, SUM(unitPrice * quantity) Total
FROM
    orderdetails
GROUP BY orderid
HAVING total > 10000;

数据库引擎将执行下面的操作:
首先,对于每个订单行,SQL使用SUM函数计算总金额。(列别名Total用于格式化输出)。
其次,GROUP BY子句根据orderid对所选行进行分组。对于每个订单,我们只有一个包含OrderID和Total的组
第三,HAVING子句获取总数大于10000的组。

使用COUNT函数的SQL HAVING 例子

下面的查询选择至少包含5项产品的所有订单。我们将COUNT函数与HAVING和GROUP BY子句一起使用。

SELECT 
    orderID, COUNT(productID) products
FROM
    orderdetails
GROUP BY orderID
HAVING products > 5;

使用MAX和MIN函数的SQL HAVING 例子

请看下面的产品表:

要选择每个类别中最贵的产品,可以使用以下查询:

SELECT 
    categoryID, productID, productName, MAX(unitprice)
FROM
    products A
WHERE
    unitprice = (
 SELECT 
            MAX(unitprice)
        FROM
            products B
        WHERE
            B.categoryId = A.categoryID)
GROUP BY categoryID;

请注意,语句的WHERE子句中使用了子查询,以便在外部查询中获得正确的结果。

如果出现下面的报错

[Err] 1055 - Expression #2 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'jpetstore.A.ProductID' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by

这是因为 如果启用了ONLY_FULL_GROUP_BY SQL模式(默认情况下为该模式),MySQL将拒绝select list、HAVING condition或ORDER BY list引用未聚合列的查询,这些列既不在groupby子句中命名,也不在功能上依赖于这些列。
详细请查看https://dev.mysql.com/doc/refman/5.7/en/sql-mode.html

解决方法有两种:

  1. 修改 sql_mode
SET GLOBAL sql_mode=(SELECT REPLACE(@@sql_mode,'ONLY_FULL_GROUP_BY',''));

SELECT 
    categoryID, productID, productName, MAX(unitprice)
FROM
    products A
WHERE
    unitprice = (
 SELECT 
            MAX(unitprice)
        FROM
            products B
        WHERE
            B.categoryId = A.categoryID)
GROUP BY categoryID;

  1. 不要选择未聚合的列
SELECT 
    categoryID, MAX(unitprice)
FROM
    products A
WHERE
    unitprice = (
 SELECT 
            MAX(unitprice)
        FROM
            products B
        WHERE
            B.categoryId = A.categoryID)
GROUP BY categoryID;

对于每个类别,要选择价格大于120元的最贵产品,可以使用HAVING子句中的MAX函数,如下所示:

SELECT 
    categoryID, productID, productName, MAX(unitprice)
FROM
    products A
WHERE
    unitprice = (
        SELECT 
            MAX(unitprice)
        FROM
            products B
        WHERE
            B.categoryId = A.categoryID)
GROUP BY categoryID
HAVING MAX(unitprice) > 120;

要选择在每一类中最便宜的产品,我们可以使用MIN函数替换MAX函数:

SELECT 
    categoryID, productID, productName, MIN(unitprice)
FROM
    products A
WHERE
    unitprice = (
        SELECT 
            MIN(unitprice)
        FROM
            products B
        WHERE
            B.categoryId = A.categoryID)
GROUP BY categoryID

使用HAVING子句中的MIN函数,我们可以找到单价低于5元并且在每一类中最便宜的产品,如下所示:

SELECT 
    categoryID, productID, productName, MIN(unitprice)
FROM
    products A
WHERE
    unitprice = (
        SELECT 
            MIN(unitprice)
        FROM
            products B
        WHERE
            B.categoryId = A.categoryID)
GROUP BY categoryID
HAVING MIN(unitprice) < 5;