安装 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 常用函数进行汇总,包括:聚合函数、日期时间函数、字符串函数和数学函数。对于窗口函数,我们将在高级篇进行介绍。
条件表达式和运算符
- 271
- 2023-07-31 07:46:41
本章将讨论 PostgreSQL 条件表达式和运算符,包括:使用 CASE
构造条件查询、使用 COALESCE
过滤非空参数、使用 NULLIF
处理 NULL
值以及使用 CAST
进行数据类型转换。
CASE
CASE
和其它编程语言中的 IF/ELSE
相当:用于构造条件查询。它是一个表达式,因此可以在任何使用表达式的地方使用它,比如:SELECT
、WHERE
、GROUP BY
和 HAVING
。
它有两种形式:通用形式和简单形式。
通用形式
CASE
的通用形式的语法如下 :
CASE
WHEN 条件1 THEN 结果1
WHEN 条件2 THEN 结果2
[WHEN ...]
[ELSE 其它结果]
END
- 如果没有提供
ELSE
,则返回NULL
示例:根据时长返回不同的时长说明
SELECT title,
length,
CASE
WHEN length> 0
AND length <= 50 THEN '短视频'
WHEN length > 50
AND length <= 120 THEN '中等长度'
WHEN length> 120 THEN '长视频'
END AS duration
FROM film
ORDER BY title;
示例二:结合聚合函数返回影片租金的说明
SELECT
SUM (CASE
WHEN rental_rate = 0.99 THEN 1
ELSE 0
END
) AS "经济型",
SUM (
CASE
WHEN rental_rate = 2.99 THEN 1
ELSE 0
END
) AS "大众型",
SUM (
CASE
WHEN rental_rate = 4.99 THEN 1
ELSE 0
END
) AS "精英型"
FROM
film;
简单形式
PostgreSQL 提供了另一种称为”简单形式“的 CASE
:
CASE 表达式
WHEN 值1 THEN 结果1
WHEN 值2 THEN 结果2
[WHEN ...]
ELSE
其它结果
END
- 首先计算
表达式
的值 - 然后将这个值分别与每个
WHEN
进行对比,如果等于某个WHEN
值,就返回对应的结果。比如,如果等于值1
就返回结果1
- 如果所有的
WHEN
都不满足表达式
的值,则返回ELSE
后面的其它结果
。如果没有提供ELSE
,则返回NULL
SELECT title,
rating,
CASE rating
WHEN 'G' THEN '一般观众'
WHEN 'PG' THEN '建议家长指导'
WHEN 'PG-13' THEN '家长强烈警告'
WHEN 'R' THEN '受限制的'
WHEN 'NC-17' THEN '仅限成年人'
END rating_description
FROM film
ORDER BY title;
示例二:结合聚合函数返回评级说明:
SELECT
SUM(CASE rating
WHEN 'G' THEN 1
ELSE 0
END) "一般观众",
SUM(CASE rating
WHEN 'PG' THEN 1
ELSE 0
END) "建议家长指导",
SUM(CASE rating
WHEN 'PG-13' THEN 1
ELSE 0
END) "家长强烈警告",
SUM(CASE rating
WHEN 'R' THEN 1
ELSE 0
END) "受限制的",
SUM(CASE rating
WHEN 'NC-17' THEN 1
ELSE 0
END) "仅限成年人"
FROM film;
COALESCE
该函数接收不限个数的参数,返回第一个不为空(NULL
)的参数的值。如果所有参数均为 NULL
,则函数也返回 NULL
。一旦发现非空参数,直接返回该参数的值,而不再处理后面的参数。
它和 MySQL 的 IFNULL
函数的功能相同。
SELECT
COALESCE (1, 2);
-- 结果为:1
SELECT
COALESCE (NULL, 2 , 1);
-- 结果为:2
CREATE TABLE items (
ID serial PRIMARY KEY,
product VARCHAR (100) NOT NULL,
price NUMERIC NOT NULL,
discount NUMERIC
);
INSERT INTO items (product, price, discount)
VALUES
('A', 1000 ,10),
('B', 1500 ,20),
('C', 800 ,5),
('D', 500, NULL);
SELECT
product,
(price - discount) AS net_price
FROM
items;
结果并不正确,因为产品D
的折扣是 NULL
,而【万恶】的 NULL
无论参与何种运算,结果都是 NULL
。
我们进行改良,如果折扣为 NULL
,那就设置为 0
:
SELECT
product,
(price - COALESCE(discount,0)) AS net_price
FROM
items;
结果终于正确了。
我们可以使用 CASE
来模拟上面的 COALESCE
:
SELECT
product,
(
price - CASE
WHEN discount IS NULL THEN
0
ELSE
discount
END
) AS net_price
FROM
items;
NULLIF
语法:
NULLIF(参数1,参数2);
如果两个参数的值相等,返回 NULL
;否则返回 参数1
比如:
SELECT
NULLIF (1, 1); -- 返回 NULL
SELECT
NULLIF (1, 0); -- 返回 1
SELECT
NULLIF ('A', 'B'); -- 返回 A
示例数据:
CREATE TABLE posts (
id serial primary key,
title VARCHAR (255) NOT NULL,
excerpt VARCHAR (150),
body TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP
);
INSERT INTO posts (title, excerpt, body)
VALUES
('test post 1','test post excerpt 1','test post body 1'),
('test post 2','','test post body 2'),
('test post 3', null ,'test post body 3');
SELECT
id,
title,
COALESCE (
NULLIF (excerpt, ''),
LEFT (body, 40)
)
FROM
posts;
示例2:防止被零除
CREATE TABLE members (
ID serial PRIMARY KEY,
first_name VARCHAR (50) NOT NULL,
last_name VARCHAR (50) NOT NULL,
gender SMALLINT NOT NULL -- 1: 男, 2 女
);
INSERT INTO members (
first_name,
last_name,
gender
)
VALUES
('John', 'Doe', 1),
('David', 'Dave', 1),
('Bush', 'Lily', 2);
SELECT
(
SUM (
CASE
WHEN gender = 1 THEN
1
ELSE
0
END
) / NULLIF (
SUM (
CASE
WHEN gender = 2 THEN
1
ELSE
0
END
),
0
)
) * 100 AS "Male/Female ratio"
FROM
members;
CAST
CAST
用于将表达式的值转换为目标数据类型:
CAST(表达式 AS 目标数据类型);
PostgreSQL 提供了等价的 ::
运算符用于简化操作:
表达式::目标数据类型;
比如:
示例:
-- 将字符串转换成整数
SELECT '100'::INTEGER;
-- 将字符串转换成日期
SELECT '2023-07-31'::DATE;
-- 将字符串转换成浮点
SELECT '10.2'::FLOAT;
-- 将字符串转换成布尔
SELECT 'true'::BOOLEAN, 'false'::BOOLEAN, 'T'::BOOLEAN, 'NO'::BOOLEAN;
-- 将字符串转换成时间戳
SELECT '2019-06-15 12:32:43'::TIMESTAMP;
-- 将字符串转换成时间间隔
SELECT '15 minute'::interval,
'2 hour'::interval,
'1 day'::interval,
'2 week'::interval,
'3 month'::interval;