不写 ORDER BY,数据库返回的顺序就没有保证——上一章的 13 行是「它高兴的顺序」。 这一章给它加上顺序:单列排、多列接力排、升序降序。 Demo 里三处关键结果: 按价格降序取第一行是 JetPack 2000、55.00。 10.00 那两个产品(Bird seed 与 TNT (5 sticks))靠第二个列才分出先后。 而 DESC 只作用在紧挨着它的那一列,要两列降序就得写两个 DESC。
接上一章:取列学会了,但取出来的行是乱序的。这一章只讲一件事——排序。 这是全书最短的一章(四页),但它管的是一条铁律: 凡是要「前几」「最新」「最大」的地方,背后都是 ORDER BY。 第 12 章的 MAX() 只能给一个数, 给不了整行;要整行就得靠这一章。
一、为什么必须自己排序
关系数据库里,行没有顺序。 表不是数组,行不占「第几个位置」。 你插进去的顺序、主键的大小,都不构成返回顺序的承诺。 那为什么平时看着有顺序? 因为小表的数据在磁盘上恰好是顺着放的。 表一大、加了索引、走了不同的执行计划,顺序立刻变。 「以前一直是这个顺序」是最贵的错觉。 所以要顺序,就得明写 ORDER BY。 这不是「加个保险」,是唯一能保证顺序的手段。
二、ORDER BY 基本用法
SELECT prod_name FROM products ORDER BY prod_name;
ORDER BY 写在 FROM 后面(有 WHERE 就写在 WHERE 后面)。
ORDER BY 后面写的是「按哪个列排」,这个列不必出现在 SELECT 里。
比如 SELECT prod_name FROM products ORDER BY prod_price 完全合法——按价格排,但只显示名字。
默认是升序(ASC)。 要降序才写 DESC。
数字按大小、文本按字符序(这跟字符集与校对有关,第 27 章讲)、日期按先后。
排序发生在取数之后、LIMIT 之前。 顺序是:
筛行(WHERE)→ 分组(GROUP BY)→ 选列(SELECT)→ 排序(ORDER BY)→ 限行(LIMIT)。
这就是为什么 ORDER BY 能用 SELECT 里起的别名,而 WHERE 不能。
三、按多个列排序
ORDER BY prod_price, prod_name 意思是:先按价格排,价格相同的那些行再按名字排。
Demo 里 10.00 有两行(Bird seed 与 TNT (5 sticks)),
它们的先后完全由第二个列决定:B 在 T 前面。 如果只写 ORDER BY prod_price,
这两行的先后就是随机的。
多列排序的实际用途:消除不确定性。 分页时如果排序键有重复值,
翻页就可能出现「同一行出现两次」或者「某行从没出现」。
加一个唯一列(比如主键)当最后一个排序键,这个问题就没了。
写几个列都行,但通常两三个就够。列越多,排序越慢。
四、指定排序方向:DESC 的作用域
DESC 只作用在紧挨着它的那一列。 这是 ORDER BY 最容易错的地方。
ORDER BY prod_price DESC, prod_name ——价格降序,
价格相同时名字仍然升序(因为 prod_name 后面没写 DESC)。
ORDER BY prod_price DESC, prod_name DESC ——这才两列都降序。要几列降序,就写几个 DESC。
还有一个组合必须记住:ORDER BY 列 DESC LIMIT 1 就是「找最大的那一行」。
Demo 里它给出 JetPack 2000、55.00——整行信息都在,而不只是一个数。
这是「取 Top N 兼取整行」的标准写法。
五、小结
教材小结一句话:ORDER BY 排序,DESC 降序,可以多列。 本课补三条:一是行序不保证是默认状态,不写 ORDER BY 就等于放弃顺序; 二是 DESC 只作用于紧挨着它的那一列; 三是 ORDER BY 加 LIMIT 1 是「取最大值那一行」的标准写法。
六、动手 Demo:从乱序到有序,再到「取最大的那一行」
Demo 走四步:单列升序、多列接力、单列降序、两列降序, 最后用一个组合收尾——ORDER BY 加 LIMIT 1 把最贵的产品整行取出来。 重点看 10.00 那两行:它在四个结果里的位置不一样,这就是「第二个列在起作用」。
import sqlite3
con = sqlite3.connect(":memory:")
con.execute("SELECT prod_name FROM products ORDER BY prod_name")
con.execute("SELECT prod_id, prod_price, prod_name FROM products "
"ORDER BY prod_price, prod_name") # 多列接力
con.execute("SELECT prod_id, prod_price FROM products "
"ORDER BY prod_price DESC LIMIT 5") # 降序
con.execute("SELECT prod_name, prod_price FROM products "
"ORDER BY prod_price DESC LIMIT 1") # 最贵的那一行
实跑输出:
--------------------------------------------------------------------
第五课:排序检索数据
--------------------------------------------------------------------
【一】排序数据:ORDER BY
SQL> SELECT prod_name FROM products ORDER BY prod_name
prod_name
---------------
.5 ton anvil
1 ton anvil
2 ton anvil
Bird seed
Carrots
Detonator
Fuses
JetPack 2000
Oil can
Safe
Sling
TNT (1 stick)
TNT (5 sticks)
(13 行)
**ORDER BY 后面写的是「按哪个列排」,这个列不必出现在 SELECT 里。**
SQL> SELECT prod_name, prod_price FROM products ORDER BY prod_price
prod_name prod_price
------------------------------
Carrots 2.50
TNT (1 stick) 2.50
Fuses 3.42
Sling 4.49
.5 ton anvil 5.99
Oil can 8.99
1 ton anvil 9.99
Bird seed 10.00
TNT (5 sticks) 10.00
Detonator 13.00
2 ton anvil 14.99
Safe 50.00
JetPack 2000 55.00
(13 行)
价格从 2.50 排到 55.00,**默认是升序(ASC)。**
**排序是「查出来之后」才发生的**,所以它几乎总是 SQL 的最后一步(LIMIT 除外)。
【二】按多个列排序
SQL> SELECT prod_id, prod_price, prod_name FROM products ORDER BY prod_price, prod_name
prod_id prod_price prod_name
------------------------------------------
FC 2.50 Carrots
TNT1 2.50 TNT (1 stick)
FU1 3.42 Fuses
SLING 4.49 Sling
ANV01 5.99 .5 ton anvil
OL1T 8.99 Oil can
ANV02 9.99 1 ton anvil
FB 10.00 Bird seed
TNT2 10.00 TNT (5 sticks)
DTNTR 13.00 Detonator
ANV03 14.99 2 ton anvil
SAFE 50.00 Safe
JP2000 55.00 JetPack 2000
(13 行)
**价格相同时才看第二个列。** 10.00 那两行(Bird seed 与 TNT (5 sticks))
就是靠 prod_name 定的先后:B 在 T 前面。**去掉第二个列,这两行的先后就是随机的。**
如果只写 ORDER BY prod_price,这两行的顺序是任意的——**加第二列就是为了消除这种任意性。**
【三】指定排序方向:DESC
SQL> SELECT prod_id, prod_price FROM products ORDER BY prod_price DESC LIMIT 5
prod_id prod_price
-----------------------
JP2000 55.00
SAFE 50.00
ANV03 14.99
DTNTR 13.00
FB 10.00
(5 行)
**DESC 只作用在紧挨着它的那一列**,这一点最容易错。
SQL> SELECT prod_id, prod_price, prod_name FROM products ORDER BY prod_price DESC, prod_name
prod_id prod_price prod_name
------------------------------------------
JP2000 55.00 JetPack 2000
SAFE 50.00 Safe
ANV03 14.99 2 ton anvil
DTNTR 13.00 Detonator
FB 10.00 Bird seed
TNT2 10.00 TNT (5 sticks)
ANV02 9.99 1 ton anvil
OL1T 8.99 Oil can
ANV01 5.99 .5 ton anvil
SLING 4.49 Sling
FU1 3.42 Fuses
FC 2.50 Carrots
TNT1 2.50 TNT (1 stick)
(13 行)
上句:价格降序,价格相同时名字**仍是升序**(因为 prod_name 后面没写 DESC)。
SQL> SELECT prod_id, prod_price, prod_name FROM products ORDER BY prod_price DESC,
prod_name DESC
prod_id prod_price prod_name
------------------------------------------
JP2000 55.00 JetPack 2000
SAFE 50.00 Safe
ANV03 14.99 2 ton anvil
DTNTR 13.00 Detonator
TNT2 10.00 TNT (5 sticks)
FB 10.00 Bird seed
ANV02 9.99 1 ton anvil
OL1T 8.99 Oil can
ANV01 5.99 .5 ton anvil
SLING 4.49 Sling
FU1 3.42 Fuses
TNT1 2.50 TNT (1 stick)
FC 2.50 Carrots
(13 行)
这一句才是两列都降序。**要几列降序,就得写几个 DESC。**
【四】用 ORDER BY 找「最大的那个」
SQL> SELECT prod_name, prod_price FROM products ORDER BY prod_price DESC LIMIT 1
prod_name prod_price
----------------------------
JetPack 2000 55.00
(1 行)
**ORDER BY + LIMIT 1 就是「最大的那一行」**,而且它带回了整行信息。
第 12 章会讲 MAX(),但 MAX() 只能给你一个数,给不了整行——**要整行就用这一招。**
第一段是单列升序。 13 行按名字排,
注意 .5 ton anvil 排在第一个——标点符号在字符序里比字母和汉字都靠前,这不是 bug。
第二段是多列接力。 价格为主、名字为辅。10.00 那两行的先后由名字决定(Bird seed 在 TNT 前面);
如果把第二个列去掉,这两行谁先谁后就看数据库心情了。
第三段是单列降序。 55.00、50.00、14.99、13.00、10.00——注意 10.00 只出现一次,
因为 LIMIT 5 把第二行 10.00 砍掉了。
第四段是这一章的关键。 前一句只给 prod_price 加 DESC,所以价格降序、价格相同时名字升序;
后一句两个列都加 DESC,10.00 那两行就翻了个个儿(TNT 在前)。同一份数据,两个 DESC,两种顺序。
最后一段是实用收尾。 ORDER BY prod_price DESC LIMIT 1 把 JetPack 2000 整行取出来——
名字、价格一起给你。第 12 章的 MAX() 只能给你 55.00 这个数,给不了产品名。
30 秒实验
- 把 ORDER BY prod_name 换成 ORDER BY prod_name DESC,第一行变成什么?
- 试
ORDER BY vend_id, prod_price DESC——同一供货商内部价格降序,供货商之间升序,结果对吗? - 不加 ORDER BY 直接 LIMIT 1,多跑几次,第一行会变吗?变或不变各说明什么?
常见误区
- 以为只写一个 DESC 就全降序。DESC 只作用于紧挨着它的那一列。要两列降序就得写两个 DESC。
- 以为排序键必须在 SELECT 里。不必。ORDER BY 可以用没取出来的列。 这一点和 DISTINCT 配合时会出问题(DISTINCT 之后不能按没选的列排)。
- 用非唯一列排序后分页。排序键有重复值时,翻页会出现重复行或漏行。 加主键当最后一个排序键。
自测三问(点开对答案)
1. 不写 ORDER BY 时,行的顺序由什么决定? —— 没有保证。取决于存储顺序、索引、执行计划。可以说「由数据库决定」,但不能当成规则来依赖。 2. `ORDER BY a DESC, b` 和 `ORDER BY a DESC, b DESC` 有什么区别? —— 前者 a 降序、a 相同时 b 升序;后者 a、b 都降序。DESC 只作用于紧挨着它的那一列。 3. 怎么取「价格最高的那个产品的名字和价格」? —— `SELECT prod_name, prod_price FROM products ORDER BY prod_price DESC LIMIT 1`。 用 MAX() 只能拿到价格,拿不到名字。能排能取了,但每次都是整表。 下一章开始筛:WHERE 子句、九种操作符、BETWEEN 的闭区间, 以及那个反直觉的规矩——NULL 不能用等号判断。
- ☐ (本章完,下一章 第6章 过滤数据)