本篇介绍SQL:2016(ISO/IEC 9075:2016)标准中定义的查询语句,以及六种主流数据库中的实现及差异:Oracle、MySQL、Microsoft SQL Server、PostgreSQL、Db2、SQLite。
从本篇开始,我们使用的示例数据库结构如下图所示。
其中包含7个表和1个视图。
- regions,全球区域表
- countries,国家信息表,通过region_id关联regions表
- locations,街道地址表,通过country_id关联countries表
- departments,部门信息表,通过location_id关联locations表,通过manager_id关联employees表
- employees,员工信息表,通过department_id关联departments表,通过job_id关联jobs表,通过manager_id与自己关联
- jobs,职位信息表
- job_history,员工任职历史表,通过employee_id关联employees表,通过department_id关联departments表,通过job_id关联jobs表
- emp_details_view,员工详细信息视图,同时显示了多个表中的关联信息
创建示例数据库的SQLite脚本点击下载。
不同的数据库产品都提供了自己的管理和开发工具,例如MySQL的MySQL Workbench,Oracle的SQL Developer。本文推荐一个第三方的免费工具:DBeaver,它可以通过JDBC连接几乎所有的数据库。
先从最简单的查询开始,SQL中的查询使用SELECT
语句表示。
最简单的查询
一个最简单的查询示例如下:
SELECT first_name, last_name FROM employees;
其中SELECT
和FROM
称为关键字,它们不区分大小写,建议大写,便于阅读。
SELECT
表示一条查询语句,后面是要显示的信息,使用逗号分隔;FROM
表示要从哪个表中进行查询;分号表示语句结束。
更一般的查询语法如下:
SELECT column1, column2, ...
FROM table;
以上示例查询的结果如下(共计107条):
如果表中的列较多,为了快速查看所有列的信息,可以使用星号(*)表示。
SELECT * FROM employees;
以上查询将会显示employees表的所有列。
在实际项目中,不要使用 SELECT *,避免表结构变更带来的不确定性。
除此之外,许多数据库还支持另一种更简单的查询:
SELECT 1+1;
这种形式不属于SQL标准规范,它不需要FROM
关键字,可以用于快速查询信息,或者当作计算器使用。
数据库 | 不带FROM的SELECT | 描述 |
---|---|---|
Oracle | N/A | Oracle提供了一个单行单列的dual表,用于执行这种简单的查询和计算: SELECT 1+1 FROM dual; |
MySQL | OK | MySQL也提供了dual表 |
SQL Server | OK | |
PostgreSQL | OK | |
Db2 | N/A | Db2也提供了Oracle中类似的表: SELECT 1+1 FROM sysibm.sysdummy1; |
SQLite | OK |
消除重复值
在SQL中,提供了DISTINCT
关键字,用于删除查询结果中的重复值。例如:
SELECT DISTINCT first_name FROM employees;
DISTINCT
位于SELECT
之后,可以基于多个列值进行查重操作,通用语法如下:
SELECT DISTINCT
column1,
column2,
...
FROM table;
为了消除重复值,数据库系统需要对结果进行排序,然后扫描重复值;因此,大量数据的重复值处理会降低查询的速度。
以上示例的结果如下(共计91条):
查询结果只有91条,而不是107条,这是因为 first_name 中有重复的数据。
DISTINCT
对于多个NULL
值,只会返回1条空值记录。例如:
SELECT DISTINCT commission_pct FROM employees;
使用列别名
在查询结果中,可以通过使用列别名为列指定一个临时的名称,以提高可读性。
SELECT c1 AS column_alias1, c2 column_alias2, FROM table;
关键字AS
用于定义一个别名,也可以省略,只保留一个空格。
SELECT commission_pct AS 'Commission percentage' FROM employees;
当列别名中包含空格或者特殊字符时,需要将别名引用起来,不同的数据库产品使用不同的引用符号。
数据库 | 使用列别名 | 描述 |
---|---|---|
Oracle | OK | Oracle返回大写的列名,对于包含空格的列别名使用双引号进行引用 |
MySQL | OK | MySQL对于包含空格的列别名支持单引号或者双引号或者反单引号(`)引用 |
SQL Server | OK | SQL Server对于包含空格的列别名支持单引号或者双引号或者中括号([ ])引用 |
PostgreSQL | OK | PostgreSQL返回小写的列名,对于包含空格的列别名使用双引号进行引用 |
Db2 | OK | 返回大写的列名,对于包含空格的列别名使用双引号进行引用 |
SQLite | OK | SQLite对于包含空格的列别名支持以上各种符号引用 |
除了列别名之外,SQL还支持表别名,我们将在介绍多表连接查询(JOIN
)时解释表的别名。
SQL中的注释
在SQL中,可以像其他编程语言一样使用注释,注释不会被执行。
SQL中的注释分为单行注释和多行注释。
单行注释以两个连字符(–)开始,直到这一行结束。例如:
SELECT DISTINCT first_name -- distinct will remove duplicate records FROM employees;
多行注释使用C语言风格的注释方法(/* … */)。例如:
SELECT DISTINCT first_name /* distinct will remove duplicate records from results */ FROM employees;
除了SQL标准中的两种注释方式之外,不同数据库还提供了额外的扩展。
数据库 | SQL中的注释 | 描述 |
---|---|---|
Oracle | OK | Oracle中的特殊用法 –+ 和 /*+ hint */ 用于表示查询提示,参考Oracle文档 |
MySQL | OK | MySQL中的 # 也可以用单行注释;/*+ hint */ 用于优化器提示;/*! */ 也属于特殊用法 |
SQL Server | OK | |
PostgreSQL | OK | |
Db2 | OK | |
SQLite | OK |