安装 PostgreSQL
PostgreSQL 是一个功能强大的开源对象关系数据库系统。它经过数十年的积极开发和经过验证的架构,使其在可靠性、数据完整性和正确性方面赢得了良好的声誉。而其天生支持异步操作的特性,在高并发场景中倍受欢迎。同时,它的扩展性极强,只要你有能力,你可以使用任何你熟悉的其它开发语言来编写 PostgreSQL 脚本,比如:Rust、Python 等。PostgreSQL 对象
本章将介绍 PostgreSQL 常见的服务器和数据库对象。示例数据库
本章将介绍示例数据库,以便后续的演示。同时,你将学习到如何将已存在的数据导入到 PostgreSQL 中。基础 SELECT
本章将讨论如何使用简单的 `SELECT` 语句从 PostgreSQL 查询数据。PostgreSQL 的 `SELECT` 语句有诸多独特的特性,让我们一起感受一下。WHERE 子句
本章我们将学习 `WHERE` 子句,它不但能用于 `SELECT` 过滤查询结果,还能用于其它语句。LIMIT、OFFSET 和 FETCH 子句
本章我们学习 `LIMIT` 、`OFFSET` 和 `FETCH` 子句。和 `LIMIT` 一样,`FETCH` 也是为了限定返回的行数,但你不知道的是,`FETCH` 才是 SQL 标准,而 `LIMIT` 不是。LIKE 和 ILIKE
前面章节提过,在 PostgreSQL 中,`LIKE` 是区分大小写的。如果要像其它数据库那样不区分大小写,需要使用 `ILIKE`。PostgreSQL 还为它们提供了等价的运算符。连接
本章将讨论 PostgreSQL 的各种连接:内连接、左外连接、右外连接、交叉连接、自然连接、自连接和完全外连接。值得一提的是,哪怕到了 MySQL 8,MySQL 依然不支持完全外连接。分组
本章将讨论 PostgreSQL 的 `GROUP BY` 子句:将`SELECT` 语句返回的结果进行分组;对于每个分组,可以使用聚合函数。同时讨论与之相关的 `HAVING`、`CUBE`、`ROLLUP` 等。联合查询(并集)、交集查询及差集查询
本章将讨论 `UNION`:联合(并集)查询、`INTERSECT `:交集查询和`EXCEPT`:差集查询。子查询
本章我们将讨论如何使用 PostgreSQL 子查询来构建复杂的查询。同时会学习 `IN`、`EXISTS`、`ANY`、`SOME`、`ALL` 等操作。插入数据
本章将讨论如何使用 `INSERT` 向 PostgreSQL 中插入新行。同时介绍如何通过`REGURNING`子句返回最新插入行的ID以及批量插入数据的方法。修改数据
本章将讨论如何使用 `UPDATE` 语句修改 PostgreSQL 数据,以及配合 `RETURNING` 子句在修改数据的同时,返回修改后的内容。最后,还将介绍 `UPDATE JOIN`:根据另一张表中的数据进行修改。删除数据
本章将讨论如何使用 `DELETE` 语句删除 PostgreSQL 数据,以及配合 `RETURNING` 子句在删除数据的同时,返回已删除的内容。最后,还将介绍 `DELETE JOIN`:根据另一张表中的数据进行删除。插入或更新数据
在关系型数据库中,术语`upsert`称为合并:当插入数据时,如果数据已存在则进行更新,否则插入新行。PostgreSQL 使用 `INSERT ON CONFLICT` 实现这一功能。基础数据类型
本章我们讨论 PostgreSQL 的基本数据类型:布尔型、字符型、数值型和日期时间型。这些类型与其它数据库有着很多不同,让我们一起深入细节进行了解。表
本章将讨论和表相关的知识,包括:创建表、修改表、清空(截断)表和删除表。约束
本章将讨论 PostgreSQL 的约束,包括:主键约束、外键约束、唯一约束、非空约束、 CHECK 约束。条件表达式和运算符
本章将讨论 PostgreSQL 条件表达式和运算符,包括:使用 `CASE` 构造条件查询、使用 `COALESCE` 过滤非空参数、使用 `NULLIF` 处理 `NULL` 值以及使用 `CAST` 进行数据类型转换。视图
本章我们将讨论视图:创建、修改、删除视图。为高级篇的物化视图、递归视图等打好基础。性能分析
PostgreSQL 提供了 `EXPLAIN` 语句,它可以用来分析 SQL 的执行情况。本章将对其进行讨论。索引
PostgreSQL 索引是增强数据库查询性能的有效工具。然而,索引增加了数据库系统的写入和存储开销。因此,正确使用它们非常重要。本章我们将讨论如何使用索引。角色与权限
本章介绍角色与权限。PostgreSQL 使用角色来表示用户账号,而不是其它数据库那样使用用户概念。客户端鉴权
本章将讨论 PostgreSQL 客户端鉴权。回到之前安装 PostgreSQL 时的一个问题,为什么在本地登录 PostgreSQL 时,不需要输入密码?本章将回答这个问题。事务
本章将讨论如何使用 `BEGIN` 、 `COMMIT` 和 `ROLLBACK` 语句处理 PostgreSQL 事务。备份与还原
本章将介绍备份和还原 PostgreSQL 数据库。常用函数
本章对 PostgreSQL 常用函数进行汇总,包括:聚合函数、日期时间函数、字符串函数和数学函数。对于窗口函数,我们将在高级篇进行介绍。
连接
- 328
- 2023-07-29 06:31:56
开始之前,先创建两张表并插入一些数据:
CREATE TABLE basket_a (
a INT PRIMARY KEY,
fruit_a VARCHAR (100) NOT NULL
);
CREATE TABLE basket_b (
b INT PRIMARY KEY,
fruit_b VARCHAR (100) NOT NULL
);
INSERT INTO basket_a (a, fruit_a)
VALUES
(1, 'Apple'),
(2, 'Orange'),
(3, 'Banana'),
(4, 'Cucumber');
INSERT INTO basket_b (b, fruit_b)
VALUES
(1, 'Orange'),
(2, 'Apple'),
(3, 'Watermelon'),
(4, 'Pear');
内连接
SELECT
a,
fruit_a,
b,
fruit_b
FROM
basket_a
INNER JOIN basket_b
ON fruit_a = fruit_b;
- 使用
INNER JOIN
进行连接,使用ON
指定连接条件 - 内连接检查第一个表(
basket_a
)中每一行,并与第二个表(basket_b
)的每一行进行对比:如果指定字段的值相等(由ON
指定的fruit_a
和fruit_b
),则创建新行,并将该行添加到结果集中。
左外连接
SELECT
a,
fruit_a,
b,
fruit_b
FROM
basket_a
LEFT JOIN basket_b
ON fruit_a = fruit_b;
- 使用
LEFT JOIN
进行连接,使用ON
指定条件LEFT JOIN
左侧的表为“左表”,此例中的basket_a
LEFT JOIN
右侧的表为“右表”,此例中的basket_b
- 从左表(
basket_a
)中选择数据,并将它的fruit_a
字段的值和右表(basket_b
)的fruit_b
字段值进行对比(由ON
指定):- 如果相等,将创建一个包含两张表记录的新行,并将新行添加到结果集中
- 如果不相等,只创建只包含左表记录,右边记录全部为
NULL
的新行,并将新行添加到结果集中
LEFT JOIN
左侧的表为“左表”,此例中的basket_a
LEFT JOIN
右侧的表为“右表”,此例中的basket_b
- 如果相等,将创建一个包含两张表记录的新行,并将新行添加到结果集中
- 如果不相等,只创建只包含左表记录,右边记录全部为
NULL
的新行,并将新行添加到结果集中
LEFT JOIN
是LEFT OUTER JOIN
的简写
LEFT JOIN
是 LEFT OUTER JOIN
的简写
右外连接
- 和左外连接原理相同
- 只是以右表的记录为准,对右表选择数据,如果左表有相等的记录则包含左表数据;反则则只包含右表数据,左表为
NULL
全外连接
SELECT
a,
fruit_a,
b,
fruit_b
FROM
basket_a
FULL OUTER JOIN basket_b
ON fruit_a = fruit_b;
交叉连接
- 没有
ON
指定条件 - 这是一个非常耗费资源的操作
SELECT 字段列表 FROM t1 CROSS JOIN t1;
-- 等价于
SELECT 字段列表 FROM t1,t2;
-- 使用INNER JOIN模拟:ON的条件始终为真
SELECT 字段列表 FROM t1 INNER JOIN t2 ON 1=1;
自然连接
基于连接表中,相同字段名创建的隐式连接。
SELECT 字段列表 FROM t1 NATURAL [INNER, LEFT, RIGHT] JOIN t2;
SELECT * FROM city NATURAL INNER JOIN country;
- 预期将隐式使用两个表中的同名字段
country_id
进行连接 - 实际结果确是空结果,原因是两个表中还有一个同名字段
last_update
自连接
所谓自连接,是指连接两方都是同一张表,常用应用场景是父子分类。
SELECT FROM 字段列表 FROM 表 AS t1 INNER JOIN 表 AS t2 ON t1.字段名1 = t2.字段名2;
示例:
CREATE TABLE employee (
employee_id INT PRIMARY KEY,
first_name VARCHAR (255) NOT NULL,
last_name VARCHAR (255) NOT NULL,
manager_id INT,
FOREIGN KEY (manager_id)
REFERENCES employee (employee_id)
ON DELETE CASCADE
);
INSERT INTO employee (
employee_id,
first_name,
last_name,
manager_id
)
VALUES
(1, 'Windy', 'Hays', NULL),
(2, 'Ava', 'Christensen', 1),
(3, 'Hassan', 'Conner', 1),
(4, 'Anna', 'Reeves', 2),
(5, 'Sau', 'Norman', 2),
(6, 'Kelsie', 'Hays', 3),
(7, 'Tory', 'Goff', 3),
(8, 'Salley', 'Lester', 3);
SELECT
e.first_name || ' ' || e.last_name AS employee,
m.first_name || ' ' || m.last_name AS manager
FROM
employee AS e
INNER JOIN employee AS m ON m.employee_id = e.manager_id
ORDER BY manager;