位置:首页 > SQL > SQL 子查询如何统计每个分类的记录数量

SQL 子查询如何统计每个分类的记录数量

时间:2026-08-23  |  作者:冻月看渠  |  阅读:0

必须用 GROUP BY 配合 COUNT() 才能获取每个分类的数量,否则聚合函数会将结果压成单行;优先使用 LEFT JOIN + GROUP BY 而非相关子查询,以确保包含无产品的分类且性能更优。

SQL子查询如何统计每个分类的记录数量

子查询里用 COUNT() 必须配 GROUP BY

直接在子查询中写 COUNT(*) 却不加 GROUP BY,数据库会报错或返回单行结果(比如所有分类共几条),根本得不到“每个分类的数量”。这是因为聚合函数默认把整个结果集压成一行,必须明确告诉它按哪个字段分组。

常见的错误写法有:SELECT name, (SELECT COUNT(*) FROM products WHERE category_id = c.id) FROM categories c。这种写法虽然能运行,但属于相关子查询,性能较差。还有一种错误写法是:SELECT (SELECT COUNT(*) FROM products) FROM categories,这种写法完全没有分组逻辑,属于误用。

  • 真正要“每个分类数量”,优先考虑 JOIN + GROUP BY,不是非用子查询
  • 若坚持用子查询,得是相关子查询:外层每扫一条分类,内层算一次对应产品的数量
  • MySQL 8.0+、PostgreSQL 支持在 SELECT 子句里直接放聚合子查询,但 SQLite 不支持

用 LEFT JOIN 配合 GROUP BY 更稳更快

比起嵌套子查询,LEFT JOIN 能一次拉出所有分类和它们的产品数,包括那些没有产品的分类(数量为 0)。子查询方式默认丢掉空分类,除非你额外补 COALESCEUNION,徒增复杂度。

实操示例:

SELECT c.name, COUNT(p.id) AS product_count
FROM categories c
LEFT JOIN products p ON c.id = p.category_id
GROUP BY c.id, c.name;
  • COUNT(p.id) 统计非 NULL 的产品 ID,自动跳过无匹配的分类行(LEFT JOINp.id 为 NULL)
  • 务必在 GROUP BY 中包含 c.id,否则 PostgreSQL 会报错,MySQL 在严格模式下也会
  • 别用 COUNT(*),它会把 NULL 行也当一行计,导致空分类显示为 1

相关子查询写法及性能隐患

如果业务强制要求用子查询(比如报表工具只允许单层 SELECT),那就得用相关子查询。语法上没问题,但执行时数据库会对每条外层记录重复执行一次内层查询,数据量一大就明显变慢。

正确写法:

SELECT c.name,
(SELECT COUNT(*) FROM products p WHERE p.category_id = c.id) AS product_count
FROM categories c;
  • 子查询里的 WHERE 条件必须关联外层表,如 p.category_id = c.id
  • 确保 products.category_id 有索引,否则每次子查询都是全表扫描
  • MySQL 5.7 默认可能不走索引,建议升级到 8.0 或显式加 FORCE INDEX

NULL 分类和空字符串分类容易被漏统计

实际数据里常有 category_id IS NULLcategory_name = '' 的脏数据。用 JOIN 时这些记录不会出现在结果里;用相关子查询时,它们会被归到“找不到分类”的情况,数量为 0,但不会单独列出来。

  • 若需统计 NULL 分类,得单独加一句:SELECT 'Uncategorized', COUNT(*) FROM products WHERE category_id IS NULL
  • 空字符串分类建议先清洗:UPDATE products SET category_id = NULL WHERE category_id = ''
  • 别依赖子查询自动覆盖边界情况——它只响应你写的条件,不会替你猜业务含义

免责声明:文中图文均来自网络,如有侵权请联系删除,心愿游戏发布此文仅为传递信息,不代表心愿游戏认同其观点或证实其描述。

相关文章

更多

精选合集

更多

大家都在玩

热门话题

大家都在看

更多