您好!欢迎访问家园网-www.jy.wang!

家园网

SQL 语句组合,它把函数、排序规则和动态排序结合

网络 作者:本站 点击:
SELECT * FROM tb_name;
SELECT *
FROM tb_name
ORDER BY LEFT(name,1) COLLATE Chinese_PRC_Stroke_CS_AS_KS_WS DESC;

这是一个非常精彩的 SQL 语句组合,它把函数排序规则动态排序结合在了一起。

下面我们拆解这个语句,并重点讲清楚第二句里 ORDER BY LEFT(name,1) COLLATE ... 到底在做什么。


一、第一句:普通查询

sql

SELECT * FROM tb_name;

非常简单,就是查询 tb_name 表中的所有列和所有行,按表的物理存储顺序返回(通常是插入顺序,但不保证)。


二、第二句:按首字符的笔画逆序排序

sql

SELECT *FROM tb_nameORDER BY LEFT(name,1) COLLATE Chinese_PRC_Stroke_CS_AS_KS_WS DESC;

逐段拆解

部分含义
SELECT *查询所有列
FROM tb_name从这张表里查
ORDER BY按后面的表达式排序
LEFT(name,1)取 name 列的第一个字符
COLLATE Chinese_PRC_Stroke_CS_AS_KS_WS临时把这个字符的排序规则改成简体中文笔画排序
DESC降序排列(笔画多的在前,少的在后)

整体含义

取 name 列的第一个汉字,按简体中文笔画排序规则(区分大小写、重音、假名、全角)进行降序排列,然后输出整张表的所有行。


三、核心重点:LEFT(name,1) COLLATE ... 的作用

1. 没有 COLLATE 会怎样?

sql

-- 假设表里有这些名字张三, 李四, 王五, 赵六, 欧阳锋

sql

ORDER BY LEFT(name,1)

结果: 按第一个字符的默认排序规则(通常是拼音)排序

首字拼音排序
li1
ou2
wang3
zhang4
zhao5

2. 加了 COLLATE Chinese_PRC_Stroke_... 后

sql

ORDER BY LEFT(name,1) COLLATE Chinese_PRC_Stroke_CS_AS_KS_WS

结果: 按第一个字符的笔画数排序

首字笔画数排序(升序)
4画1
7画2
7画2(笔顺可能不同)
8画4
9画5

3. 加了 DESC 后

sql

ORDER BY ... DESC

结果: 笔画多的在前,少的在后

首字笔画数排序(降序)
9画1
8画2
7画3
7画4
4画5

四、为什么这个写法很巧妙?

场景:按名字首字的笔画数排序

如果没有 COLLATE,你需要:

  1. 创建一个笔画数字段

  2. 写一个复杂的函数计算每个字的笔画

  3. 或者关联一个笔画字典表

有了 COLLATE

  • 一行代码搞定

  • 利用 SQL Server 内置的笔画排序规则

  • 实时计算,不需要额外字段

性能代价

方面说明
索引失效用了函数 LEFT(name,1),普通索引用不上
每行计算每一行都要取首字符、应用排序规则
大数据量会慢,需要优化(如加计算列并建索引)

五、完整的执行逻辑示例

假设 tb_name 表有这些数据:

idname
1张三
2李四
3王五
4赵六
5欧阳锋
6周一
7孙七

执行第二句 SQL:

text

第1步:对每一行,取 name 的第一个字符
  1 → '张'
  2 → '李'
  3 → '王'
  4 → '赵'
  5 → '欧'
  6 → '周'
  7 → '孙'

第2步:用笔画排序规则计算这些字符的排序权重
  张(7画) → 权重值
  李(7画) → 权重值(可能和'张'不同,取决于笔顺)
  王(4画) → 权重值
  赵(9画) → 权重值
  欧(8画) → 权重值
  周(8画) → 权重值
  孙(6画) → 权重值

第3步:按权重降序排列
  赵(9画) → 第1行
  欧(8画) → 第2行
  周(8画) → 第3行
  张(7画) → 第4行
  李(7画) → 第5行
  孙(6画) → 第6行
  王(4画) → 第7行

第4步:返回整行数据


六、注意事项和坑

1. 空值和空字符串

sql

-- 如果 name 是 NULLLEFT(NULL,1) → NULL-- NULL 在排序中通常排在最前或最后(取决于数据库设置)-- 如果 name 是空字符串 ''LEFT('',1) → ''(空字符串)

2. 非汉字字符

sql

-- 如果 name = '123'LEFT('123',1) → '1'-- 笔画排序规则如何处理数字?按 Unicode 码位排,通常数字在汉字前面

3. 多字节字符(Emoji)

sql

-- 如果 name = '😀笑'LEFT('😀笑',1) → '😀'(一个 Emoji)-- 笔画排序规则可能不认识 Emoji,会按码位排序

4. 排序规则中的 _CS_AS_KS_WS 对中文的影响

后缀对简体中文的影响
_CS区分大小写(中文没有大小写,不影响)
_AS区分重音(中文没有重音,不影响)
_KS区分假名(日文特有,中文不影响)
_WS区分全角/半角(中文全角字母数字会有影响)

实际效果: 对于纯汉字,Chinese_PRC_Stroke_CI_AS 和 Chinese_PRC_Stroke_CS_AS_KS_WS 结果一样。


七、对比:有无 COLLATE 的区别

sql

-- 按默认拼音排序SELECT * FROM tb_name ORDER BY name;-- 结果:李四、欧阳锋、孙七、王五、张三、赵六、周一-- 按首字符笔画排序SELECT * FROM tb_name ORDER BY LEFT(name,1) COLLATE Chinese_PRC_Stroke_CI_AS;-- 结果:王五、李四、张三、孙七、欧、周、赵-- 按首字符笔画降序排序(你的语句)SELECT * FROM tb_name ORDER BY LEFT(name,1) COLLATE Chinese_PRC_Stroke_CS_AS_KS_WS DESC;-- 结果:赵六、欧阳锋、周一、张三、李四、孙七、王五


八、总结

问题答案
这个 SQL 在做什么?按名字的第一个字的笔画数,从多到少排序
LEFT(name,1)取第一个字符
COLLATE Chinese_PRC_Stroke_...临时改用笔画排序规则
DESC降序(笔画多的在前)
为什么能这么写?SQL Server 允许在表达式中使用 COLLATE 临时覆盖列的默认排序规则
有什么代价?无法使用索引,大数据量会慢

一句话:这个 SQL 巧妙地利用 LEFT() 函数提取首字,再用 COLLATE 临时切换成笔画排序规则,实现了“按名字首字笔画数降序排列”的效果——这是 SQL Server 排序规则灵活性的一个经典应用


标签: