五种主流数据库:从无序到有序

SQL 查询不保证返回结果的顺序。如果我们想要按照某种规则对结果进行排序显示,例如按照工资从高到低进行排序,需要使用 ORDER BY 子句。

本文比较五种主流数据库对查询结果排序的实现和差异,包括 MySQL、Oracle、SQL Server、PostgreSQL 以及 SQLite。

ORDER BY MySQL Oracle SQL Server PostgreSQL SQLite
单个字段排序 ✔️ ✔️ ✔️ ✔️ ✔️
多个字段排序 ✔️ ✔️ ✔️ ✔️ ✔️
表达式排序 ✔️ ✔️ ✔️ ✔️ ✔️
空值排序 默认最小 默认最大 默认最小 默认最大 默认最小
中文排序 偏旁部首、拼音 偏旁部首、拼音、笔画 偏旁部首、拼音、笔画 偏旁部首、拼音 偏旁部首

基于单个字段排序

基于单个字段值的排序操作被称为单列排序。单列排序的语法如下:

sql 复制代码
SELECT col1, col2, ...
FROM t
[WHERE ...]
ORDER BY col1 [ASC | DESC];

其中,ORDER BY 子句用于指定排序,ASC 表示按照升序排序(Ascending),DESC 表示按照降序排序(Descending),默认按照升序排序。

以下语句查找公司的女性员工,并且按照月薪从高到低排序显示:

sql 复制代码
SELECT emp_name, salary
FROM employee
WHERE sex = '女'
ORDER BY salary DESC;

查询返回的结果如下:

sql 复制代码
emp_name|salary 
--------|--------
孙尚香  |12000.00
赵氏    | 6600.00
孙丫鬟  | 6000.00

提示:对于升序排序,数字按照从小到大的顺序排列,字符按照编码的顺序排列,日期和时间按照从早到晚的顺序排列;对于降序排序则正好相反。

基于多个字段排序

如果排序字段中存在相同的数据,那么它们的排序顺序是随机的。为了进一步明确这些数据的排序顺序,可以使用多列排序。

多列排序指的是基于多个字段值的排序,多个字段间使用逗号进行分隔。多列排序的语法如下:

sql 复制代码
SELECT col1, col2, ...
FROM t
[WHERE ...]
ORDER BY col1 [ASC | DESC], col2 [ASC | DESC], ...;

首先,查询基于第一个字段进行排序,对于第一个字段排序相同的数据,再基于第二个字段进行排序,并且依此类推。

以下语句查找销售部(dept_id=5)的员工信息,并且按照月薪从高到低排序,如果其月薪相同,则按照入职先后进行排序:

sql 复制代码
SELECT emp_name, salary, hire_date
FROM employee
WHERE dept_id = 5
ORDER BY salary DESC, hire_date;

查询返回的结果如下:

sql 复制代码
emp_name|salary |hire_date 
--------|--------|----------
法正    |10000.00|2017-04-09
简雍    | 4800.00|2019-05-11
...
蒋琬    | 4000.00|2018-01-28
邓芝    | 4000.00|2018-11-11

其中,"蒋琬"和"邓芝"的月薪相同,但是"蒋琬"排在了"邓芝"之前,因为他的入职日期更早。

基于表达式排序

除了基于字段的值进行排序外,我们也可以基于表达式的值进行排序。例如,以下语句查找行政管理部(dept_id=1)的员工,并且按照全年总收入进行排序:

sql 复制代码
SELECT emp_name, salary * 12 + bonus
FROM employee
WHERE dept_id = 1
ORDER BY salary * 12 + bonus;

员工的全年总收入等于年薪(salary*12)加奖金(bonus),查询返回的结果如下:

sql 复制代码
emp_name|salary * 12 + bonus
--------|-------------------
张飞    | 298000.00
关羽    | 322000.00
刘备    | 370000.00

另外,我们也可以使用字段或者表达式在 SELECT 列表中出现的位置来指定数据的排序。

例如,上面的查询语句可以改写如下:

sql 复制代码
SELECT emp_name, salary * 12 + bonus
FROM employee
WHERE dept_id = 1
ORDER BY 2;

表达式 salary * 12 + bonus 是查询返回的第 2 列,因此 ORDER BY 2 也表示按照全年总收入进行排序。

空值的排序位置

空值(NULL)在数据库中表示未知或者缺失的数据。如果排序的字段中存在空值时,应该如何处理呢?以下语句查找人力资源部(dept_id=2)中的员工,并且按照奖金从低到高进行排序显示:

sql 复制代码
SELECT emp_name, bonus
FROM employee
WHERE dept_id = 2
ORDER by bonus;

不同数据库系统对于空值的排序位置采用了不同的处理方式。MySQL、Microsoft SQL Server 以及 SQLite 中的空值排在了最前,查询返回的结果如下:

sql 复制代码
-- MySQL、Microsoft SQL Server 以及 SQLite
emp_name|bonus 
--------|-------
黄忠    | 
魏延    | 
诸葛亮  |8000.00

Oracle 和 PostgreSQL 中的空值排在了最后,查询返回的结果如下:

sql 复制代码
-- Oracle 以及 PostgreSQL
emp_name|bonus 
--------|-------
诸葛亮  |8000.00
黄忠    | 
魏延    | 

另外,Oracle、PostgreSQL 以及 SQLite 支持使用 NULLS FIRST 关键字,将空值排在最前;或者使用 NULLS LAST 关键字,将空值排在最后。以下查询语句返回的结果与上面的 MySQL 和 Microsoft SQL Server 一致:

sql 复制代码
-- Oracle、PostgreSQL 以及 SQLite
SELECT emp_name, bonus
FROM employee
WHERE dept_id = 2
ORDER by bonus NULLS FIRST;

总而言之,对于空值的排序:

  • MySQL、Microsoft SQL Server 以及 SQLite 认为排序时空值最小,升序排序时空值排在最前,降序排序时空值排在最后。
  • Oracle 和 PostgreSQL 认为排序时空值最大,升序排序时空值排在最后,降序排序时空值排在最前。
  • Oracle、PostgreSQL 以及 SQLite 支持使用 NULLS FIRST 和 NULLS LAST 指定空值的排序位置。

中文的排序方式

在创建数据库或者表时,我们通常会指定一个字符集和排序规则。字符集(Charset)决定了数据库能够存储哪些字符,比如 ASCII 字符集只能存储简单的英文、数字和一些控制字符,GB2312 字符集可以存储中文,Unicode 字符集能够支持世界上的各种文字。

排序规则(Collation)定义了字符集中字符的排序顺序,包括是否区分大小写、是否区分重音等。对于中文而言,排序方式与英文有所不同,中文通常需要按照拼音、偏旁部首或者笔画进行排序。

如果想要支持中文排序,最简单的方式就是使用支持中文排序的字符集和排序规则。如果使用的字符集和排序规则不满足我们的排序需求,可以通过其他方法实现。

Oracle 默认使用 AL32UTF8 字符编码,中文按照偏旁部首进行排序。我们可以通过一个转换函数实现其他方式的中文排序,以下查询按照员工姓名的拼音进行排序:

sql 复制代码
-- Oracle 实现中文拼音排序
SELECT emp_name
FROM employee
WHERE dept_id = 4
ORDER BY NLSSORT(emp_name,'NLS_SORT = SCHINESE_PINYIN_M');

其中,NLSSORT()是 Oracle 提供的一个系统函数,用于返回按照指定排序规则编码的字符序列,SCHINESE_PINYIN_M 表示中文的拼音排序规则。查询返回的结果如下:

sql 复制代码
EMP_NAME
--------
关平 
关兴 
廖化 
马岱 
张苞 
赵氏 
赵统 
赵云 
周仓 

除按照拼音排序外,Oracle 还支持按照偏旁部首(SCHINESE_RADICAL_M)以及笔画(SCHINESE_STROKE_M)进行中文排序。

MySQL 8.0 默认使用 utf8mb4 字符编码,中文按照偏旁部首进行排序。我们可以通过一个转换函数实现其他方式的中文排序,以下查询按照员工姓名的拼音进行排序:

sql 复制代码
-- MySQL 实现中文拼音排序
SELECT emp_name
FROM employee
WHERE dept_id = 4
ORDER BY CONVERT(emp_name USING GBK);

其中,CONVERT()是一个 MySQL 系统函数,用于转换数据的字符集编码,中文 GBK 字符集默认使用拼音进行排序。查询返回的结果和上面的 Oracle 示例相同。

Microsoft SQL Server 中的字符集和排序规则是同一个概念,安装数据库时默认根据操作系统所在的区域进行设置,中国地区默认使用 Chinese_PRC_CI_AS 排序规则,中文按照偏旁部首进行排序。我们可以通过 COLLATE 关键字实现其他方式的中文排序,以下查询按照员工姓名的拼音进行排序:

sql 复制代码
-- SQL Server 实现中文拼音排序
SELECT emp_name
FROM employee
WHERE dept_id = 4
ORDER BY emp_name COLLATE Chinese_PRC_CI_AI_KS_WS;

其中,COLLATE 表示按照某种排序规则进行排序,Chinese_PRC_CI_AI_KS_WS 表示中文拼音排序规则。查询返回的结果和上面的 Oracle 示例一样。

Microsoft SQL Server 也支持中文按照笔画进行排序(Chinese_PRC_Stroke_CI_AS)。

PostgreSQL 默认使用 UTF-8 编码字符集,中文按照偏旁部首进行排序。我们可以通过 COLLATE 关键字实现其他方式的中文排序,以下查询按照员工姓名的拼音进行排序:

sql 复制代码
-- PostgreSQL 实现中文拼音排序
SELECT emp_name
FROM employee
WHERE dept_id = 4
ORDER BY emp_name COLLATE "zh_CN";

其中,COLLATE 表示按照某种排序规则进行排序,zh_CN 表示中文拼音排序规则。查询返回的结果和上面的 Oracle 示例一样。

SQLite 默认使用 UTF-8 字符编码,中文按照偏旁部首进行排序,不支持其他的排序方式。

相关推荐
易云码14 分钟前
信息安全建设方案,网络安全等保测评方案,等保技术解决方案,等保总体实施方案(Word原件)
数据库·物联网·安全·web安全·低代码
newxtc19 分钟前
【客观理性深入讨论国产中间件及数据库-科创基础软件】
数据库·中间件·国产数据库·国产中间件·科创
蓝眸少年CY20 分钟前
MySQL 【流程控制】函数
mysql
水月梦镜花21 分钟前
redis:list列表命令和内部编码
数据库·redis·list
MonkeyKing_sunyuhua1 小时前
ubuntu22.04 docker-compose安装postgresql数据库
数据库·docker·postgresql
天郁青1 小时前
数据库交互的本地项目:后台管理系统
数据库·交互
马剑威(威哥爱编程)1 小时前
MongoDB面试专题33道解析
数据库·mongodb·面试
小光学长2 小时前
基于vue框架的的流浪宠物救助系统25128(程序+源码+数据库+调试部署+开发环境)系统界面在最后面。
数据库·vue.js·宠物
掘金-我是哪吒2 小时前
微服务mysql,redis,elasticsearch, kibana,cassandra,mongodb, kafka
redis·mysql·mongodb·elasticsearch·微服务
零炻大礼包3 小时前
【SQL server】数据库远程连接配置
数据库