下图是著名的技术问答网站 Stack Overflow 发布的 2019 年度开发者调查报告,SQL 在最受欢迎的编程语言中排在了第 3 名。超过一半的开发者在工作中需要使用 SQL。
具体来说,如果你打算从事以下工作,都不可避免需要涉及到数据的处理:
这些职位都要求我们具有访问和操作数据库的能力;尤其是当前主流的关系数据库,如 Oracle、MySQL、SQL Server 等。
SQL(Structured Query Language,结构化查询语言)作为访问和操作关系数据库的标准语言,不但应用广泛,而且简单易学,因为它在设计之初就考虑了非技术人员的使用需求。SQL 语句全都是由简单的英语单词组成;我们只需要说明自己想要的结果,然后将具体的实现交给数据库管理系统。
学习编程,你可能会犹豫选择 C++ 还是 Java;入门数据科学,你可能会纠结于选择 Python 还是 R;但无论如何,SQL 都是 IT 从业人员不可或缺的技能!
本专栏主要讨论 SQL 编程技术和思想,分为四个部分:基础篇、进阶篇、开发篇以及扩展篇。如果是初学者,建议按照顺序阅读;如果你已经具有一定的 SQL 基础,也可以针对感兴趣的部分单独学习。
第一部分:基础篇。首先介绍数据库领域的最新发展,回顾数据库和 SQL 的核心概念;然后讨论如何使用 SELECT 语句查询数据,过滤数据、对结果进行排序、实现排行榜与分页效果;同时还会介绍常见的 SQL 函数、CASE 表达式以及数据的分组汇总;最后是一个分析世界银行全球 GDP 数据的实战案例。
第二部分:进阶篇。主要包括 SQL 数据分析的一些高级功能:空值的问题、多表连接查询、子查询、集合运算、通用表表达式与递归查询、高级分组与多维度交叉分析、窗口函数与高级报表以及基于行模式识别的数据流分析等。
第三部分:开发篇。讲述数据库设计与开发过程中涉及到的一些实用知识。包括如何设计规范化的数据库、如何管理数据库对象、如何对数据进行增删改、数据库事务的概念、索引的原理;同时还会介绍视图的概念、如何使用存储过程实现业务逻辑以及如何利用触发器实现用户操作的审计。
第四部分:扩展篇。我们将分析 SQL 语句的执行计划与查询语句的优化、使用 SQL 处理 JSON 数据、在 Python 和 Java 中执行 SQL 语句,并介绍动态语句和 SQL 注入攻击的预防。在专栏的最后,我们将探讨一下 SQL 编程中的道与术。
1970 年 IBM 的 E.F. Codd 博士发表了论文《A Relational Model of Data for Large Shared Data Banks》并创建了关系模型,通过一个简单的数据结构(关系,也就是二维表)来实现数据的存储。
1979 年 Relational Software, Inc.(后来改名为 Oracle)发布了第一个商用的关系数据库产品。随后出现了大量的关系数据库管理系统,包括 MySQL、SQL Server、PostgreSQL 以及大数据分析平台 Apache Hive、Spark SQL、Presto 等。至今,关系数据库仍然是数据库领域的主流。
以下是著名的数据库系统排名网站 DB-Engines 上各种数据库的排名情况,关系数据库占据了绝对的优势。
SQL(Structured Query Language,结构化查询语言)是访问和操作关系数据库的标准语言。只要是关系数据库,都可以使用 SQL 进行访问和控制。SQL 同样由 IBM 在 1970 年代开发,1986 年成为 ANSI 标准,并且在 1987 年成为 ISO 标准。SQL 标准随后经历了多次修订,最新的版本为 SQL:2019,增加了多维数组(MDA)的支持。下图是 SQL 标准的发展历程和主要的新增功能。
对于 SQL 标准,人们最熟悉的就是 SQL92 或者 SQL99。但实际上经过多次修改,SQL 早已不是 40 年前的 SQL;如今它已经相当完备,功能强大,并且能够同时支持关系模型和非关系(XML、JSON)模型。具体来说,最新的 SQL 标准包含 10 个部分:
为了便于学习,通常将主要的 SQL 语句分为以下几个类别:
SQL 是一种标准,不同厂商基于 SQL 标准实现了自己的数据库产品,例如 Oracle、MySQL 等。这些数据库都在一定程度上兼容 SQL 标准,具有一定的可移植性。但另一方面,它们都存在许多专有的扩展,没有任何一种产品完全遵循标准。
随着互联网的发展和大数据的兴起,出现了各种各样的非关系(NoSQL)数据库。NoSQL 代表 Not only SQL,表明它是针对传统关系数据库的补充和升级,而不是为了替代关系数据库。
NoSQL 数据库主要用于解决关系数据库在某些特定场景下的局限性,比如海量存储和水平扩展;但同时也会为此牺牲某些关系数据库的特性,例如对事务强一致性的支持和标准 SQL 接口。因此,这类数据库主要用于对一致性要求不是非常严格的互联网业务。常见的 NoSQL 数据库可以分为以下几类:
另一方面,关系数据库也在积极拥抱变化,添加了许多非关系模型(XML 和 JSON)支持。以最流行的开源关系数据库 MySQL 为例,最新的 MySQL 8.0 版本增加了 JSON 文档存储的支持,并且推出了一个新的概念:NoSQL + SQL = MySQL。以下是 MySQL 官方的宣传图。
Oracle、SQL Server 以及 PostgreSQL 同样也进行了类似的扩展,可以支持原生的 XML 和 JSON 数据,并且提供了许多标准的 SQL 接口。
中国有句古话:天下大势,合久必分,分久必合。数据库领域的发展也印证了这一规律,为了同时获得关系数据库对于事务的支持和标准的 SQL 接口,以及非关系数据库的高度扩展性和高性能。如今市场上已经出现了一类新型关系型数据库系统:NewSQL 数据库。
比较有代表性的 NewSQL 数据库包括 Google Spanner、VoltDB、PostgreSQL-XL 以及国产的 TiDB。这类新型数据库是数据库领域最新的发展方向,有志于在数据库行业发展的同学可以加以关注。
让我们回到专栏的主题,为什么要学习 SQL 呢?简单来说,因为有用。下图是 Stack Overflow 在 2019 年关于最流行编程技术的调查结果。
作为数据处理领域的专用语言,SQL 排在了第三位,超过 50% 的开发者都需要使用到 SQL。那么,具体什么职位需要使用 SQL,用 SQL 来做什么?
SQL 不但应用广泛,而且简单易学。因为它在设计之初就考虑了非技术人员的使用需求,SQL 语句全都是由简单的英语单词组成,使用者只需要声明自己想要的结果,而将具体的实现过程交给数据库管理系统。
学习编程,你可能会犹豫选择 C++ 还是 Java;入门数据科学,你可能会纠结于选择 Python 还是 R;但无论如何,SQL 都是 IT 从业人员不可或缺的一项技能!
本专栏主要讨论 SQL 编程技术和思想,分为四个部分:基础篇、进阶篇、开发篇以及扩展篇。
第一部分:基础篇。首先介绍数据库领域的最新发展,回顾数据库和 SQL 的核心概念;然后讨论如何使用 SELECT 语句查询数据,过滤数据、对结果进行排序、实现排行榜与分页效果;同时还会介绍常见的 SQL 函数、CASE 表达式以及数据的分组汇总;最后是一个分析世界银行全球 GDP 数据的实战案例。
第二部分:进阶篇。主要包括 SQL 数据分析的一些高级功能:空值的问题、多表连接查询、子查询、集合运算、通用表表达式与递归查询、高级分组与多维度交叉分析、窗口函数与高级报表以及基于行模式识别的数据流分析等。
第三部分:开发篇。讲述数据库设计与开发过程中涉及到的一些实用知识。包括如何设计规范化的数据库、如何管理数据库对象、如何对数据进行增删改、数据库事务的概念、索引的原理;同时还会介绍视图的概念、如何使用存储过程实现业务逻辑以及如何利用触发器实现用户操作的审计。
第四部分:扩展篇。我们将分析 SQL 语句的执行计划与查询语句的优化、使用 SQL 处理 JSON 数据、在 Python 和 Java 中执行 SQL 语句,并介绍动态语句和 SQL 注入攻击的预防。在专栏的最后,我们将探讨一下 SQL 编程中的道与术。
希望大家能够通过本专栏的学习,在掌握 SQL 技能的同时能够理解对面向集合的编程思想,并且在将来的工作中学以致用。
学习是一个输入再输出的过程,因此特地创建了本专栏的微信交流群,让我们一起学习一起成长。入群方式请扫描第 3 篇末尾的微信二维码,欢迎你来!
在上一篇中,我们回顾了数据库领域以及 SQL 的最新发展趋势。
本篇我们将会介绍 SQL 的基本特性以及最重要的一个编程思想:一切都是关系。让我们先来回顾一下关系数据库的几个基本概念。
关系数据库(Relational database)是指基于关系模型的数据库。关系模型由关系数据结构、关系操作集合、关系完整性约束三部分组成。
在关系模型中,用于存储数据的逻辑结构称为关系(Relation);对于使用者而言,关系就是二维表(Table)。
以下是一个员工信息表,它和 Excel 表格非常类似,由行(Row)和列(Column)组成。
在不同的场景下,大家可能会听到关于同一个概念的不同说法。在此,我们列出了关系数据库中的一些常见概念:
有了关系结构之后,就需要定义基于关系的数据操作。
常见的数据操作包括增加(Create)、查询(Retrieve)、更新(Update)以及删除(Delete),或者统称为增删改查(CRUD)。
其中,使用最多、也最复杂的操作就是查询,具体来说包括选择(Selection)、投影(Projection)、并集(Union)、交集(Intersection)、差集(exception)以及笛卡儿积(Cartesian product)等。我们将会介绍如何使用 SQL 语句完成以上各种数据操作。
为了维护数据的完整性或者满足业务需求,关系模型还定义了完整性约束。
关系模型中定义了三种完整性约束:实体完整性、参照完整性以及用户定义完整性。
本专栏涉及的 4 种数据库对于这些完整性约束的支持情况如下:
数据库 | 非空约束 | 唯一约束 | 主键约束 | 外键约束 | 检查约束 | 默认值 |
---|---|---|---|---|---|---|
Oracle | 支持 | 支持 | 支持 | 支持 | 支持 | 支持 |
MySQL | 支持 | 支持 | 支持 | 支持* | 支持* | 支持 |
SQL Server | 支持 | 支持 | 支持 | 支持 | 支持 | 支持 |
PostgreSQL | 支持 | 支持 | 支持 | 支持 | 支持 | 支持 |
* MySQL 中只有 InnoDB 存储引擎支持外键约束;MySQL 8.0.16 增加了对检查约束的支持。
存储引擎(Storage Engine)是 MySQL 中用于管理、访问和修改物理数据的组件,不同的存储引擎提供了不同的功能和特性。从 MySQL 5.5 开始默认使用 InnoDB 存储引擎,支持事务处理(ACID)、行级锁定、故障恢复、多版本并发控制(MVCC)以及外键约束等。
关系数据库使用 SQL 作为访问和操作数据的标准语言。现在,让我们来直观感受一下 SQL 语句的特点。
本节会出现几个示例,我们还没有正式开始学习 SQL 语句,可以暂时不必理会细节。
SQL 是一种声明性的编程语言,语法接近于自然语言(英语)。通过几个简单的英文单词,例如 SELECT、INSERT、UPDATE、CREATE、DROP 等,完成大部分的数据库操作。以下是一个简单的查询示例:
SELECT emp_id, emp_name, salary FROM employee WHERE salary > 10000 ORDER BY emp_id;
即使没有学过 SQL 语句,但只要知道几个单词的意思,就能明白该语句的作用。它查询员工表(employee)中月薪(salary)大于 10000 的员工,返回工号、姓名以及月薪,并且按照工号进行排序。可以看出,SQL 语句非常简单直观。
以上查询中的 SELECT、FROM 等称为关键字(也称为子句),一般大写;表名、列名等内容一般小写;分号(;)表示语句的结束。SQL 语句不区分大小写,但是遵循一定的规则可以让代码更容易阅读。
SQL 是一种声明式的语言,声明式语言的主要思想是告诉计算机想要什么结果(what),但不指定具体怎么做。这类语言还包括 HTML、正则表达式以及函数式编程等。
对于 SQL 语句而言,它所操作的对象是一个集合(表),操作的结果也是一个集合(表)。例如以下查询:
SELECT emp_id, emp_name, salary FROM employee;
其中 employee 是一个表,它是该语句查询的对象;同时,查询的结果也是一个表。所以,我们可以继续扩展该查询:
SELECT emp_id, emp_name, salary FROM ( SELECT emp_id, emp_name, salary FROM employee ) dt;
我们将括号中的查询结果(取名为 dt)作为输入值,传递给了外面的查询;最终整个语句的结果仍然是一个表。在第 17 篇中,我们将会介绍这种嵌套在其他语句中的查询就是子查询(Subquery)。
SQL 中的查询可以完成各种数据操作,例如过滤转换、分组汇总、排序显示等;但是它们本质上都是针对表的操作,结果也是表。
不仅仅是查询语句,SQL 中的插入、更新和删除都以集合为操作对象。我们再看一个插入数据的示例:
CREATE TABLE t(id INTEGER);-- 适用于 MySQL、SQL Server 以及 PostgreSQLINSERT INTO t(id)VALUES (1), (2), (3);
我们首先使用 CREATE TABLE 语句创建了一个表,然后使用 INSERT INTO 语句插入数据。在执行插入操作之前,会在内存中创建一个包含 3 条数据的临时集合(表),然后将该集合插入目标表中。由于我们通常一次插入一条数据,以为是按照数据行进行插入;实际上,一条数据也是一个集合,只不过它只有一个元素而已。
Oracle 不支持以上插入多行数据的语法,可以使用下面的插入语句:
-- 适用于 OracleINSERT INTO t(id)SELECT 1 FROM DUAL UNION ALLSELECT 2 FROM DUAL UNION ALLSELECT 3 FROM DUAL;
UNION ALL 是 SQL 中的并集运算,用于将两个集合组成一个更大的集合。此外,SQL 还支持交集运算(INTERSECT)、差集运算(EXCEPT)以及笛卡儿积(Cartesian product)。我们会在第 18 篇中介绍这些内容,它们也都是以集合为对象的操作。
我们已经介绍了 SQL 语言的声明性和面向集合的编程思想。在正式学习编写 SQL 语句之前,还需要进行一些准备工作,主要就是安装示例数据库。
在本专栏的学习过程中,我们主要使用一个虚构的公司数据模型。该示例数据库包含 3 个表:员工表(employee)、部门表(department)和职位表(job)。以下是它们的结构图,也称为实体-关系图(Entity-Relational Diagram):
我们在 GitHub 上为大家提供了示例表和初始数据的创建脚本和安装说明,支持 Oracle、MySQL、SQL Server 以及 PostgreSQL。点击链接进行下载。
运行这些脚本之前,需要先安装数据库软件。网络上有很多这类安装教程可以参考;如果无法安装数据库,也可以使用这个免费的在线 SQL 开发环境:http://sqlfiddle.com,它提供了各种常见的关系数据库服务。下图是使用 MySQL 运行示例脚本的结果:
选择数据库之后,将创建表和插入数据的脚本复制到左边窗口,点击“Build Schema”进行初始化;点击“Browser”可以查看表结构;在右侧窗口输入 SQL 语句,点击“Run SQL”运行并查看结果。该工具提供的数据库不是最新版本,但是可以运行大部分的示例。
本专栏中所有的示例都在以下数据库版本中进行了验证:
我们使用 DBeaver 开发工具编写所有的 SQL 语句,该工具的安装和使用可以参考我的博客文章。当然,你也可以使用自己喜欢的开发工具。
关系模型中定义了一个简单的数据结构,即关系(表),用于存储数据。SQL 是关系数据库的通用标准语言,它使用接近于自然语言(英语)的语法,通过声明的方式执行数据定义、数据操作、访问控制等。对于 SQL 而言,一切都是关系(表)。
阅读全文: http://gitbook.cn/gitchat/column/5dae96ec669f843a1a4aed95