Skip to content

SQLite - HAVING 子句

HAVING 子句与 GROUP BY 子句结合使用,用于筛选聚合函数的结果。它作用类似于 WHERE 子句,但针对的是组而不是单个行。

这是一个常见的混淆点。关键区别在于查询中的操作顺序:

  • WHERE 子句在行被分组之前进行筛选。它作用于单个行数据。
  • HAVING 子句在组通过 GROUP BY 创建之后进行筛选。它作用于聚合函数(如 COUNT()、SUM()、AVG())的结果。

HAVING 子句必须出现在 GROUP BY 子句之后,以及任何 ORDER BY 子句之前。

SELECT
column_name(s),
aggregate_function(column_name)
FROM table_name
WHERE [ 单个行条件 ]
GROUP BY column_name(s)
HAVING [ 基于聚合函数的组条件 ]
ORDER BY column_name(s);

让我们考虑一个 products 表,其中包含以下记录:

CREATE TABLE products (
id INTEGER PRIMARY KEY,
name TEXT,
category TEXT,
price REAL,
stock_quantity INTEGER
);
INSERT INTO products (name, category, price, stock_quantity) VALUES
('Laptop', 'Electronics', 1200.00, 10),
('Mouse', 'Electronics', 25.00, 150),
('Keyboard', 'Electronics', 75.00, 70),
('Desk Chair', 'Furniture', 150.00, 30),
('Coffee Table', 'Furniture', 220.00, 15),
('T-Shirt', 'Apparel', 20.00, 200),
('Jeans', 'Apparel', 60.00, 80);

问题:查找产品数量超过一个的类别。

Section titled “问题:查找产品数量超过一个的类别。”

我们需要按 category 分组,然后计算每个组中的产品数量。最后,筛选这些组,只保留数量大于 1 的组。

SELECT
category,
COUNT(id) AS product_count
FROM products
GROUP BY category
HAVING COUNT(id) > 1;

这将产生以下结果:

category product_count
----------- -------------
Apparel 2
Electronics 3
Furniture 2

问题:查找产品平均价格超过 100 美元的类别。

Section titled “问题:查找产品平均价格超过 100 美元的类别。”

在这里,我们按 category 分组,计算每个类别的平均价格,然后使用 HAVING 根据该平均价格进行筛选。

SELECT
category,
AVG(price) AS average_price
FROM products
GROUP BY category
HAVING AVG(price) > 100.00;

这将产生以下结果:

category average_price
----------- ----------------
Electronics 433.333333333333
Furniture 185.0

让我们查找产品平均价格(成本超过 50 美元)超过 100 美元的类别。

SELECT
category,
AVG(price) as average_price
FROM products
WHERE price > 50.00 -- 首先筛选单个行
GROUP BY category
HAVING AVG(price) > 100.00; -- 在聚合后筛选组

此查询首先从计算中排除 ‘Mouse’ 和 ‘T-Shirt’,然后对组进行分组和筛选。

category average_price
----------- ----------------
Electronics 637.5
Furniture 185.0

将 WHERE 用于聚合函数: 以下查询将失败,因为 WHERE 无法对 COUNT() 的结果进行操作。

-- 不正确
SELECT category, COUNT(id)
FROM products
GROUP BY category
WHERE COUNT(id) > 1; -- 错误!

将 HAVING 用于非聚合条件: 尽管有些数据库允许这样做,但这是一种不好的做法,效率也较低。请使用 WHERE 筛选单个行。

-- 效率低下(尽管在 SQLite 中可能有效)
SELECT category, AVG(price)
FROM products
GROUP BY category
HAVING category = 'Electronics';
-- 正确且高效
SELECT category, AVG(price)
FROM products
WHERE category = 'Electronics'
GROUP BY category;