order by 决定结果按什么顺序出来:单列、多列、升序降序、按别名、按序号。
它永远放在语句最后(limit 之前)。
Demo 里 ORDER BY height DESC 把 180.20 排到最前;多列排序先按班级、同班再按身高;
中文按名字排出来是「刘吴周孙张徐」——按编码,不是拼音。
上一篇筛行,这一篇定顺序。 两件事合起来,才叫「查出一份能看的结果」。
它和下一篇的 limit 是一对:不排序就分页,翻页必然乱——这两篇要连着看。
一、升序与降序:asc 能省,desc 不能
ORDER BY 列名 默认升序(从小到大),等价于 ORDER BY 列名 ASC。 降序必须写 DESC。
数字按大小、字符串按校对规则、日期按时间先后——
前提是日期存成了标准格式,否则按字典序排就乱了。
ASC/DESC 只作用于紧跟它的那一列,不影响别的列。
二、多列排序:先按第一列,撞了再看第二列
ORDER BY class_id, height DESC:先按班级升序,同班的再按身高降序。
写在后面的列只在前面「打平」时才起作用——这就是「排序的优先级」:靠前的说了算。
实务tip:排序的列最好是「有索引的列 + 唯一列」组合,
否则同分的行之间顺序不保证,翻页会抖。
三、中文排序:按编码,不是按拼音
Demo 排出来是「刘、吴、周、孙、张、徐」——这是 UTF-8 编码序,既不是拼音,也不是笔画。
MySQL 默认的 utf8mb4_0900_ai_ci 对中文也是按编码权重排,
同样不是拼音序。 想要拼音序只有两条路。
第一条:ORDER BY CONVERT(name USING gbk)——GBK 编码恰好接近拼音序,
但它只对常用汉字成立,生僻字会乱。
第二条(生产里更常见):另存一个 name_pinyin 字段,插入时算好拼音,排序直接用。
可控、也快,还能处理多音字。
四、按别名、按序号——能用,但别依赖
按别名:ORDER BY double_h DESC,标准写法,两边都认。
按序号:ORDER BY 2 表示「按第二列」。
能跑,但极其危险:以后在 select 里加一列,序号指的东西就变了,排序悄悄错掉。
推荐做法:永远写列名或别名,不写序号。
五、三条要特别注意的
一、NULL 的位置:
升序时 NULL 排最前,降序时排最后——引擎把 NULL 当最小值看(MySQL 也是)。
要固定位置就写 ORDER BY 列 IS NULL, 列。
二、位置固定:order by 在 where/group by/having 之后、limit 之前。
写错位置是语法错,不是逻辑错。
三、排序有代价:数据量大时它要占内存、甚至写临时文件。
能靠索引顺序直接拿到的,就别再排一遍——
ORDER BY 主键 常常是免费的,ORDER BY 函数(列) 一定不免费。
六、小结
教材小结: order by 指定排序列与方向(asc/desc),可以多列排序;中文按编码排序,需要拼音序要另行处理。 本课补三条:一是 desc 只作用于紧跟的那一列; 二是中文默认按编码排,拼音序要 gbk 转换或另存拼音列;三是别用序号排序,加一列就错。
七、动手 Demo:从升序降序到中文那五个字
Demo 六段:单列升降、多列排序、中文排序、按别名排、按序号排,最后讲三条注意事项。 第三段是这一篇的重点——中文排出来的顺序会让第一次见的人吃一惊。
import _q46 as Q
c = Q.con()
c.execute("SELECT name, height FROM students ORDER BY height DESC LIMIT 4")
c.execute("SELECT name, height FROM students ORDER BY height LIMIT 2")
# 多列:先按班级,同班按身高降序
c.execute("SELECT class_id, name, height FROM students "
"ORDER BY class_id, height DESC")
# 中文:按编码排,不是拼音
c.execute("SELECT name FROM students ORDER BY name LIMIT 6")
# 别名与序号
c.execute("SELECT name, height * 2 AS double_h FROM students "
"ORDER BY double_h DESC LIMIT 3")
c.execute("SELECT name, height FROM students ORDER BY 2 DESC LIMIT 3")
实跑输出:
--------------------------------------------------------------------
第十二课:order by,以及中文到底按什么排
--------------------------------------------------------------------
升序降序:asc 可以不写,desc 必须写
SQL> SELECT name, height FROM students ORDER BY height DESC LIMIT 4
name height
----------------
黄磊 180.20
刘洋 178.30
杨帆 175.10
周涛 174.00
(4 行)
SQL> SELECT name, height FROM students ORDER BY height LIMIT 2
name height
----------------
陈静 158.60
王芳 160.20
(2 行)
**默认是 asc(升序),所以升序一般省掉不写;降序必须写 desc。**
多列排序:先按第一列,撞了再按第二列
SQL> SELECT class_id, name, height FROM students ORDER BY class_id, height DESC
class_id name height
-------------------------------
1 杨帆 175.10
1 周涛 174.00
1 张伟 172.50
1 王芳 160.20
2 刘洋 178.30
2 李娜 165.00
2 吴倩 163.50
2 赵敏 162.80
3 黄磊 180.20
3 徐明 169.70
3 孙悦 161.40
3 陈静 158.60
(12 行)
**先按班级升序,同班的按身高降序。** **写在后面的列只在前面「打平」时才起作用。**
中文排序:按编码排,不是按拼音
SQL> SELECT name FROM students ORDER BY name LIMIT 6
name
-----
刘洋
吴倩
周涛
孙悦
张伟
徐明
(6 行)
**看到的是 `UTF-8 编码序`,不是拼音序,也不是笔画序。**
**MySQL 默认的 `utf8mb4_0900_ai_ci` 对中文也是按编码权重排,同样不是拼音。**
**真要拼音序怎么办**:
**MySQL 可以 `ORDER BY CONVERT(name USING gbk)`**(GBK 的编码恰好接近拼音序),
**或者干脆存一个 `name_pinyin` 字段专门排序。** **后者在生产里更常见——可控、也快。**
order by 能用别名,也能用列序号
SQL> SELECT name, height * 2 AS double_h FROM students ORDER BY double_h DESC LIMIT 3
name double_h
------------------
黄磊 360.40
刘洋 356.60
杨帆 350.20
(3 行)
SQL> SELECT name, height FROM students ORDER BY 2 DESC LIMIT 3
name height
----------------
黄磊 180.20
刘洋 178.30
杨帆 175.10
(3 行)
**`ORDER BY 2` 是「按第二列排」,能跑,但千万别写进代码**——
**以后在 select 里加一列,序号指的东西就变了。**
三条要特别注意的
**一、null 的位置**:升序时 null 排最前,降序时排最后。 MySQL 也是这个规矩(null 当最小值看)。
**二、order by 一定要放在语句最后**,在它后面只能再跟 limit。
**三、排序有代价**:数据量大时它要占内存甚至写临时文件,**能靠索引顺序拿到的,就别再排一遍。**
第一段降序。 黄磊 180.20、刘洋 178.30、杨帆 175.10、周涛 174.00。 第二段升序。 陈静 158.60、王芳 160.20——最矮的两个在前面。 第三段多列。 先按班级,一班里再按身高降序——两个条件叠在一起,看输出就能验证。 第四段中文。 刘、吴、周、孙、张、徐,是编码序:刘 U+5218、吴 U+5434、周 U+5468, 越往后码位越大。 第五段别名与序号。 两种都能排,但序号那种写法别进代码。 第六段三条注意。 NULL 的位置、子句位置、排序的代价。
30 秒实验
ORDER BY class_id DESC, height与ORDER BY class_id, height DESC差在哪?- (先想再跑)
ORDER BY phone升序,没填手机号的孙悦排在哪? - 把
ORDER BY 2 DESC里的 2 改成 3,排的是哪一列?
常见误区
- 以为中文会按拼音排。 默认按编码,排出来是「刘吴周孙张徐」这种顺序。
- 用序号排序。
ORDER BY 2在加了一列之后指向别处,排序悄悄错。 - 只按非唯一列排序还分页。 同分的行顺序不保证,翻页时同一行可能出现两次。
自测三问(点开对答案)
1. 多列排序时,后面的列什么时候起作用? —— 只在前面所有列的值都相等(打平)时才起作用;靠前的列优先。 2. 中文默认按什么排?想要拼音序怎么办? —— 按编码(UTF-8 字节序)排,不是拼音; 可以 ORDER BY CONVERT(name USING gbk),或另存一个拼音字段。 3. NULL 在排序里排在哪? —— 当最小值看:升序排最前,降序排最后。顺序定了,
但一查就是十几万行,谁也不想一次看完。 下一篇 limit:只取前几行,以及分页那条公式。
- ☐ (本篇完,下一篇 3.5 限制行数:limit)