多列排序与 NULL 位置
了解 ASC/DESC 混用,以及不同数据库中 NULLS FIRST/LAST 的差异
多列排序与 NULL 位置 是 CoddyKit 上的免费 Coding Interview Prep 课时。 这是第 1 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Coding Interview Prep 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Coding Interview Prep 课程共包含 4 节课。
为什么排序会出现在面试中
面试官往往很早就会问到 ORDER BY,因为这能体现您是否理解 SQL 结果集默认是无序的。如果没有明确的排序,数据库可以按照任意顺序返回行。
一个常见的开场问题是:“如何保证返回的行按照特定顺序排列?”唯一正确的答案是使用明确的 ORDER BY 子句。依赖插入顺序、主键顺序或索引顺序,是初级开发者常犯的错误。
在本课中,您将掌握多列排序,以及 NULL 值会排在哪里这一棘手问题。
ASC 和 DESC 基础
ORDER BY 默认按升序(ASC)排序。只有需要反转顺序时才需要使用 DESC。排序方向是逐列生效的,而不是作用于整个子句。
面试提示:请说明 ASC 是隐式默认值,因此不必显式写出。许多候选人会错误地认为,一个 DESC 就会让所有列反转。
SELECT name, hire_date
FROM employees
ORDER BY hire_date DESC;按多列排序
将多个列名用逗号分隔。SQL 会先按第一列排序,然后用第二列打破并列,以此类推。您可以把它理解为一条逐级决胜链。
下面的示例先按部门名称的字母顺序排序,然后在每个部门内按薪资从高到低排序。
- 主要排序:
department升序 - 决胜排序:
salary降序
SELECT department, name, salary
FROM employees
ORDER BY department ASC, salary DESC;混合使用 ASC 和 DESC
这是面试中常见的陷阱:每一列都有自己的排序方向。写成 ORDER BY a, b DESC 时,a 按升序排列,b 按降序排列,而不是两列都按降序排列。
如果希望两列都按降序排列,必须写成 ORDER BY a DESC, b DESC。当题目混合要求不同排序方向时,请明确写出每一列的方向。
SELECT region, sales_year, revenue
FROM sales
ORDER BY region ASC, sales_year DESC;NULL 会排在哪里
这是本课的核心。NULL 表示未知,因此标准没有强制规定其位置,而且不同数据库的默认行为并不一致:
- PostgreSQL & Oracle:NULL 值在
ASC中排在最后,在DESC中排在最前。 - MySQL & SQL Server:NULL 值在
ASC中排在最前,在DESC中排在最后(被视为最小值)。
面试官很喜欢问:“NULL 会出现在这个排序的什么位置?”诚实的回答是:这取决于数据库引擎,除非您明确控制排序方式。
明确控制 NULL 的位置
若要不受数据库引擎默认行为影响,确定 NULL 的位置,请使用 NULLS FIRST 或 NULLS LAST。PostgreSQL、Oracle 和 SQLite 都直接支持这种写法。
下面的查询会强制让未知的入职日期排在底部,即使该列本身按升序排列。
SELECT name, hire_date
FROM employees
ORDER BY hire_date ASC NULLS LAST;在 MySQL 中模拟 NULLS LAST
MySQL 不支持 NULLS LAST 关键字。通用的解决方法是添加一个位于最前面的排序键,用来标记值是否为 NULL。
hire_date IS NULL 表达式会对实际日期返回 0,对 NULL 返回 1。按升序排列该表达式会将 NULL 推到末尾,然后由第二个排序键对实际日期进行排序。
SELECT name, hire_date
FROM employees
ORDER BY (hire_date IS NULL) ASC, hire_date ASC;在 SQL Server 中模拟 NULLS FIRST
SQL Server 同样不支持 NULLS FIRST/LAST。请使用 CASE 表达式作为位于最前面的排序键。在这里,NULL 的排名为 0,因此会排在最前面。
这个模式值得记住:将计算得到的标记列放在实际排序列之前,就可以在任何数据库方言中完全控制 NULL 的位置。
SELECT name, hire_date
FROM employees
ORDER BY CASE WHEN hire_date IS NULL THEN 0 ELSE 1 END,
hire_date ASC;完整示例:排行榜
假设您要构建一个排行榜:分数最高者排在最前面;如果分数相同,则注册时间更早的玩家排名更高。从未得分的玩家(分数为 NULL)应排在底部。
排序需要三个键:用于标记 NULL 的键、按降序排列的分数,以及作为平局决胜项按升序排列的注册日期。
SELECT player, score, signup_date
FROM players
ORDER BY (score IS NULL) ASC,
score DESC,
signup_date ASC;排序稳定性的注意事项
还有一个面试官很喜欢问的问题:“如果两行在每个 ORDER BY 排序键上的值都相同,它们会以什么顺序返回?”
答案是:未定义。SQL 排序不保证稳定,因此相同的行可以按任意相对顺序出现,而且这个顺序可能在不同运行之间,或索引发生变化后改变。
解决方法是添加一个完全唯一的决胜键,通常使用主键,从而使结果具有可复现性。
SELECT id, name, salary
FROM employees
ORDER BY salary DESC, id ASC;关于排序性能的说明
排序可能代价高昂。如果 ORDER BY 与现有索引的列顺序和排序方向完全一致,数据库引擎就可以按预排序顺序读取行,从而跳过单独的排序步骤。
方向不匹配时(例如索引中的所有列均为升序,但您将其中一列按降序排序),通常无法利用这一点,因而必须进行内存排序或磁盘排序。提到索引顺序与排序成本之间的联系,可以向面试官体现您的成熟度。
快速检查
测试您对多列排序方向规则的理解。
回顾
多列排序和 NULL 位置的要点:
- 除非添加
ORDER BY,否则结果集是无序的。 - 排序方向逐列生效;
ASC是默认值。 - NULL 的位置因数据库引擎而异:PostgreSQL/Oracle 在 ASC 中排在最后,MySQL/SQL Server 在 ASC 中排在最前。
- 在支持的数据库中使用
NULLS FIRST/LAST;在其他数据库中使用位于最前面的IS NULL或CASE标记。 - 添加唯一的决胜键(例如主键),以获得可复现的排序结果。
常见问题解答
「多列排序与 NULL 位置」课时是免费的吗?
是的 — 「多列排序与 NULL 位置」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Coding Interview Prep 课程的其余内容,请升级到 CoddyKit PRO。 Coding Interview Prep 课程共包含 4 节课。
「多列排序与 NULL 位置」这节课中我会学到什么?
了解 ASC/DESC 混用,以及不同数据库中 NULLS FIRST/LAST 的差异 你通过在浏览器中直接运行的动手代码来练习 Coding Interview Prep,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Coding Interview Prep 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Coding Interview Prep 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 1 节课,共 4 节。
「多列排序与 NULL 位置」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Coding Interview Prep 课中编写并运行代码吗?
能。每节 Coding Interview Prep 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。
此课程中的所有课时
- 多列排序与 NULL 位置
- LIMIT、OFFSET 与 FETCH FIRST
- 可靠地返回前 N 行
- 按表达式和别名排序