上一篇的增删改查和基础筛选操作
[SQL系列] 从头开始学PostgreSQL 增删改查_Edward.W的博客-CSDN博客https://blog.csdn.net/u013379032/article/details/131775853这篇大多是基于单张表的一些简单操作,但是我们经常要操作多张表一起查询,有些表的位置还必须要有限制,那怎么办呢?今天还是一起来学习学习。
约束
PostgreSQL的约束是用于规定表中的数据规则,如果违反了这个规则,行为就会被约束终止。
约束是针对表存在的,一般在建表和修改的时候规定,这样可以确保数据库中数据的准确性和可靠性。
一般有这些约束:
1. NOT NULL:用于保证表中某一列的值不为空。
sql
CREATE TABLE my_table (
id SERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL
);
上面的句子使用了NOT NULL约束,插入数据的时候name不能为空。以下是一个反例:
sql
INSERT INTO my_table (name, id) VALUES (NULL, 30);
这个插入语句将被拒绝,因为"name"字段不能为空。
2. UNIQUE:用于保证表中某一列的值唯一。
sql
CREATE TABLE my_table (
id SERIAL PRIMARY KEY,
name VARCHAR(255) UNIQUE NOT NULL
);
反例:
sql
INSERT INTO my_table(name, id) VALUES ('Alice', 30);
INSERT INTO my_table (name, id) VALUES ('Alice', 35);
第二个插入语句将被拒绝,因为"name"字段的值已经存在,不能重复插入。
3. PRIMARY KEY:用于定义表的主键,保证表中每条记录的唯一性。
sql
CREATE TABLE my_table (
id SERIAL PRIMARY KEY,
name VARCHAR(255)
);
反例:
sql
CREATE TABLE my_table (
id SERIAL PRIMARY KEY,
name VARCHAR(255) PRIMARY KEY
);
这个建表的时候就会出错,因为出现了两个primary key。
4. FOREIGN KEY:用于定义表之间的关系,保证数据的一致性和完整性。
sql
CREATE TABLE my_table (
id SERIAL PRIMARY KEY,
parent_id INTEGER NOT NULL REFERENCES another_table(id)
);
反例:在another_table里面插入一条记录
sql
INSERT INTO another_table (id) VALUES (1);
并且插入到my_table表
sql
INSERT INTO my_table(parent_id) VALUES (1);
这时候,如果删除another__table的记录的话:
sql
DELETE FROM another_table WHERE id = 1;
那么"foreign_key_example"表中的记录也将被自动删除。
5. CHECK:用于限制某一列的取值范围。
sql
CREATE TABLE my_table (
id SERIAL PRIMARY KEY,
age INTEGER CHECK (age > 0 AND age < 100)
);
反例:
sql
INSERT INTO my_table(age) VALUES (-1);
这个插入语句将被拒绝,因为"age"字段的值不满足 CHECK 约束的条件
6. DEFAULT:用于定义某一列的默认值。
sql
ALTER TABLE my_table ALTER COLUMN name SET DEFAULT 'unknown';
反例:
sql
insert into my_table(name) value (NULL);
这个插入语句将插入一条记录,其中"name"字段的值为"unknown",因为"name"字段没有提供值,所以使用默认值。
连接
连接就是把两个表或者多个表结合起来,基于表共同的字段进行连接。
总共有以下几种连接:
内部连接(inner join) 全连接(full join) 左连接(left join) 右连接(right join) 交叉连接(cross join)
准备数据:
sql
CREATE TABLE classes (
id SERIAL PRIMARY KEY,
name VARCHAR(50) NOT NULL UNIQUE
);
CREATE TABLE students (
id SERIAL PRIMARY KEY,
name VARCHAR(50) NOT NULL UNIQUE,
age INT NOT NULL,
gender VARCHAR(10) NOT NULL,
class_id INTEGER NOT NULL REFERENCES classes(id)
);
INSERT INTO classes (name) VALUES ('班级 1');
INSERT INTO classes (name) VALUES ('班级 2');
INSERT INTO classes (name) VALUES ('班级 3');
INSERT INTO classes (name) VALUES ('班级 4');
INSERT INTO classes (name) VALUES ('班级 5');
INSERT INTO classes (name) VALUES ('班级 6');
INSERT INTO classes (name) VALUES ('班级 7');
INSERT INTO classes (name) VALUES ('班级 8');
INSERT INTO classes (name) VALUES ('班级 9');
INSERT INTO classes (name) VALUES ('班级 10');
INSERT INTO students (name, age, gender, class_id) VALUES ('张三', 18, '男', 1);
INSERT INTO students (name, age, gender, class_id) VALUES ('李四', 19, '女', 1);
INSERT INTO students (name, age, gender, class_id) VALUES ('王五', 20, '男', 2);
INSERT INTO students (name, age, gender, class_id) VALUES ('赵六', 18, '女', 2);
INSERT INTO students (name, age, gender, class_id) VALUES ('陈七', 19, '男', 3);
INSERT INTO students (name, age, gender, class_id) VALUES ('孙八', 20, '女', 3);
INSERT INTO students (name, age, gender, class_id) VALUES ('周九', 18, '男', 4);
INSERT INTO students (name, age, gender, class_id) VALUES ('吴十', 19, '女', 4);
INSERT INTO students (name, age, gender, class_id) VALUES ('郑十一', 20, '男', 5);
INSERT INTO students (name, age, gender, class_id) VALUES ('王十二', 18, '女', 5);
cross join (交叉连接)
交叉连接(CROSS JOIN)把第一个表的每一行与第二个表的每一行进行匹配。如果两个输入表分别有 x 和 y 行,则结果表有 x*y 行。
由于交叉连接(CROSS JOIN)有可能产生非常大的表,使用时必须谨慎,只在适当的时候使用它们。
sql
testdb=# SELECT * FROM classes CROSS JOIN students S;
id | name | id | name | age | gender | class_id
----+---------+----+--------+-----+--------+----------
1 | 班级 1 | 1 | 张三 | 18 | 男 | 1
1 | 班级 1 | 2 | 李四 | 19 | 女 | 1
1 | 班级 1 | 3 | 王五 | 20 | 男 | 2
1 | 班级 1 | 4 | 赵六 | 18 | 女 | 2
1 | 班级 1 | 5 | 陈七 | 19 | 男 | 3
1 | 班级 1 | 6 | 孙八 | 20 | 女 | 3
1 | 班级 1 | 7 | 周九 | 18 | 男 | 4
1 | 班级 1 | 8 | 吴十 | 19 | 女 | 4
1 | 班级 1 | 9 | 郑十一 | 20 | 男 | 5
1 | 班级 1 | 10 | 王十二 | 18 | 女 | 5
2 | 班级 2 | 1 | 张三 | 18 | 男 | 1
2 | 班级 2 | 2 | 李四 | 19 | 女 | 1
2 | 班级 2 | 3 | 王五 | 20 | 男 | 2
2 | 班级 2 | 4 | 赵六 | 18 | 女 | 2
2 | 班级 2 | 5 | 陈七 | 19 | 男 | 3
2 | 班级 2 | 6 | 孙八 | 20 | 女 | 3
2 | 班级 2 | 7 | 周九 | 18 | 男 | 4
2 | 班级 2 | 8 | 吴十 | 19 | 女 | 4
2 | 班级 2 | 9 | 郑十一 | 20 | 男 | 5
2 | 班级 2 | 10 | 王十二 | 18 | 女 | 5
3 | 班级 3 | 1 | 张三 | 18 | 男 | 1
3 | 班级 3 | 2 | 李四 | 19 | 女 | 1
3 | 班级 3 | 3 | 王五 | 20 | 男 | 2
3 | 班级 3 | 4 | 赵六 | 18 | 女 | 2
3 | 班级 3 | 5 | 陈七 | 19 | 男 | 3
3 | 班级 3 | 6 | 孙八 | 20 | 女 | 3
3 | 班级 3 | 7 | 周九 | 18 | 男 | 4
3 | 班级 3 | 8 | 吴十 | 19 | 女 | 4
3 | 班级 3 | 9 | 郑十一 | 20 | 男 | 5
3 | 班级 3 | 10 | 王十二 | 18 | 女 | 5
4 | 班级 4 | 1 | 张三 | 18 | 男 | 1
4 | 班级 4 | 2 | 李四 | 19 | 女 | 1
4 | 班级 4 | 3 | 王五 | 20 | 男 | 2
4 | 班级 4 | 4 | 赵六 | 18 | 女 | 2
4 | 班级 4 | 5 | 陈七 | 19 | 男 | 3
4 | 班级 4 | 6 | 孙八 | 20 | 女 | 3
4 | 班级 4 | 7 | 周九 | 18 | 男 | 4
4 | 班级 4 | 8 | 吴十 | 19 | 女 | 4
4 | 班级 4 | 9 | 郑十一 | 20 | 男 | 5
4 | 班级 4 | 10 | 王十二 | 18 | 女 | 5
5 | 班级 5 | 1 | 张三 | 18 | 男 | 1
5 | 班级 5 | 2 | 李四 | 19 | 女 | 1
5 | 班级 5 | 3 | 王五 | 20 | 男 | 2
5 | 班级 5 | 4 | 赵六 | 18 | 女 | 2
5 | 班级 5 | 5 | 陈七 | 19 | 男 | 3
left join(左连接)
左连接是指将左表中的所有数据与右表中的数据进行匹配,如果右表中没有匹配的数据,则返回左表中的数据以及一个空值。左连接可以使用 left join 语句进行查询。
sql
testdb=# SELECT * FROM classes C LEFT JOIN students S ON S.class_id = C.id;
id | name | id | name | age | gender | class_id
----+---------+----+--------+-----+--------+----------
1 | 班级 1 | 1 | 张三 | 18 | 男 | 1
1 | 班级 1 | 2 | 李四 | 19 | 女 | 1
2 | 班级 2 | 3 | 王五 | 20 | 男 | 2
2 | 班级 2 | 4 | 赵六 | 18 | 女 | 2
3 | 班级 3 | 5 | 陈七 | 19 | 男 | 3
3 | 班级 3 | 6 | 孙八 | 20 | 女 | 3
4 | 班级 4 | 7 | 周九 | 18 | 男 | 4
4 | 班级 4 | 8 | 吴十 | 19 | 女 | 4
5 | 班级 5 | 9 | 郑十一 | 20 | 男 | 5
5 | 班级 5 | 10 | 王十二 | 18 | 女 | 5
10 | 班级 10 | | | | |
8 | 班级 8 | | | | |
6 | 班级 6 | | | | |
9 | 班级 9 | | | | |
7 | 班级 7 | | | | |
(15 rows)
right join(右连接)
右连接是指将右表中的所有数据与左表中的数据进行匹配,如果左表中没有匹配的数据,则返回右表中的数据以及一个空值。右连接可以使用 right join 语句进行查询。
sql
testdb=# SELECT * FROM classes C RIGHT JOIN students S ON S.class_id = C.id;
id | name | id | name | age | gender | class_id
----+--------+----+--------+-----+--------+----------
1 | 班级 1 | 1 | 张三 | 18 | 男 | 1
1 | 班级 1 | 2 | 李四 | 19 | 女 | 1
2 | 班级 2 | 3 | 王五 | 20 | 男 | 2
2 | 班级 2 | 4 | 赵六 | 18 | 女 | 2
3 | 班级 3 | 5 | 陈七 | 19 | 男 | 3
3 | 班级 3 | 6 | 孙八 | 20 | 女 | 3
4 | 班级 4 | 7 | 周九 | 18 | 男 | 4
4 | 班级 4 | 8 | 吴十 | 19 | 女 | 4
5 | 班级 5 | 9 | 郑十一 | 20 | 男 | 5
5 | 班级 5 | 10 | 王十二 | 18 | 女 | 5
(10 rows)
inner join(内连接)
内连接是连接的两个表中的数据进行匹配,如果匹配不到数据,则不返回结果。内连接可以使用 select 语句进行查询。
sql
testdb=# SELECT * FROM classes C inner JOIN students S ON S.class_id = C.id;
id | name | id | name | age | gender | class_id
----+--------+----+--------+-----+--------+----------
1 | 班级 1 | 1 | 张三 | 18 | 男 | 1
1 | 班级 1 | 2 | 李四 | 19 | 女 | 1
2 | 班级 2 | 3 | 王五 | 20 | 男 | 2
2 | 班级 2 | 4 | 赵六 | 18 | 女 | 2
3 | 班级 3 | 5 | 陈七 | 19 | 男 | 3
3 | 班级 3 | 6 | 孙八 | 20 | 女 | 3
4 | 班级 4 | 7 | 周九 | 18 | 男 | 4
4 | 班级 4 | 8 | 吴十 | 19 | 女 | 4
5 | 班级 5 | 9 | 郑十一 | 20 | 男 | 5
5 | 班级 5 | 10 | 王十二 | 18 | 女 | 5
(10 rows)
full join(全连接)
全连接是指将左表和右表中的所有数据进行匹配,如果左表或右表中没有匹配的数据,则返回空值。全连接可以使用 full outer join 语句进行查询。
sql
testdb=# SELECT * FROM classes C FULL JOIN students S ON S.class_id = C.id;
id | name | id | name | age | gender | class_id
----+---------+----+--------+-----+--------+----------
1 | 班级 1 | 1 | 张三 | 18 | 男 | 1
1 | 班级 1 | 2 | 李四 | 19 | 女 | 1
2 | 班级 2 | 3 | 王五 | 20 | 男 | 2
2 | 班级 2 | 4 | 赵六 | 18 | 女 | 2
3 | 班级 3 | 5 | 陈七 | 19 | 男 | 3
3 | 班级 3 | 6 | 孙八 | 20 | 女 | 3
4 | 班级 4 | 7 | 周九 | 18 | 男 | 4
4 | 班级 4 | 8 | 吴十 | 19 | 女 | 4
5 | 班级 5 | 9 | 郑十一 | 20 | 男 | 5
5 | 班级 5 | 10 | 王十二 | 18 | 女 | 5
10 | 班级 10 | | | | |
8 | 班级 8 | | | | |
6 | 班级 6 | | | | |
9 | 班级 9 | | | | |
7 | 班级 7 | | | | |
(15 rows)