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

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 字符编码,中文按照偏旁部首进行排序,不支持其他的排序方式。

相关推荐
Jacky(易小天)3 分钟前
MongoDB比较查询操作符中英对照表及实例详解
数据库·mongodb·typescript·比较操作符
Karoku06641 分钟前
【企业级分布式系统】ELK优化
运维·服务器·数据库·elk·elasticsearch
莫叫石榴姐1 小时前
数据科学与SQL:组距分组分析 | 区间分布问题
大数据·人工智能·sql·深度学习·算法·机器学习·数据挖掘
小技与小术2 小时前
数据库表设计范式
数据库·mysql
安迁岚2 小时前
【SQL Server】华中农业大学空间数据库实验报告 实验三 数据操作
运维·服务器·数据库·sql·mysql
安迁岚2 小时前
【SQL Server】华中农业大学空间数据库实验报告 实验九 触发器
数据库·sql·mysql·oracle·实验报告
Loganer2 小时前
MongoDB分片集群搭建
数据库·mongodb
LKID体2 小时前
Python操作neo4j库py2neo使用之创建和查询(二)
数据库·python·neo4j
刘大浪2 小时前
后端数据增删改查基于Springboot+mybatis mysql 时间根据当时时间自动填充,数据库连接查询不一致,mysql数据库连接不好用
数据库·spring boot·mybatis
一只爱撸猫的程序猿2 小时前
简单实现一个系统升级过程中的数据平滑迁移的场景实例
数据库·spring boot·程序员