PostgreSQL 基础
表格属性
一般在 PostgreSQL 中以表格形式存储的数据,表格具有一定的属性维持其结构化:
- 表名:数据库中表名是唯一的
- 列 column:表中一个字段,且界定了该列的数据类型(该列的每一行的数据的类型需要相同)
- 行 row:每条数据按行存储
- 主键 primary key:表中每行数据的唯一标识,如订单 id,员工 id
常用语句
.sql
脚本由各种语句 clause 构成筛选条件,用以选择特定的数据,主要语句分为两类:
- 数据定义语言 Data Definition Language,一般操作表格元信息,用于创建、删除、修改、索引等
- 创建/删除新数据库
CREATE
/DROP DATABASE
- 修改数据库
ALTER DATABASE
- 创建/删除表
CREATE
/DROP TABLE
- 变更表
ALTER TABLE
- 创建/删除索引(搜索键)
CREATE
/DROP INDEX
- 创建/删除新数据库
- 数据操纵语言 Data Manipulation Language,一般操作表格数据,用于查询、插入、更新、删除数据等
- 从数据库表中获取数据
SELECT
- 更新数据库表中的数据
UPDATE
- 从数据库表中删除数据
DELETE
- 向数据库表中插入数据
INSERT INTO
- 从数据库表中获取数据
- 其他语句:判断、排序、分组、链接、函数处理等
数据定义语言
CREATE DATABASE
语句 CREATE DATABASE database_name
创建数据库 database_name
CREATE DATABASE c03_sql_stydy;
ALTER DATABASE
修改数据库元信息
-- 将数据库名字修改从 c03_sqlstudy 为 c03_sqlstudy_gai
ALTER DATABASE c03_sqlstudy RENAME TO c03_sqlstudy_gai;
-- 修改数据库所有者
ALTER DATABASE c03_sqlstudy OWNER TO u1;
Warning
不能修改当前激活的数据库元信息,如果需要修改当前数据库要先使用 psql 命令 \c database_name
切换到其他数据库
CREATE TABLE
创建表格时需要设置表格的字段(列),并规定每个字段的数据类型,字段之间用逗号 ,
分隔,这些设置使用括号 ()
包括。
-- 创建一个表格,表名为 company
-- 包括4个字段,每个字段都设置了数据类型
-- 第一个字段作为 PRIMARY KEY 即数据库表的主键约束
CREATE TABLE company(
No int PRIMARY KEY,
name text,
age int,
address text
);
Tip
设置字段时可以添加约束条件,常见的约束有
PRIMARY KEY
主键约束,1 个表中只有 1 个主键,该字段的数据每一行都是唯一的,而且不能有NULL
值(主键是数据的唯一标识符,即每行数据该字段的值都不同)UNIQUE
唯一约束,防止两个记录在 1 个特定的列具有相同的值NOT NULL
非空约束,该列不能有NULL
值CHECK
自定义条件约束,如果判断条件为 false 则该值不写入表格
CREATE TABLE company2(
No int PRIMARY KEY,
name text NOT NULL UNIQUE,
age int NOT NULL UNIQUE,
-- 限制字段 salary 的数据的值大于 0
salary numeric CHECK(salary>0)
);
ALTER TABLE
语句 ALTER TABLE
用于变更表格的属性,如表格的字段、修改字段的约束、修改字段的数据类型等。
- 添加新字段
ALTER TABLE table_name ADD column_name datatype
需要同时设置新增列的数据的类型 - 删除字段
ALTER TABLE table_name DROP COLUMN column_name
- 修改字段名称
ALTER TABLE table_name RENAME COLUMN column_name TO new_column_name
- 修改字段的数据类型
ALTER TABLE table_name ALTER COLUMN column_name TYPE datatype;
需结合语句ALTER COLUMN
指定变更的字段,语句TYPE
指定数据类型 - 设置字段约束,需结合语句
ADD CONSTRAINT
- 设置主键约束
ALTER TABLE table_name ADD CONSTRAINT MyPrimaryKey PRIMARY KEY (column1, column2...)
,其中MyPrimaryKey
称为主键索引,作为表格的主键「别名」,默认值是tableName_pkey
,可以设置任意值;需要使用语句PRIMARY KEY
,💡 主键在每个表格中只能设置 1 个,但是它可以由不同字段组合而成,只要这些组合值是唯一(即对于每一行数据而言,这个组合值都是不重复的) - 添加唯一约束
ALTER TABLE table_name ADD CONSTRAINT MyUniqueConstraint UNIQUE (column1, column2...)
,其中MyUniqueConstraint
作为约束名;需要使用语句UNIQUE
- 添加自定义约束
ALTER TABLE table_name ADD CONSTRAINT MyUniqueConstraint CHECK (CONDITION)
其中约束名为MyUniqueConstraint
;需要使用语句CHECK
Tip
设置非空约束所使用的语句不太一样
ALTER TABLE table_name ALTER COLUMN column_name SET NOT NULL
,取消非空约束则使用ALTER TABLE table_name ALTER COLUMN column_name DROP NOT NULL
- 设置主键约束
- 删除字段约束
ALTER TABLE table_name DROP CONSTRAINT constraint_name
,需要结合语句DROP
-- 添加新列
ALTER TABLE company ADD gender text;
-- 删除列
ALTER TABLE company DROP COLUMN gender;
-- 修改列的数据类型
ALTER TABLE company ALTER COLUMN No TYPE numeric;
-- 设置约束
-- 设置列为非空
ALTER TABLE company ALTER COLUMN age SET NOT NULL;
-- 删除非空设置
ALTER TABLE company ALTER COLUMN age DROP NOT NULL;
-- 添加主键primary key,这里可以是多个列,主键名称这里为'pkey'
ALTER TABLE company ADD CONSTRAINT pkey PRIMARY KEY (No,name);
-- 添加 UNIQUE 约束,这里添加约束名为 'ukey'
ALTER TABLE company ADD CONSTRAINT ukey UNIQUE (name);
-- 添加CHECK约束,这里约束名为'agecheck',约束条件为 age>0
ALTER TABLE company ADD CONSTRAINT agecheck CHECK (age > 0);
-- 删除约束条件
ALTER TABLE company DROP CONSTRAINT pkey; -- 删除主键 pkey
ALTER TABLE company DROP CONSTRAINT ukey; -- 删除UNIQUE约束 ukey
ALTER TABLE company DROP CONSTRAINT agecheck; -- 删除CHECK约束 agecheck
数据操纵语言
SELECT
语句 SELECT
用于查询数据,结合语句 FROM
以指明数据来源的表格。
- 查询表格的指定的单列/多列数据
SELECT column1, column2, columnN FROM table_name
- 查询表格的所有列数据
SELECT * FROM table_name
sql-- 读取表格 student 的所有列的数据 SELECT * FROM student; -- 读取表格 student 两列,分别为 no 列 和 studentname 列 SELECT no,studentname FROM student;
- 结合语句
LIMIT
限制展示的数据条数 - 结合语句
OFFSET
设置读取数据时(从头开始)偏移数量sql-- 显示 4 条数据 SELECT * FROM student LIMIT 4; -- 从第2条开始显示4条数据 SELECT * FROM student LIMIT 4 OFFSET 2;
- 结合语句
DISTINCT
筛选显示唯一值的数据sql-- 只显示 student 表格字段 age 中的唯一值 SELECT DISTINCT age FROM student;
- 结合语句
ORDER BY
对数据进行排序,默认按升序展示,可以添加关键字DESC
以降序排序Tip
支持基于多字段排序,字段的排序优先权限为从左到右
sql-- 按照年龄排序 SELECT * FROM student ORDER BY age; -- 按照年龄降序排列 SELECT * FROM student ORDER BY age DESC; -- 按照多字段排序 SELECT studentname,age,classno FROM student ORDER BY age,classno;
INSERT
语句 INSERT
用于插入数据(行数据)
可以指定插入的数据项填充哪些特定的字段(没有指定的字段就会使用 NULL
填充) INSERT INTO TABLE_NAME (column1, column2,...columnN) VALUES (value1, value2,...valueN)
Tip
支持同时插入多行数据,用逗号 ,
分隔
-- 表格 student 有 4 个字段
-- 在表格中插入一行数据,4 个字段都有相应的数据
INSERT INTO student VALUES(9, 'Ben', 18, 6);
-- 只插入3列字段的数据,缺失数据的字段对应的单元格用 NULL 填充
INSERT INTO student(no,studentname,classno) VALUES(10, 'Thomson', 8);
-- 多行插入数据
INSERT INTO student VALUES(11, 'Sam', 21, 8),(12, 'Candy', 17, 6),(13, 'Tom', 27, 6);
DELETE
语句 DELETE
删除数据(行数据),结合语句 FROM
指定从哪个表格删除数据
- 删除表格所有数据sql
-- 删除表格 student 中所有数据 DELETE FROM student;
- 结合语句
WHERE
对表格数据进行筛选,删除匹配的数据(行数据)sql-- 删除年龄大于 14 岁的学生数据 DELETE FROM student WHERE age > 14;
UPDATE
语句 UPDATE
更新数据(列数据),一般结合语句 WHERE
筛选需要更新的行
-- 将表格 student 中的所有行的字段 age 更新为 18
UPDATE student SET age = 18;
-- 使用 WHERE 筛选特定行更新其字段 age 为 26
UPDATE student SET age = 26 WHERE studentname = 'Ben';
数据运算
算术运算符
- 加法
5+5
- 减法
10-5
- 乘法
2*3
- 除法
10.0/3
- 取余数
10%7
- 幂
2^3
- 平方根
|/25.0
- 三次方根
||/27.0
- 阶乘
5!
比较运算符
- 等于
10 = 20
- 不等于
10 != 20
- 不等于
10 <> 20
- 小于
10 < 20
- 大于
10 > 20
- 小于等于
10 <= 20
- 大于等于
10 >= 20
数字处理函数
- 取绝对值
ABS(x)
- π
PI();
- 取平方根
SQRT(x)
- 四舍五入
ROUND(x)
默认修约到个位(整数),可以传递第二个参数设置保留的小数位数,如保留 3 位小数ROUND(1.24368, 3)
- 幂运算函数
POW(x, n)
如 2 的 3 次方POW(2, 3)
💡 对于底数为自然底数e
的幂运算使用另一个特有的函数EXP(n)
- 对数函数
LOG10(x)
返回基数为10的对数,参数需大于零 💡 如果是自然对数则使用LOG(x)
- 三角函数与反三角函数
SIN(x)
、ASIN(x)
、COS(x)
、ACOS(x)
、TAN(x)
、ATAN(x)
- 符号函数
SIGN(x);
返回参数的符号,值为负数、零或正数时分别返回-1
、0
或1
- 弧度与角度相互转换函数
- 将角度转换为弧度
RADIANS();
- 将弧度转换为角度
DEGREES()
- 将角度转换为弧度
- 最大值
MAX()
- 最小值
MIN()
- 计数
COUNT()
- 均值
AVG()
- 求和
SUM()
- 标准差
STDDEV()
- 生成数组
ARRAY_AGG(column_name) FROM table_name;
将表格特定字段的数据转换为数组形式,数组以花括号{}
包括,是另一种数据结构(与数据表格不同)
字符串操作
- 字符串连接,使用符号
'A'||'B'
或函数CONCAT(10,'a','hello',20.0);
(可同时连接多个字符串) - 转换成小写
LOWER('str')
- 转换成大写
UPPER('str')
- 每个单词的首字母大写
INITCAP('str'
- 替换字符串
SELECT REPLACE(str, target, replace);
在字符串str
中匹配target
子字符串,并将其替换为replace
字符串 - 返回给定子字符串在字符串的位置
POSITION(subStr IN str)
在字符串str
中查询子字符串subStr
索引位置 💡 索引从 1 开始 - 截取字符串
SUBSTRING(str FROM 3 FOR 10)
从FROM
位置开始,截取长度为FOR
- 删除字符串的头尾部空格
TRIM(' asd ')
该函数默认删除空格,但可以传递第二个参数以指定删除的字符,如TRIM('aaahelloworldaaa', 'a')
。
默认为BOTH
模式TRIM(BOTH ' asd ')
,即删除字符串两端的空格,但可以设置不同模式,仅删除其中一侧的空格- 删除头部空格
TRIM(LEADING ' asd ')
- 删除尾部空格
TRIM(TRAILING ' asd ')
- 删除头部空格
- 返回字符串中字符的个数
LENGTH('str')
如果字符串包含空格也算作字符 - 返回字符串前
n
个字符LEFT(str, n);
如果n
为负数时返回除最后|n|
个字符以外的所有字符 - 返回字符串后
n
个字符RIGHT(str, n)
如果n
为负数时返回除最前|n|
个字符意外的所有字符
Warning
在 SQL 中第一个位置的索引是 1,而很多编程语言的索引是从 0 开始。
数据类型转换
函数 CAST(expression AS target_type)
将数据转换为指定的数据类型,如将字符串转换为数值或日期(但字符串的值应该是 sql 可理解的)CAST(date_column AS DATE)
💡 可以使用简写方式 date_column::DATE
条件过滤
语句 WHERE
用于设置过滤条件筛选数据 SELECT column1, column2, columnN FROM table_name WHERE [search_condition]
筛选的条件语句可以使用多种操作符构造
=
等于<>
不等于 或!=
不等于>
大于<
小于>=
大于等于<=
小于等于!<
不小于!>
不大于
-- 筛选表格 student 字段 age 大于14岁的数据
SELECT * FROM student WHERE age>14;
还可以使用各种逻辑运算符构造复杂的组合条件
- 结合语句
AND
构造同时需要同时满足的多个条件 - 结合语句
OR
构建只需满足任意其一的条件sql-- 语句 AND 表示且,筛选出需要同时满足多个条件的数据 SELECT * FROM student WHERE age>14 AND classno <3; -- 语句 OR 表示或,筛选出只要满足任意条件即可的数据 SELECT * FROM student WHERE classno = 2 OR classno = 4;
- 针对含有/不含有空值
NULL
的数据项可以使用IS NULL
或IS NOT NULL
进行筛选sql-- 是否为空值 SELECT * FROM student WHERE age IS NOT NULL; SELECT * FROM student WHERE age IS NULL;
- 语句
IN
用来制定多个可匹配值(离散值),只要满足其中一个条件即成立Tip
相当于逻辑运算符
OR
sql-- 从表格 student 中筛选出班级为 3,4,5 的数据 SELECT * FROM student WHERE classno IN (3,4,5);
- 语句
BETWEEN
指定可匹配的值的范围(连续值)sql-- 从表格 student 中筛选出班级范围从 2 到 5 的数据 SELECT * FROM student WHERE classno BETWEEN 2 AND 5;
- 语句
NOT
筛选出满足否定条件的数据sql-- 筛选出年龄小于或等于 14 岁的数据 SELECT * FROM student WHERE NOT age>14;
- 模糊匹配十分常用,可以结合语句
LIKE
和通配符设置模糊匹配条件- 通配符
%
表示任意字符,出现任意次数包括 0次、1次、多次,但空值NULL
不能匹配 - 通配符
_
表示任意字符,但只出现1次
sql-- 匹配名字以 B 开头的数据 SELECT * FROM student WHERE studentname LIKE 'B%'; -- 匹配名字以 B 开头,且总共有 3 个字符的数据 SELECT * FROM student WHERE studentname LIKE 'B__';
- 通配符
数据分组
语句 GROUP BY
基于特定字段总不同值对数据项进行分组,然后可以得到关于不同组别的统计信息,如 COUNT
计数、AVG
均值、MAX
/MIN
最大值/最小值等。
Tip
注意语句的顺序 WHERE
-> GROUP BY
-> HAVING
-> ORDER BY
SELECT column-list FROM table_name
WHERE [ conditions ]
GROUP BY column1, column2
HAVING [ conditions ]
ORDER BY column1, column2;
Tip
语句 WHERE
和语句 HAVING
相似,都是对数据进行条件过滤,但是语句 WHERE
语句只能对分组前的字段进行分组(由于语句 WHERE
作用与分组前);而语句 HAVING
更「强大」,它不仅可以对「原始」字段进行筛选,还可以对分组后构成的新字段进行过滤(由于语句 HAVING
主要用于过滤分组):thumbsup: 推荐在分组中都使用语句 HAVING
进行数据项的过滤
-- 按照 classno 字段对表格 student 数据进行分组,并汇总各班的学生数量(汇总结果作为表格的新的字段)
SELECT classno, COUNT(studentname) FROM student GROUP BY classno;
-- 按照 classno 对表格 student 数据进行分组,并汇总各班的学生数量,汇总结果以(默认)降序排列展示
SELECT classno, COUNT(studentname) FROM student GROUP BY classno ORDER BY classno;
-- 使用 WHERE 过滤数据再进行分组
SELECT classno,COUNT(studentname) FROM student
WHERE classno > 2
GROUP BY classno; -- WHERE 作用与分组前,这里先筛选 classno>2 的数据,再分组
-- 注意,这里如果书写:WHERE COUNT(studentname) > 1 就会报错
-- 使用 HAVING 过滤分组
SELECT classno,COUNT(studentname) FROM student
GROUP BY classno
HAVING COUNT(studentname) > 1; -- HAVING 主要用于过滤分组,且是在分组后进行过滤
-- 所以一般对于分组的条件过滤都用 HAVING
数据连接
数据连接是基于特定字段将两个表格的数据进行匹配连接,即列的整合。
可以使用语句 WHERE
进行简单连接
-- 通过 WHERE 构建匹配逻辑
SELECT * FROM company3, department WHERE company3.no = department.id;
一般使用语句 JOIN
实现多种连接方式:
INNER JOIN
内连接(交集)LEFT OUTER JOIN
左连接(基于左表)RIGHT OUTER JOIN
右连接(基于右表)FULL OUTER JOIN
全连接(并集)CROSS JOIN
交叉连接
以下演示连接方式时使用的两个表格
-- 表格 employees
CREATE TABLE employees(
id int PRIMARY KEY,
name text,
age int CHECK(age > 0),
address text,
salary numeric CHECK(salary > 0)
);
INSERT INTO employees VALUES
(1, '王大', 25, 'beijing', 10000),
(2, '张三', 25, 'beijing', 10000),
(3, '李四', 21, 'beijing', 15000),
(4, '李二', 28, 'shenzhen', 10000),
(5, '王五', 24, 'shanghai', 20000),
(6, '杨三', 19, 'shanghai', 15000),
(7, '张四', 22, 'shenzhen', 20000),
(8, '杨四', 20, 'beijing', 10000);
-- 表格 department
CREATE TABLE department(id int,dept text,fac_id int);
INSERT INTO department VALUES
(1, 'IT', 1),
(2, 'Engineering', 2),
(3, 'HR', 7),
(10, 'Market', 10);
# 两个表格的数据
# 表格 employees
id | name | age | address | salary
----+------+-----+----------+--------
1 | 王大 | 25 | beijing | 10000
2 | 张三 | 25 | beijing | 10000
3 | 李四 | 21 | beijing | 15000
4 | 李二 | 28 | shenzhen | 10000
5 | 王五 | 24 | shanghai | 20000
6 | 杨三 | 19 | shanghai | 15000
7 | 张四 | 22 | shenzhen | 20000
8 | 杨四 | 20 | beijing | 10000
(8 行记录)
# 表格 deparment
id | dept | fac_id
----+-------------+--------
1 | IT | 1
2 | Engineering | 2
3 | HR | 7
10 | Market | 10
(4 行记录)
Tip
除了可以连接两个表,技术上可以实现连接任意数量的表格,只需要将组合后得到的新的表格再与其他表格进行组合就可以(或者使用嵌套方式)。
-- 创建表格3
-- 表格 education
CREATE TABLE education(name text, edu text);
INSERT INTO education VALUES
('王大', '本科'),
('张三', '本科'),
('李四', '硕士'),
('李二', '本科'),
('王五', 'PHD'),
('杨三', '硕士'),
('张四', 'PHD'),
('杨四', '本科');
SELECT employees.id, employees.name, education.edu, employees.salary, department.dept
FROM (employees INNER JOIN education ON employees.name = education.name) -- 注意嵌套写法
FULL OUTER JOIN department ON employees.id = department.id;
🔨 执行结果
id | name | edu | salary | dept
----+------+------+--------+-------------
1 | 王大 | 本科 | 10000 | IT
2 | 张三 | 本科 | 10000 | Engineering
3 | 李四 | 硕士 | 15000 | HR
| | | | Market
6 | 杨三 | 硕士 | 15000 |
5 | 王五 | PHD | 20000 |
8 | 杨四 | 本科 | 10000 |
7 | 张四 | PHD | 20000 |
4 | 李二 | 本科 | 10000 |
(9 行记录)
Tip
连接时可以使用逻辑运算符 AND
或 OR
基于多个字段设置连接条件。
SELECT employees.id, employees.name, department.dept
FROM employees INNER JOIN department
ON employees.id = department.id
AND employees.id = department.fac_id;
🔨 执行结果
id | name | dept
----+------+-------------
1 | 王大 | IT
2 | 张三 | Engineering
(2 行记录)
INNER JOIN
一般将两个表格「连接」使用 INNER JOIN
内连接的方式,即只取指定字段中有相同值的数据项组合成一张表格,相当于取表格的交集数据。
-- 基于两个表格的 id 字段连接表格,取两个字段中值相同的数据项(交集)组成新的表格
-- 显示连接后表格的字段 employees.id, employees.name, department.dept
SELECT employees.id, employees.name, department.dept
-- 连接左表为 employees,右表为 department
FROM employees INNER JOIN department
-- 连接基于两个表格的 id 字段
ON employees.id = department.id;
🔨 执行结果
id | name | dept
----+------+-------------
1 | 王大 | IT
2 | 张三 | Engineering
3 | 李四 | HR
(3 行记录)
FULL OUTER JOIN
如果需要保留两个表格完整的数据可以使用 FULL OUTER JOIN
全连接,即指定字段中有相同值的数据项组合,未匹配的数据组合时产生的缺失值的单元格用 NULL
填充成一张表格,相当于取表格的并集数据。
SELECT employees.id, employees.name, department.dept
FROM employees FULL OUTER JOIN department
ON employees.id = department.id;
🔨 执行结果
id | name | dept
----+------+-------------
1 | 王大 | IT
2 | 张三 | Engineering
3 | 李四 | HR
| | Market
5 | 王五 |
8 | 杨四 |
6 | 杨三 |
4 | 李二 |
7 | 张四 |
(9 行记录)
LEFT OUTER JOIN
左连接 LEFT OUTER JOIN
是基于左表(即使用语句 FROM
指定的表格)的外连接,即保留左表的所有数据项,从右表中寻找相应的字段值匹配的数据项进行组合,如果左表中未能匹配的数据项在合并表中产生了缺失值单元格使用 NULL
填充。
SELECT employees.id,employees.name,department.dept
FROM employees LEFT OUTER JOIN department
ON employees.id = department.id;
🔨 执行结果
id | name | dept
----+------+-------------
1 | 王大 | IT
2 | 张三 | Engineering
3 | 李四 | HR
5 | 王五 |
8 | 杨四 |
6 | 杨三 |
4 | 李二 |
7 | 张四 |
(8 行记录)
RIGHT OUTER JOIN
右连接 RIGHT OUTER JOIN
作用与左连接一样,但是它是基于右表(即使用语句 JOIN
指定的表格)的外连接,即保留右表的所有数据项,从左表中寻找相应的字段值匹配的数据项进行组合,如果右表中未能匹配的数据项在合并表中产生了缺失值单元格使用 NULL
填充。
SELECT employees.id, employees.name, department.dept
FROM employees LEFT OUTER JOIN department
ON employees.id = department.id;
🔨 执行结果
id | name | dept
----+------+-------------
1 | 王大 | IT
2 | 张三 | Engineering
3 | 李四 | HR
| | Market
(4 行记录)
CROSS JOIN
交叉连接 CROSS JOIN
通过笛卡尔积的方式组合两个表格,即检索出/组合得到的行的数目为第一个表(左表)中的行数乘以第二个表(右表)中的行数,相当于将左表的每个数据项都按照右表复制一份。
SELECT employees.id, employees.name, department.dept
FROM employees CROSS JOIN department
ORDER BY employees.id;
🔨 执行结果
id | name | dept
----+------+-------------
1 | 王大 | IT
1 | 王大 | Engineering
1 | 王大 | HR
1 | 王大 | Market
2 | 张三 | IT
2 | 张三 | Engineering
2 | 张三 | HR
2 | 张三 | Market
3 | 李四 | IT
3 | 李四 | Engineering
3 | 李四 | HR
3 | 李四 | Market
4 | 李二 | IT
4 | 李二 | Engineering
4 | 李二 | HR
4 | 李二 | Market
5 | 王五 | IT
5 | 王五 | Engineering
5 | 王五 | HR
5 | 王五 | Market
6 | 杨三 | IT
6 | 杨三 | Engineering
6 | 杨三 | HR
6 | 杨三 | Market
7 | 张四 | IT
7 | 张四 | Engineering
7 | 张四 | HR
7 | 张四 | Market
8 | 杨四 | IT
8 | 杨四 | Engineering
8 | 杨四 | HR
8 | 杨四 | Market
(32 行记录)
数据合并
使用语句 UNION
进行数据合并。数据合并是指表格的数据进行「叠加」合并,即行的整合,因此需要合并的两个表格具有相同的列结构,即列数相同(列名可以不同,会基于第一个表格的列名为准)。
-- 组合两个或多个 SELECT 语句的结果,而不返回任何重复的行
SELECT column1 [, column2 ] FROM table1 [, table2 ] [WHERE condition]
UNION
SELECT column1 [, column2 ] FROM table1 [, table2 ] [WHERE condition]
以下演示数据合并使用的表格
# 表格 t1
id | value1
----+--------
1 | a
2 | b
3 | c
(3 行记录)
# 表格 t2,有一条数据项与表格 t1 相同
id | value2
----+--------
1 | a
4 | A
5 | B
6 | C
(4 行记录)
-- 合并表格 t1 和 表格 t2,即将两个表格按行与行整合
SELECT * FROM t1
UNION
SELECT * FROM t2;
🔨 执行结果
# 返回的组合表去除了重复数据
# 因此字段 value1 中值为 a 的数据项只有一个
id | value1
----+--------
6 | C
2 | b
5 | B
3 | c
1 | a
4 | A
(6 行记录)
Tip
数据合并时默认去除重复数据,如果希望保留所有数据(包括重复项)可以设置关键字 ALL
SELECT * FROM t1
UNION ALL
SELECT * FROM t2;
🔨 执行结果
id | value1
----+--------
1 | a
2 | b
3 | c
1 | a
4 | A
5 | B
6 | C
(7 行记录)
别名
使用语句 AS
可以创建表别名或字段别名,表别名一般使用单个小写字母,使得在其他语句中调用表格的字段时可以编写更少的代码,提高编程效率;字段别名可以作为显示结果中的表头名称,使输出的表格更具语义方便理解。
-- 列/字段别名
-- alias_name: 它指定分配给列的临时名称
SELECT column_name AS alias_name FROM table_name [conditions...];
-- 表别名
-- alias_name:它指定分配给表的临时名称
SELECT column1, column2.... FROM table_name AS alias_name [conditions...];
Tip
一般可以省略语句 AS
,直接在表/字段名称后设置别名,并用空格分隔。
动态表复制
使用语句 SELECT
查询获得的表格是临时创建的,并未保存在数据库中。如果需要保存查询获得的数据,可以使用语句 CREATE TABLE ... AS
结合查询语句 SELECT
动态地基于查询结果创建表格。
CREATE TABLE new_table_name AS
SELECT column_name FROM table_name [conditions...];
Warning
基于查询结果「复制」得到的动态表并不会拷贝原始表格具有的约束、注释和序列,它只是复制数据。如果拷贝表格的约束可以使用语句 LIKE
,但它只是基于特定原始表格创建一个具有相同约束(结构)的空表格,并没有拷贝数据
CREATE TABLE new_table_name (LIKE table_name);
临时表格
可能原始数据构成表格并不适用于直接进行数据分析,需要使用包含语句 WITH
的表达式 CTE,common table expression 创建临时公用表/通用表。
-- 每个 CTE 都需要设置别名 name_for_summary_data(它们通过别名来被使用)。
WITH name_for_summary_data AS (
SELECT column_name FROM table_name [codition...])
SELECT columns
FROM name_for_summary_data [codition...]
Warning
需要在查询的开头定义所有的 CTE,然后在脚本其他地方就可以多次复用这些临时表格。
-- 先筛选出 companyname 为 c1 数据并构建临时表 t
-- 临时表 t 并不会存储于数据库中
WITH t AS (
SELECT companyname, city, client FROM w1
WHERE companyname = 'c1')
-- 再基于临时表 t 进行数据处理
SELECT SUM(client) FROM t; -- 等价于 SELECT SUM(client) FROM w1 WHERE companyname = 'c1';
可以将临时表格作为数据「中转站」对表格数据进行拆分
WITH t AS (
DELETE FROM w1 WHERE client < 2000 -- 将表格 w1 中客户数小于 200 的数据项删除
RETURNING * ) -- 并使用 RETURNING 子句返回数据,存放在临时表格 t 中
-- 创建空表 w2 用于接收临时表格的数据
-- 其结构需要与 w1 相同
CREATE TAbLE w2(id int PRIMARY KEY, companyname text, city text, client int);
-- 将临时表格的数据插入新建的表格 w2 中
-- 实现了按条件将数据从表格 w1 移动到表格 w2 中
INSERT INTO w2(SELECT * FROM t);