COUNT(*)、COUNT(column) 与 COUNT(DISTINCT)
掌握经典问题:每种 COUNT 写法如何处理 NULL 和重复值
COUNT(*)、COUNT(column) 与 COUNT(DISTINCT) 是 CoddyKit 上的免费 Coding Interview Prep 课时。 这是第 1 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Coding Interview Prep 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Coding Interview Prep 课程共包含 4 节课。
您将被问到的问题
如果您参加 SQL 面试,请准备好在前十分钟内回答这个问题:COUNT(*)、COUNT(column) 和 COUNT(DISTINCT column) 有什么区别?
这个问题看似简单,但面试官会借此检查您是否真正理解聚合函数如何处理 NULL 值和重复值。回答自信而准确,说明您编写过实际查询,而不只是记住了语法。
在本课中,我们将建立一个非常扎实的思维模型,让您能够立即回答,并解释其中的原因。
COUNT(*) 统计行数
COUNT(*) 统计行。它完全不会查看任何列值,因此 NULL 与它无关。如果表中有 100 行,COUNT(*) 就返回 100,仅此而已。
这里的星号不是用于乘法,也不是用于展开列。它是一个特殊标记,表示“统计每一行符合条件的行”。当问题只是“有多少条记录?”时,您应当使用这种形式。
SELECT COUNT(*) AS total_rows
FROM employees;用于分析的示例数据
让我们用一张小表来说明所有内容。假设有一张 employees 表,其中包含可为 NULL 的 department 列:
- Alice,销售
- Bob,销售
- Carol,NULL
- Dan,工程
- Eve,NULL
总共有5 行。其中三行有部门值(销售、销售、工程),两行的值为 NULL。请记住这些数字;接下来我们会用三种不同方式统计这张表。
COUNT(column) 跳过 NULL
COUNT(column) 只统计该列不为 NULL 的行。它会完全忽略 NULL 值。
在我们的示例数据中,COUNT(department) 返回3,而不是 5,因为有两个部门值为 NULL。这是整节课中最重要的事实:对列使用 COUNT 时,永远不会统计 NULL。
SELECT COUNT(department) AS depts_present
FROM employees;
-- returns 3 on our sample data目前的两者对比
在同一张包含 5 行的表中并列比较:
COUNT(*)= 5(每一行)COUNT(department)= 3(不为 NULL 的部门)
两者相差 5 减去 3,也就是 NULL 部门的数量。一个实用的面试技巧是:COUNT(*) - COUNT(col) 可以直接得到该列中 NULL 的数量,而无需单独编写 WHERE 子句。
SELECT COUNT(*) - COUNT(department) AS null_departments
FROM employees;
-- returns 2COUNT(DISTINCT 列)
COUNT(DISTINCT column) 统计不重复且不为 NULL 的值的数量。它会先去除重复值,再忽略 NULL,最后统计剩余值。
在我们的数据中,不重复的部门值是销售和工程,因此 COUNT(DISTINCT department) 返回2。两个 NULL 不会被统计,重复的销售也会合并为一个。
SELECT COUNT(DISTINCT department) AS unique_depts
FROM employees;
-- returns 2三者放在一起
这张包含 5 行的表的完整结果如下:
COUNT(*)= 5 — 行COUNT(department)= 3 — 不为 NULL 的值COUNT(DISTINCT department)= 2 — 不重复且不为 NULL 的值
如果您能记住这个顺序:先处理 NULL,再处理重复值,那么就掌握了整个概念。请注意,每种形式返回的值都小于或等于它上方的形式。
SELECT
COUNT(*) AS rows_total,
COUNT(department) AS depts_present,
COUNT(DISTINCT department) AS unique_depts
FROM employees;一道完整的面试变体题
面试官经常会将问题换一种说法:“有多少名员工被分配到了部门?一共有多少个不同的部门?”
前半问对应 COUNT(department)(已分配意味着不为 NULL)。后半问对应 COUNT(DISTINCT department)。能够识别每种表述对应哪个 COUNT,正是这道题要考查的技能。
SELECT
COUNT(department) AS assigned_employees,
COUNT(DISTINCT department) AS distinct_departments
FROM employees;带条件的 COUNT
一个常见的追问是:只统计满足某个条件的行。一种简洁且具有良好可移植性的技巧,是对 CASE 表达式使用 COUNT。由于 COUNT(column) 会跳过 NULL,因此可以让 CASE 对要排除的行返回 NULL。
这里我们统计销售部门的员工。CASE 只对销售行产生值,对其他行返回 NULL,因此 COUNT 只会统计这些行。
SELECT
COUNT(CASE WHEN department = 'Sales' THEN 1 END) AS sales_count
FROM employees;
-- returns 2需要避免的常见错误
请注意面试官可能设置的这些陷阱:
- 认为
COUNT(column)等于COUNT(*)— 只有当该列完全没有 NULL 时,两者才相等。 - 认为
COUNT(DISTINCT col)会将 NULL 作为一个不重复值包含在内 — 实际上不会。 - 编写
COUNT(1)并以为它会跳过 NULL — 它的行为与COUNT(*)一样,会统计所有行。
在面试中主动说明这些情况,可以展示您的理解深度。
COUNT(1) 与 COUNT(常量)
候选人经常会问,COUNT(*) 和 COUNT(1) 哪个更快。答案是:它们在语义上完全相同 — 无论是否存在 NULL,两者都会统计每一行;现代优化器也会以相同方式处理它们,因此没有实际的性能差异。
COUNT(1) 中的常量永远不会是 NULL,因此不会跳过任何行。为了清晰起见,建议使用 COUNT(*);这是更惯用的写法。
SELECT COUNT(*) AS a, COUNT(1) AS b
FROM employees;
-- a and b are always equal快速检查
在示例表上检验您的思维模型。
小结
现在您已经掌握了最常被问到的聚合问题:
COUNT(*)统计每一行,包括 NULL。COUNT(column)只统计不为 NULL 的值。COUNT(DISTINCT column)统计不重复且不为 NULL 的值。COUNT(*) - COUNT(col)可以直接得到 NULL 的数量。COUNT(1)等于COUNT(*)— 不会跳过 NULL,也没有速度差异。
请清晰地说出结论,并说明背后的原因。接下来:SUM 和 AVG 如何处理 NULL。
常见问题解答
「COUNT(*)、COUNT(column) 与 COUNT(DISTINCT)」课时是免费的吗?
是的 — 「COUNT(*)、COUNT(column) 与 COUNT(DISTINCT)」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Coding Interview Prep 课程的其余内容,请升级到 CoddyKit PRO。 Coding Interview Prep 课程共包含 4 节课。
「COUNT(*)、COUNT(column) 与 COUNT(DISTINCT)」这节课中我会学到什么?
掌握经典问题:每种 COUNT 写法如何处理 NULL 和重复值 你通过在浏览器中直接运行的动手代码来练习 Coding Interview Prep,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Coding Interview Prep 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Coding Interview Prep 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 1 节课,共 4 节。
「COUNT(*)、COUNT(column) 与 COUNT(DISTINCT)」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Coding Interview Prep 课中编写并运行代码吗?
能。每节 Coding Interview Prep 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。
此课程中的所有课时
- COUNT(*)、COUNT(column) 与 COUNT(DISTINCT)
- 包含 NULL 的 SUM 和 AVG
- MIN、MAX 与非数值汇总
- 不使用 GROUP BY 的汇总