0Pricing
SQL Academy · 课时

聚合和连接中的 NULL

了解 NULL 在 COUNT、SUM 和 JOIN 中的行为

聚合和连接中的 NULL 是 CoddyKit 上的免费 SQL Academy 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 SQL Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 SQL Academy 课程共包含 4 节课。

NULL 值会改变计算结果

聚合函数和连接都会以特殊方式处理 NULL。如果不了解这些规则,您的总数和计数可能会在不知不觉中出错。

本课将展示 COUNT、SUM、AVG、GROUP BY 和外连接如何共同处理缺失值。

SELECT amount FROM payments;
-- amount
-- -------
--    100
--   NULL   <- missing
--    200

聚合函数会忽略 NULL

大多数聚合函数 — SUM、AVG、MIN、MAX — 都会直接跳过 NULL 值。它们只对有数据的行进行聚合。

因此,NULL 金额不会破坏 SUM;它只会被排除在总数之外。

-- Using amounts 100, NULL, 200
SELECT
  SUM(amount) AS total,  -- 300 (NULL skipped)
  MIN(amount) AS lo,     -- 100
  MAX(amount) AS hi      -- 200
FROM payments;

AVG 同样会跳过 NULL

AVG 会用非 NULL 值的总和除以非 NULL 值的数量。NULL 会同时从两者中排除。

这一点很重要:{100, NULL, 200} 的平均值是 150,而不是 100 — NULL 不会被当作零计入。

-- (100 + 200) / 2 = 150, the NULL row is ignored
SELECT AVG(amount) AS avg_amount FROM payments;

-- If you WANT NULLs counted as 0, COALESCE first:
SELECT AVG(COALESCE(amount, 0)) AS avg_with_zeros FROM payments; -- 100

COUNT(*) 与 COUNT(column)

这一点常让许多人困惑:

  • COUNT(*) 统计行数,包括含有 NULL 的行。
  • COUNT(column) 只统计该列不为 NULL 的行。
-- 3 rows total, but only 2 have a non-NULL amount
SELECT
  COUNT(*)       AS row_count,    -- 3
  COUNT(amount)  AS has_amount    -- 2
FROM payments;

COUNT(DISTINCT) 与 NULL

COUNT(DISTINCT col) 统计不同非 NULL 值的数量。NULL 会被完全排除 — 不会增加不同值的计数。

当您统计“有多少个不同的 X”时,请牢记这一点。

-- statuses: 'paid', NULL, 'paid', 'void'
SELECT COUNT(DISTINCT status) AS distinct_statuses
FROM payments;
-- 2  (paid, void) -- NULL not counted

空集合上的聚合

当聚合函数作用于零行时,结果取决于函数:

  • COUNT(...) 返回 0。
  • SUM、AVG、MIN、MAX 返回 NULL。

适当时,可以使用 COALESCE 将 NULL 总和转换为 0。

-- No rows match -> SUM is NULL, not 0
SELECT COALESCE(SUM(amount), 0) AS total
FROM payments
WHERE status = 'refunded';  -- no such rows

GROUP BY 会将 NULL 归为一组

虽然在其他地方 NULL = NULL 的结果是未知,但 GROUP BY 会将所有 NULL 归入同一组。

因此,NULL 类别会在结果中成为自己的分组,让您可以将缺失数据的行汇总在一起。

SELECT category, COUNT(*) AS n
FROM products
GROUP BY category;

-- category | n
-- ---------+---
-- books    | 5
-- toys     | 3
-- NULL     | 2   <- all NULL categories in one group

外连接产生的 NULL

外连接是 NULL 的重要来源。LEFT JOIN 会保留左侧的每一行;如果右侧没有匹配项,右侧列就会变为 NULL。

这些 NULL 表示“没有匹配的行”,而不是“存储的 NULL 值”。

SELECT c.name, o.id AS order_id
FROM customers c
LEFT JOIN orders o ON o.customer_id = c.id;

-- name  | order_id
-- ------+---------
-- Alice | 10
-- Bob   | NULL     <- Bob has no orders

统计 LEFT JOIN 后的匹配项

要在 LEFT JOIN 后只统计真正的匹配项,请统计右表中的一个非 NULL 列,而不是 COUNT(*)。

COUNT(o.id) 会忽略左表未匹配行产生的 NULL 行,从而给出真实的订单数量。

SELECT c.name, COUNT(o.id) AS order_count
FROM customers c
LEFT JOIN orders o ON o.customer_id = c.id
GROUP BY c.name;

-- Bob shows 0, not 1×NULL

筛除不匹配项

有一个容易忽略的陷阱:在 LEFT JOIN 之后将右表条件放入 WHERE,会使其变成内连接,因为 NULL = 值 的结果是未知,因而会被筛除。

如果您希望保留不匹配的行,请将条件放入 ON 子句,或明确检查 NULL。

-- Accidentally drops Bob (his o.status is NULL)
SELECT c.name FROM customers c
LEFT JOIN orders o ON o.customer_id = c.id
WHERE o.status = 'open';

-- Keep unmatched rows: move the test into ON
SELECT c.name FROM customers c
LEFT JOIN orders o ON o.customer_id = c.id AND o.status = 'open';

经验法则

将以下规则应用到每个聚合与连接查询中:

  • 聚合函数会忽略 NULL(COUNT(*) 除外)。
  • 当 col 含有 NULL 时,COUNT(col) < COUNT(*)。
  • 空集合上的 SUM/AVG 为 NULL — 请使用 COALESCE 包裹它们。
  • LEFT JOIN 会为不匹配项生成 NULL;请统计右侧的键。
  • 右表筛选条件应放在 ON 中,而不是 WHERE 中。
SELECT c.name,
  COALESCE(SUM(o.amount), 0) AS spent,
  COUNT(o.id)                AS orders
FROM customers c
LEFT JOIN orders o ON o.customer_id = c.id
GROUP BY c.name;

快速检查

某列 amount 在三行中分别有值 100、NULL 和 200。COUNT(*) 和 COUNT(amount) 会分别返回什么?

回顾

您了解了 NULL 在聚合和连接中的传递方式:聚合函数会跳过 NULL,COUNT(*) 统计行数而 COUNT(col) 统计非 NULL 值,空集合上的总和为 NULL,而 GROUP BY 会将 NULL 归入一组。

您还了解了外连接会为不匹配项生成 NULL,以及为什么右表筛选条件应放在 ON 中。这就完成了处理 NULL 值课程 — 现在,您已经能够自信地处理缺失数据。

-- A NULL-safe summary query
SELECT c.name,
  COUNT(o.id)                AS orders,
  COALESCE(SUM(o.amount), 0) AS total_spent
FROM customers c
LEFT JOIN orders o ON o.customer_id = c.id
GROUP BY c.name
ORDER BY total_spent DESC;

常见问题解答

「聚合和连接中的 NULL」课时是免费的吗?

是的 — 「聚合和连接中的 NULL」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 SQL Academy 课程的其余内容,请升级到 CoddyKit PRO。 SQL Academy 课程共包含 4 节课。

「聚合和连接中的 NULL」这节课中我会学到什么?

了解 NULL 在 COUNT、SUM 和 JOIN 中的行为 你通过在浏览器中直接运行的动手代码来练习 SQL Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 SQL Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 SQL Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。

「聚合和连接中的 NULL」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 SQL Academy 课中编写并运行代码吗?

能。每节 SQL Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. NULL 的真正含义
  2. IS NULL 与 IS NOT NULL
  3. COALESCE 与 NULLIF
  4. 聚合和连接中的 NULL
← 返回 SQL Academy