SQL Academy · 课时

ORDER BY 和聚合中的 CASE

实现条件排序和计数

第 4 / 4 课13 个步骤

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

按自定义优先级排序

SQL 的 ORDER BY 子句通常按列的自然值对行排序。但您可以在 ORDER BY 中嵌入 CASE 表达式,创建完全自定义的排序顺序——这是任何单个列都无法独自实现的顺序。

当优先级由业务规则而非原始数据值决定时,这项技术非常有用。

SELECT product_name, status
FROM products
ORDER BY
  CASE status
    WHEN 'urgent'   THEN 1
    WHEN 'active'   THEN 2
    WHEN 'pending'  THEN 3
    ELSE                 4
  END;

CASE 在 ORDER BY 中的工作方式

数据库计算 ORDER BY CASE ... END 时,会为每一行计算一个整数(或任何可比较的值)。随后,行会按照这个计算出的值排序,而不是按照原始列排序,或者在此基础上进一步排序。

CASE 表达式不会被存储;它只在查询执行期间存在。

SELECT order_id, priority
FROM orders
ORDER BY
  CASE priority
    WHEN 'high'   THEN 1
    WHEN 'medium' THEN 2
    WHEN 'low'    THEN 3
    ELSE               9
  END,
  order_id;

显式排序 NULL

默认情况下,不同数据库会以不同方式将 NULL 放在排序结果的开头或末尾。ORDER BY 中的 CASE 允许您准确决定 NULL 的位置——无论使用哪种数据库引擎。

SELECT employee_name, manager_id
FROM employees
ORDER BY
  CASE WHEN manager_id IS NULL THEN 0 ELSE 1 END,
  manager_id;

条件升序与降序

ORDER BY 中的 CASE 还可以模拟条件排序方向。通过将类别值映射为负数,您可以有效地反转特定分组的排序顺序,同时让其他分组保持正常顺序。

当单个结果集中的不同类型行需要不同的排序逻辑时,这种方法非常有用。

SELECT task_name, due_date, is_overdue
FROM tasks
ORDER BY
  CASE WHEN is_overdue = 1 THEN 0 ELSE 1 END,
  due_date;

COUNT 中的 CASE

您可以在 COUNT 等聚合函数中嵌入 CASE 表达式。诀窍是:对想要计数的行返回非 NULL 值,对想要跳过的行返回 NULL——因为 COUNT 会忽略 NULL。

SELECT
  COUNT(CASE WHEN status = 'active'   THEN 1 END) AS active_count,
  COUNT(CASE WHEN status = 'inactive' THEN 1 END) AS inactive_count
FROM users;

SUM 中的 CASE——条件总计

将 CASE 放入 SUM 中,可以仅在条件为真时累加值,并将不匹配的行视为零。这是透视样式报表中非常常见的模式,可将一个列拆分为多个指标列。

SELECT
  SUM(CASE WHEN region = 'North' THEN sales_amount ELSE 0 END) AS north_total,
  SUM(CASE WHEN region = 'South' THEN sales_amount ELSE 0 END) AS south_total,
  SUM(CASE WHEN region = 'East'  THEN sales_amount ELSE 0 END) AS east_total
FROM sales;

使用 CASE 进行条件 AVG

同样的模式适用于 AVG。由于 AVG 会忽略 NULL,对想要排除的行返回 NULL,就能得到仅包含匹配行的平均值——无需子查询。

SELECT
  AVG(CASE WHEN department = 'Engineering' THEN salary END) AS avg_eng_salary,
  AVG(CASE WHEN department = 'Marketing'   THEN salary END) AS avg_mkt_salary
FROM employees;

使用 CASE 分组——对行进行分桶

您可以在 GROUP BY 或 SELECT 列表中使用 CASE,将连续值分成多个类别,然后对每个分桶进行聚合。这样可以在不更改底层数据的情况下,将数值列转换为带标签的分组。

SELECT
  CASE
    WHEN age < 18             THEN 'Under 18'
    WHEN age BETWEEN 18 AND 35 THEN '18-35'
    WHEN age BETWEEN 36 AND 55 THEN '36-55'
    ELSE                            '56+'
  END AS age_group,
  COUNT(*) AS user_count
FROM users
GROUP BY
  CASE
    WHEN age < 18             THEN 'Under 18'
    WHEN age BETWEEN 18 AND 35 THEN '18-35'
    WHEN age BETWEEN 36 AND 55 THEN '36-55'
    ELSE                            '56+'
  END;

使用别名与重复 CASE 的对比

在 SELECT 和 GROUP BY 中重复冗长的 CASE 表达式会使语句很繁琐。某些数据库(MySQL,以及通过变通方法实现的 PostgreSQL)允许您在 ORDER BY 中引用别名,但不能在 GROUP BY 中引用。最安全、可移植的方法是将查询包装在子查询或 CTE 中,然后在那里按别名执行 GROUP BY。

WITH scored AS (
  SELECT
    customer_id,
    CASE
      WHEN total_spent >= 1000 THEN 'Gold'
      WHEN total_spent >= 500  THEN 'Silver'
      ELSE                          'Bronze'
    END AS tier
  FROM customers
)
SELECT tier, COUNT(*) AS customer_count
FROM scored
GROUP BY tier
ORDER BY
  CASE tier
    WHEN 'Gold'   THEN 1
    WHEN 'Silver' THEN 2
    ELSE               3
  END;

组合使用 ORDER BY CASE 与 ASC / DESC

在 CASE 表达式后,仍然可以追加 ASC 或 DESC,并用逗号分隔添加更多排序列。CASE 得分只是第一个排序键;后续列会按通常方式打破并列。

SELECT
  ticket_id,
  category,
  created_at
FROM support_tickets
ORDER BY
  CASE category
    WHEN 'billing'  THEN 1
    WHEN 'outage'   THEN 2
    WHEN 'feature'  THEN 3
    ELSE                 4
  END ASC,
  created_at ASC;

真实案例——销售仪表板

下面是一个贴近实际的查询,它将基于 CASE 的聚合与基于 CASE 的排序结合起来。该查询会生成按地区汇总的销售摘要,并按收入从高到低排序,使收入最高的地区始终排在最前面,同时将“其他”排到最后。

SELECT
  CASE
    WHEN region IN ('North', 'South', 'East', 'West') THEN region
    ELSE 'Other'
  END AS region_label,
  SUM(CASE WHEN status = 'completed' THEN amount ELSE 0 END) AS completed_sales,
  COUNT(CASE WHEN status = 'refunded' THEN 1 END)           AS refund_count
FROM orders
GROUP BY
  CASE
    WHEN region IN ('North', 'South', 'East', 'West') THEN region
    ELSE 'Other'
  END
ORDER BY completed_sales DESC;

知识检查

检验您对在 ORDER BY 和聚合函数中使用 CASE 的理解。

课程回顾

在本课中,您学习了如何将 CASE 与 ORDER BY 和聚合函数结合使用:

  • ORDER BY 中的 CASE — 为各行分配自定义排序分数,控制 NULL 的显示位置,并在一个查询中组合多条排序规则。
  • COUNT 中的 CASE — 对要包含的行返回非 NULL 值,对要跳过的行隐式或显式地返回 NULL。
  • SUM / AVG 中的 CASE — 使用 0 或 NULL 作为 ELSE 值,在一次遍历中构建条件总计和平均值。
  • GROUP BY 中的 CASE — 将连续值或类别值划分到带标签的分组中,以便进行聚合。

这些模式可以消除许多子查询,让您能够直接使用 SQL 简洁地编写透视表式报表。

免费开始

用 AI 导师学习 SQL — 免费

在浏览器中编写并运行真实代码,获得全天候 AI 导师的即时帮助,并在网页或应用中继续学习。

课程
46
课程
183

常见问题解答

「ORDER BY 和聚合中的 CASE」课时是免费的吗?

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

「ORDER BY 和聚合中的 CASE」这节课中我会学到什么?

实现条件排序和计数 你通过在浏览器中直接运行的动手代码来练习 SQL Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 SQL Academy 需要有经验吗?

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

「ORDER BY 和聚合中的 CASE」课时需要多长时间?

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

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

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

此课程中的所有课时

  1. CASE 表达式
  2. 搜索式 CASE 与简单 CASE
  3. 数据分桶与标注
  4. ORDER BY 和聚合中的 CASE
← 返回 SQL Academy