安装 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 常用函数进行汇总,包括:聚合函数、日期时间函数、字符串函数和数学函数。对于窗口函数,我们将在高级篇进行介绍。
子查询
- 380
- 2023-07-30 06:10:14
本章我们将讨论如何使用 PostgreSQL 子查询来构建复杂的查询。同时会学习 IN
、EXISTS
、ANY
、SOME
、ALL
等操作。
子查询简介
假设我们想找到租金高于平均值的电影,可以分两步:
- 使用
SELECT
语句和AVG()
函数计算出平均值 - 使用第二个
SELECT
语句,并使用前一个语句计算的平均值来查找符合条件的电影。
这种方法不太优雅,利用子查询可以将其合并成一条 SQL 语句,一步实现:
SELECT
film_id, title, rental_rate
FROM
film
WHERE
rental_rate > (
SELECT AVG(rental_rate) FROM film
);
括号内的查询称为子查询,包含子查询的查询称为外部查询。PostgreSQL 按以下步骤执行包含子查询的查询:
- 首先,执行子查询
- 其它,获取子查询的结果,并将其传递给外部查询
- 第三,执行外部查询
带有 IN
运算符的子查询
比如,要查询 2005-05-29
~ 2005-05-30
的电影,可以使用以下查询:
SELECT
inventory.film_id
FROM
rental
INNER JOIN inventory ON inventory.inventory_id = rental.inventory_id
WHERE
return_date BETWEEN '2005-05-29'
AND '2005-05-30';
它的结果我们可以用作 WHERE
子句的子查询:
带有 EXISTS
运算符的子查询
EXISTS
的语法:
EXISTS 子查询
- 如果子查询返回一行及以上,则
EXISTS
运算符的结果为true
;否则为false
EXISTS
只关心子查询返回的行数,而不关心内容,所以它的常见编码约定是:EXISTS (SELECT 1 FROM 表名 WHERE 条件);
SELECT
first_name,
last_name
FROM
customer
WHERE
EXISTS (
SELECT
1
FROM
payment
WHERE
payment.customer_id = customer.customer_id
);
ANY
和SOME
运算符
ANY
运算符将一个值 与子查询返回的一组值进行比较:
表达式 运算符 ANY(子查询)
- 子查询必须有且只有一行结果返回。如果子查询不返回任何行,则整个查询将返回空结果集。
ANY
前面必须有以下比较运算符之一:=
、<=
、>
、<
、>=
或<>
- 如果子查询满足其中任意条件,
ANY
运算符的结果为true
;否则为false
SOME
是ANY
的同义词,可以在使用 SQL 语句中使用SOME
替换ANY
SOME
是 ANY
的同义词,可以在使用 SQL 语句中使用 SOME
替换 ANY
以下示例返回按影片类别分组的影响的最大片长:
SELECT
MAX( length )
FROM
film
INNER JOIN film_category
USING(film_id)
GROUP BY
category_id;
你可以将上面的查询作为子查询,查询片长大于或等于最大片长的影片:
SELECT title
FROM film
WHERE length >= ANY(
SELECT MAX( length )
FROM film
INNER JOIN film_category USING(film_id)
GROUP BY category_id );
ANY
与 IN
= ANY
相当于 IN
运算符。
比如,要查询分类为 Action
或 Drama
的电影,使用 = ANY
:
SELECT
title,
category_id
FROM
film
INNER JOIN film_category
USING(film_id)
WHERE
category_id = ANY(
SELECT
category_id
FROM
category
WHERE
NAME = 'Action'
OR NAME = 'Drama'
);
它和 IN
的结果一样:
SELECT
title,
category_id
FROM
film
INNER JOIN film_category
USING(film_id)
WHERE
category_id IN(
SELECT
category_id
FROM
category
WHERE
NAME = 'Action'
OR NAME = 'Drama'
);
<> ANY
和 NOT IN
并不一样
而 NOT IN
:
x NOT IN (a,b,c)
-- 相当于
x <> a AND x <> b AND x <> c
ALL
运算符
ALL
运算符的语法和ANY
运算符的语法类似,它的工作原理如下:
表达式 > ALL (子查询)
:如果表达式
某个值大于子查询返回的最大值,则结果为true
表达式 >= ALL (子查询)
:如果表达式
某个值大于等于子查询返回的最大值,则结果为true
表达式 < ALL (子查询)
:如果表达式
某个值小于子查询返回的最小值,则结果为true
表达式 <= ALL (子查询)
:如果表达式
某个值小于等于子查询返回的最小值,则结果为true
表达式 = ALL (子查询)
:如果表达式
某个值等于子查询返回的任何值,则结果为true
表达式 <> ALL (子查询)
:如果表达式
某个值不等于子查询返回的任何值,则结果为true
- 如果子查询不返回任何行,则
ALL
的计算结果永远为true
以下查询返回按电影评级分组的所有电影的平均时长:
SELECT
ROUND(AVG(length), 2) avg_length
FROM
film
GROUP BY
rating
ORDER BY
avg_length DESC;
要查询时长大于上述平均时长的电影,可以使用 > ALL
:
SELECT
film_id,
title,
length
FROM
film
WHERE
length > ALL (
SELECT
ROUND(AVG (length),2)
FROM
film
GROUP BY
rating
)
ORDER BY
length;