🚀 十一月开始了!SQLtest.online 依靠像您这样的用户捐款保持免费。请帮助我们尽早达成本月目标,让网站持续稳定运行。 立即支持 →
SQL 代码已复制到剪贴板

SQL 标准的版本与 SQL 方言

第 1.8 课 · 阅读时间:约 8 分钟

SQL 标准是 SQL 语言的国际规范,由 ISO 和 ANSI 以 ISO/IEC 9075 的编号发布。第一版发布于 1986 年,最新版本是 SQL:2023。本课介绍标准的每个版本新增了什么,从显式的 JOIN 语法到 JSON 和图查询,以及为什么每个数据库都有自己的 SQL 方言。学完本课,你会知道查询中哪些部分可以通用,哪些取决于具体的数据库。

在上一课中,你了解了什么是 SQL 以及基本查询的结构。SQL 不属于某一家厂商:它的核心由标准定义,而每个数据库都以自己的方式实现这个标准。

这也解释了一个常见的意外:在 PostgreSQL 中能运行的查询,在 SQL Server 或 MySQL 中可能会报错。了解标准,有助于写出在数据库之间迁移时改动更少的查询。

SQL 标准版本时间线:从 SQL-86 到 SQL:2023 以及每个版本的主要功能,还有建立在共同标准之上的 MySQL、PostgreSQL、SQL Server、Oracle 和 SQLite 方言


什么是 SQL 标准?

SQL 于 20 世纪 70 年代诞生于 IBM。到 80 年代中期,多家厂商都有了各自版本的语言,于是 ANSI 和随后的 ISO 发布了一份共同的规范:SQL-86。此后,ISO/IEC JTC 1/SC 32 委员会定期修订这一标准。

标准篇幅很大,由多个部分组成。第 2 部分 SQL/Foundation 定义了语言的核心:表、查询、数据修改和事务。其他部分涉及 XML、外部数据、多维数组,以及从 2023 年起的属性图。

有几点值得了解:

  • 标准定义了一组必须支持的功能,称为 Core SQL;其余功能都是可选的。
  • 没有任何数据库实现了完整的标准,每个数据库也都加入了自己的扩展。
  • 标准文档需要付费购买,所以在实践中,人们主要通过数据库文档来学习 SQL。

SQL 标准的各个版本及其新增功能

每个版本都保留了之前的内容,并加入了新功能。下表列出了你在本课程中会遇到的变化:

版本主要新增本课程中的位置
SQL-86、SQL-89SELECT、INSERT、UPDATE、DELETE、CREATE TABLE,主键和外键第 2 模块
SQL-92显式 JOIN ... ON,LEFT、RIGHT 和 FULL OUTER JOIN,CASE、CAST,DATE 和 TIMESTAMP 类型JOIN、CASE
SQL:1999WITH 和递归查询(CTE)、BOOLEAN、触发器、ROLLUP 和 CUBECTE、递归 CTE
SQL:2003窗口函数、MERGE、标识列、序列、SQL/XML窗口函数
SQL:2006使用 XQuery 查询 XML-
SQL:2008FETCH FIRST n ROWS ONLY、OFFSET、TRUNCATE TABLELIMIT 和 FETCH FIRST
SQL:2011时态表(行的历史)、LAG、LEAD、FIRST_VALUE、LAST_VALUELAG 和 LEAD
SQL:2016JSON 函数(JSON_VALUE、JSON_QUERY、JSON_TABLE)、LISTAGG、MATCH_RECOGNIZEJSON 函数
SQL:2019多维数组(SQL/MDA)-
SQL:2023JSON 数据类型、属性图查询(SQL/PGQ)、GREATEST、LEAST、ANY_VALUE复杂数据类型

SQL-92 至今仍是重要的参照点:它确定了几乎所有关系数据库都支持的语法。但现代标准要丰富得多,分析型 SQL 的大部分功能都是在 1999 年之后出现的。


SQL:2023 的新内容:JSON 和图查询

SQL:2023 让同一个数据库可以在同一条查询中同时处理关系数据、文档数据和图数据。

JSON 数据类型

SQL:2016 加入了读取以文本形式存储的 JSON 的函数。SQL:2023 则加入了真正的 JSON 类型:数据库会检查列中是否是有效的 JSON,并能以高效的二进制形式存储。MySQL、MariaDB 和 PostgreSQL(jsonb)在标准之前就有了各自的 JSON 类型;Oracle 从 21c 版本开始遵循标准类型。

属性图查询(SQL/PGQ)

属性图是一组顶点和边,例如通过“参演”关系连接起来的演员和电影。Neo4j 等图数据库使用专门的语言查询这类数据。标准新增的第 16 部分 SQL/PGQ 允许在普通表之上定义图,并用 SQL 来查询它。

在 Sakila 中,actor 和 film 成为顶点,film_actor 成为连接它们的边:

CREATE PROPERTY GRAPH film_graph
  VERTEX TABLES (actor KEY (actor_id), film KEY (film_id))
  EDGE TABLES (
    film_actor KEY (actor_id, film_id)
      SOURCE KEY (actor_id) REFERENCES actor (actor_id)
      DESTINATION KEY (film_id) REFERENCES film (film_id)
      LABEL acted_in
  );

注意:图不会复制数据,它只描述现有的表之间如何关联。

GRAPH_TABLE 运算符按模式查找路径。下面的查询返回与 Penelope Guiness 合演过电影的演员:

SELECT DISTINCT partner
FROM GRAPH_TABLE (film_graph
  MATCH (a IS actor) -[IS acted_in]-> (f IS film) <-[IS acted_in]- (b IS actor)
  WHERE a.first_name = 'PENELOPE'
    AND a.last_name = 'GUINESS'
    AND b.actor_id <> a.actor_id
  COLUMNS (b.first_name || ' ' || b.last_name AS partner)
);

结果:每位合演演员一行。模式读起来就像一幅图:演员 → 电影 ← 演员。

同样的结果也可以用 film_actor 的两次连接得到,你会在 JOIN 模块中学到这种写法。对于更长的路径,例如“通过两部电影联系起来的演员”,图语法要简短得多。目前 Oracle Database 23ai 支持 SQL/PGQ;PostgreSQL 的支持正在开发中。


SQL 方言:各数据库与标准有何不同

SQL 方言是某个数据库所实现的 SQL 版本:它支持的标准功能加上自己的扩展。基本查询在各处看起来都一样,但细节有所不同。例如,在不同数据库中查询最长的五部电影:

-- 标准(PostgreSQL、Oracle)
SELECT title, length
FROM film
ORDER BY length DESC
FETCH FIRST 5 ROWS ONLY;

-- MySQL、MariaDB、SQLite、PostgreSQL
SELECT title, length
FROM film
ORDER BY length DESC
LIMIT 5;

-- SQL Server
SELECT TOP 5 title, length
FROM film
ORDER BY length DESC;

结果:每种写法都返回相同的五部电影。LIMIT 和 TOP 比标准的 FETCH FIRST 出现得早,至今仍更常见。

其他常见差异:

任务标准MySQL / MariaDBPostgreSQLSQL ServerOracleSQLite
取前 N 行FETCH FIRSTLIMITLIMIT、FETCH FIRSTTOP、OFFSET ... FETCHFETCH FIRSTLIMIT
拼接字符串a || bCONCAT(a, b)a || ba + b、CONCATa || ba || b
给名称加引号"name"`name`"name"[name]、"name""name""name"
自增主键GENERATED AS IDENTITYAUTO_INCREMENTGENERATED AS IDENTITY、SERIALIDENTITY(1, 1)GENERATED AS IDENTITYINTEGER PRIMARY KEY
递归 CTEWITH RECURSIVEWITH RECURSIVEWITH RECURSIVEWITHWITHWITH RECURSIVE
布尔类型BOOLEANBOOLEAN = TINYINT(1)BOOLEANBITBOOLEAN(23ai)0 和 1
FULL OUTER JOIN支持不支持支持支持支持支持(3.39+)

PostgreSQL 通常被认为最接近标准。MySQL 与标准的差异最多,不过它的新版本也加入了 CTE、窗口函数等标准功能。


如何写出可移植的 SQL

把数据库结构迁移到另一个数据库总要做一些工作,但以下习惯能让查询更贴近标准:

  • 数据库支持时,优先使用标准写法:用 CASE 而不是 IF(),用 COALESCE 而不是 IFNULL 或 ISNULL,使用显式的 JOIN ... ON。
  • 使用 CAST(x AS type),而不是 PostgreSQL 的 x::type 这类简写。
  • 避免给名称加引号:小写且不含空格的名称在任何数据库中都不需要引号。
  • 把依赖具体数据库的部分,例如行数限制或日期函数,放在明确标注的位置。

在本网站上,同一道题可以在多个数据库上求解,你会在练习中亲眼看到这些差异。下一个模块将从 SELECT 开始编写查询,它是所有数据读取背后的语句。


本课要点:

  • SQL 标准是 ISO/IEC 9075;它始于 SQL-86,当前版本是 SQL:2023。
  • SQL-92 奠定了共同基础,SQL:1999 和 SQL:2003 加入了 CTE 和窗口函数,SQL:2016 加入了 JSON 函数。
  • SQL:2023 加入了 JSON 类型和基于普通表的属性图查询(SQL/PGQ)。
  • SQL 方言是某个数据库实现的标准,再加上它自己的扩展。
  • 基本查询可以通用;差异最大的是行数限制、字符串函数、自增和引号。

常见问题

SQL 标准的最新版本是什么?

最新版本是 SQL:2023(ISO/IEC 9075:2023),于 2023 年 6 月发布。它加入了 JSON 数据类型、属性图查询(SQL/PGQ),以及 GREATEST、LEAST 和 ANY_VALUE 等较小的功能。

ANSI SQL 和 ISO SQL 有什么区别?

如今它们是同一个标准。ANSI 于 1986 年发布了第一版,ISO 于 1987 年采纳了它,此后 ANSI 一直采用 ISO/IEC 9075 标准。“ANSI SQL”只是标准 SQL 的习惯叫法。

有没有数据库完全支持 SQL 标准?

没有。每个数据库都支持 Core SQL 和一组不同的可选功能,并加入自己的扩展。PostgreSQL 通常被认为最接近标准。

现在还值得学习 SQL-92 吗?

SQL-92 的语法是几乎在所有数据库中都能运行的基础,因此是很好的起点。但现代 SQL 还包括 CTE、窗口函数和 JSON,数据分析工作中每天都会用到它们。

面试题

什么是 SQL 方言?

SQL 方言是某个数据库所实现的 SQL 版本:ISO 标准的一部分加上厂商的扩展。例如 SQL Server 的 T-SQL,以及 Oracle、MySQL 和 PostgreSQL 各自的 SQL 方言。基本语法是共通的;行数限制、函数和数据类型等细节各不相同。

说出 MySQL 和 SQL Server 语法的几个区别。

MySQL 用 LIMIT 限制行数,SQL Server 用 TOP 或 OFFSET ... FETCH。MySQL 用 CONCAT 拼接字符串,SQL Server 还可以用 +;MySQL 用反引号给名称加引号,SQL Server 用方括号。自增主键在 MySQL 中写作 AUTO_INCREMENT,在 SQL Server 中写作 IDENTITY。

SQL:2023 给标准加入了什么?

原生的 JSON 数据类型和 SQL/PGQ:用 CREATE PROPERTY GRAPH 和 GRAPH_TABLE 在关系表之上进行属性图查询。它还加入了 GREATEST、LEAST 和 ANY_VALUE 等较小的功能。

如何让 SQL 查询可以在不同数据库之间迁移?

使用标准写法:显式的 JOIN ... ON、CASE、COALESCE、CAST。避免使用某个厂商特有的函数和带引号的标识符,并把必须不同的部分,例如行数限制和日期函数,单独隔离出来。