From 5c247c03c352a34cbda1828068d54911fa45e31f Mon Sep 17 00:00:00 2001 From: pengshiyu <1940607002@qq.com> Date: Fri, 1 Apr 2022 22:36:10 +0800 Subject: [PATCH] fix --- blog/php-mysql/sql-join.md | 363 ++++++++++++++++++++++++++++++++++++- 1 file changed, 360 insertions(+), 3 deletions(-) diff --git a/blog/php-mysql/sql-join.md b/blog/php-mysql/sql-join.md index 762f8a3..6e57bfb 100644 --- a/blog/php-mysql/sql-join.md +++ b/blog/php-mysql/sql-join.md @@ -9,9 +9,366 @@ - 交叉连接 - 内连接 - 外连接 - - 左外链接(左连接) - - 右外连接(右连接) + - 左外链接(左连接) + - 右外连接(右连接) - 自然连接 +## 2、交叉连接 + +将两张表的数据与另外一张表彼此交叉 + +### 2.1、原理 + +笛卡尔积 + +1. 从第一张表一次取出每一条数据 +2. 取出每一条记录之后,与另外一张表的全部记录挨个匹配 +3. 没有任何匹配条件,所有的结果都会保留 +4. 记录数=第一张表记录数 \* 第二张表记录数 +5. 字段数 = 第一张表字段数 + 第二章表字段数 + +### 2.2、基本语法 + +```sql +表1 cross join 表2; +``` + +```sql +mysql> select * from tb_teacher; ++--------+------+ +| name | age | ++--------+------+ +| Jack | 24 | +| Tom | 26 | +| Steve | NULL | +| 张三 | 23 | +| 张三 | 23 | ++--------+------+ +5 rows in set (0.00 sec) + +mysql> select * from my_student; ++----+--------+----------+------+--------+ +| id | name | class_id | age | gender | ++----+--------+----------+------+--------+ +| 1 | 刘备 | 1 | 18 | 2 | +| 2 | 李四 | 1 | 19 | 1 | +| 3 | 王五 | 2 | 20 | 2 | +| 7 | 张飞 | 2 | 21 | 1 | +| 8 | 关羽 | 1 | 22 | 2 | +| 9 | 曹操 | 1 | 20 | NULL | ++----+--------+----------+------+--------+ +6 rows in set (0.01 sec) + +mysql> select * from my_student cross join tb_teacher; ++----+--------+----------+------+--------+--------+------+ +| id | name | class_id | age | gender | name | age | ++----+--------+----------+------+--------+--------+------+ +| 1 | 刘备 | 1 | 18 | 2 | Jack | 24 | +| 1 | 刘备 | 1 | 18 | 2 | Tom | 26 | +| 1 | 刘备 | 1 | 18 | 2 | Steve | NULL | +| 1 | 刘备 | 1 | 18 | 2 | 张三 | 23 | +| 1 | 刘备 | 1 | 18 | 2 | 张三 | 23 | +| 2 | 李四 | 1 | 19 | 1 | Jack | 24 | +| 2 | 李四 | 1 | 19 | 1 | Tom | 26 | +| 2 | 李四 | 1 | 19 | 1 | Steve | NULL | +| 2 | 李四 | 1 | 19 | 1 | 张三 | 23 | +| 2 | 李四 | 1 | 19 | 1 | 张三 | 23 | +| 3 | 王五 | 2 | 20 | 2 | Jack | 24 | +| 3 | 王五 | 2 | 20 | 2 | Tom | 26 | +| 3 | 王五 | 2 | 20 | 2 | Steve | NULL | +| 3 | 王五 | 2 | 20 | 2 | 张三 | 23 | +| 3 | 王五 | 2 | 20 | 2 | 张三 | 23 | +| 7 | 张飞 | 2 | 21 | 1 | Jack | 24 | +| 7 | 张飞 | 2 | 21 | 1 | Tom | 26 | +| 7 | 张飞 | 2 | 21 | 1 | Steve | NULL | +| 7 | 张飞 | 2 | 21 | 1 | 张三 | 23 | +| 7 | 张飞 | 2 | 21 | 1 | 张三 | 23 | +| 8 | 关羽 | 1 | 22 | 2 | Jack | 24 | +| 8 | 关羽 | 1 | 22 | 2 | Tom | 26 | +| 8 | 关羽 | 1 | 22 | 2 | Steve | NULL | +| 8 | 关羽 | 1 | 22 | 2 | 张三 | 23 | +| 8 | 关羽 | 1 | 22 | 2 | 张三 | 23 | +| 9 | 曹操 | 1 | 20 | NULL | Jack | 24 | +| 9 | 曹操 | 1 | 20 | NULL | Tom | 26 | +| 9 | 曹操 | 1 | 20 | NULL | Steve | NULL | +| 9 | 曹操 | 1 | 20 | NULL | 张三 | 23 | +| 9 | 曹操 | 1 | 20 | NULL | 张三 | 23 | ++----+--------+----------+------+--------+--------+------+ +30 rows in set (0.00 sec) +``` + +### 2.3、应用 + +基本没有实际意义 + +等价于 + +```sql +select * from my_student, tb_teacher; +``` + +## 3、内连接 + +从一张表中取出所有的记录,去另外一张表中匹配,利用匹配条件进行匹配,成功则保留,失败则放弃 + +### 3.1、原理 + +1. 从第一张表中取出一条记录,然后去另外一张表中进行匹配 +2. 利用匹配条件进行匹配 +3. 匹配到则保留,继续向下匹配 +4. 匹配失败则放弃 + +### 3.2、基本语法 + +```sql +表1 inner join 表2 on 匹配条件 +``` + +```sql +create table my_class( + id int primary key auto_increment, + name varchar(10) not null +); + +insert into my_class (name) values ('一班'), ('二班'); + +mysql> select * from my_class; ++----+--------+ +| id | name | ++----+--------+ +| 1 | 一班 | +| 2 | 二班 | ++----+--------+ + +mysql> select * from my_student; ++----+--------+----------+------+--------+ +| id | name | class_id | age | gender | ++----+--------+----------+------+--------+ +| 1 | 刘备 | 1 | 18 | 2 | +| 2 | 李四 | 1 | 19 | 1 | +| 3 | 王五 | 2 | 20 | 2 | +| 4 | 张飞 | 2 | 21 | 1 | +| 5 | 关羽 | 1 | 22 | 2 | +| 6 | 曹操 | 1 | 20 | NULL | ++----+--------+----------+------+--------+ + +-- 如果内连接没有条件,其实就是交叉连接(笛卡尔积) +mysql> select * from my_student inner join my_class; ++----+--------+----------+------+--------+----+--------+ +| id | name | class_id | age | gender | id | name | ++----+--------+----------+------+--------+----+--------+ +| 1 | 刘备 | 1 | 18 | 2 | 1 | 一班 | +| 1 | 刘备 | 1 | 18 | 2 | 2 | 二班 | +| 2 | 李四 | 1 | 19 | 1 | 1 | 一班 | +| 2 | 李四 | 1 | 19 | 1 | 2 | 二班 | +| 3 | 王五 | 2 | 20 | 2 | 1 | 一班 | +| 3 | 王五 | 2 | 20 | 2 | 2 | 二班 | +| 4 | 张飞 | 2 | 21 | 1 | 1 | 一班 | +| 4 | 张飞 | 2 | 21 | 1 | 2 | 二班 | +| 5 | 关羽 | 1 | 22 | 2 | 1 | 一班 | +| 5 | 关羽 | 1 | 22 | 2 | 2 | 二班 | +| 6 | 曹操 | 1 | 20 | NULL | 1 | 一班 | +| 6 | 曹操 | 1 | 20 | NULL | 2 | 二班 | ++----+--------+----------+------+--------+----+--------+ +12 rows in set (0.00 sec) + +-- 表的设计,通常会有同名字段,通常使用`表名.字段`来保证唯一性 +mysql> select * from my_student inner join my_class on my_student.class_id = my_class.id; ++----+--------+----------+------+--------+----+--------+ +| id | name | class_id | age | gender | id | name | ++----+--------+----------+------+--------+----+--------+ +| 1 | 刘备 | 1 | 18 | 2 | 1 | 一班 | +| 2 | 李四 | 1 | 19 | 1 | 1 | 一班 | +| 3 | 王五 | 2 | 20 | 2 | 2 | 二班 | +| 4 | 张飞 | 2 | 21 | 1 | 2 | 二班 | +| 5 | 关羽 | 1 | 22 | 2 | 1 | 一班 | +| 6 | 曹操 | 1 | 20 | NULL | 1 | 一班 | ++----+--------+----------+------+--------+----+--------+ + +-- 如果表名比较长,可以使用别名简化 +mysql> select * from my_student as a inner join my_class b on a.class_id = b.id; ++----+--------+----------+------+--------+----+--------+ +| id | name | class_id | age | gender | id | name | ++----+--------+----------+------+--------+----+--------+ +| 1 | 刘备 | 1 | 18 | 2 | 1 | 一班 | +| 2 | 李四 | 1 | 19 | 1 | 1 | 一班 | +| 3 | 王五 | 2 | 20 | 2 | 2 | 二班 | +| 4 | 张飞 | 2 | 21 | 1 | 2 | 二班 | +| 5 | 关羽 | 1 | 22 | 2 | 1 | 一班 | +| 6 | 曹操 | 1 | 20 | NULL | 1 | 一班 | ++----+--------+----------+------+--------+----+--------+ + +-- 可以交换两张表的先后顺序 +mysql> select * from my_class b inner join my_student as a on a.class_id = b.id; ++----+--------+----+--------+----------+------+--------+ +| id | name | id | name | class_id | age | gender | ++----+--------+----+--------+----------+------+--------+ +| 1 | 一班 | 1 | 刘备 | 1 | 18 | 2 | +| 1 | 一班 | 2 | 李四 | 1 | 19 | 1 | +| 2 | 二班 | 3 | 王五 | 2 | 20 | 2 | +| 2 | 二班 | 4 | 张飞 | 2 | 21 | 1 | +| 1 | 一班 | 5 | 关羽 | 1 | 22 | 2 | +| 1 | 一班 | 6 | 曹操 | 1 | 20 | NULL | ++----+--------+----+--------+----------+------+--------+ + +-- on 可以使用 where 替换,推荐使用 on +mysql> select * from my_class b inner join my_student as a where a.class_id = b.id; ++----+--------+----+--------+----------+------+--------+ +| id | name | id | name | class_id | age | gender | ++----+--------+----+--------+----------+------+--------+ +| 1 | 一班 | 1 | 刘备 | 1 | 18 | 2 | +| 1 | 一班 | 2 | 李四 | 1 | 19 | 1 | +| 2 | 二班 | 3 | 王五 | 2 | 20 | 2 | +| 2 | 二班 | 4 | 张飞 | 2 | 21 | 1 | +| 1 | 一班 | 5 | 关羽 | 1 | 22 | 2 | +| 1 | 一班 | 6 | 曹操 | 1 | 20 | NULL | ++----+--------+----+--------+----------+------+--------+ + +``` + +### 3.3、应用 + +内连接通常是在对数据有精确要求的地方使用,必须保证两张表中都能进行数据匹配,内连接匹配到才会保存 + +## 4、外连接 + +按照某一张表作为主表(表中所有记录在最后都会保留)根据条件取连接另外一张表,从而得到目标数据 + +外连接分为两种 + +- 左连接:左表是主表 +- 右连接:右表是主表 + +### 4.1、原理 + +1. 确定主表,左连接就是左边的表为主表,右连接就是右边的表为主表 +2. 拿主表的每一条记录,去匹配另外的一张表(从表)的每一条记录 +3. 如果满足匹配条件,保留,不满足即不保留 +4. 如果主表记录在从表中一条都没有匹配成功,那么也要保留记录, 从表对应的字段值都是null + + +### 4.2、基本语法 + +```sql +-- 左连接 +主表 left join 从表 on 连接条件; + +-- 右连接 +从表 right join 主表 on 连接条件; +``` + +左表的数据在前,右表的数据在后 + +```sql +mysql> select * from my_student; ++----+--------+----------+------+--------+ +| id | name | class_id | age | gender | ++----+--------+----------+------+--------+ +| 1 | 刘备 | 1 | 18 | 2 | +| 2 | 李四 | 1 | 19 | 1 | +| 3 | 王五 | 2 | 20 | 2 | +| 4 | 张飞 | 2 | 21 | 1 | +| 5 | 关羽 | 1 | 22 | 2 | +| 6 | 曹操 | 1 | 20 | NULL | ++----+--------+----------+------+--------+ + +mysql> select * from my_class; ++----+--------+ +| id | name | ++----+--------+ +| 1 | 一班 | +| 3 | 三班 | +| 2 | 二班 | ++----+--------+ + +mysql> select * from my_student as s left join my_class c on s.class_id = c.id; ++----+--------+----------+------+--------+------+--------+ +| id | name | class_id | age | gender | id | name | ++----+--------+----------+------+--------+------+--------+ +| 1 | 刘备 | 1 | 18 | 2 | 1 | 一班 | +| 2 | 李四 | 1 | 19 | 1 | 1 | 一班 | +| 3 | 王五 | 2 | 20 | 2 | 2 | 二班 | +| 4 | 张飞 | 2 | 21 | 1 | 2 | 二班 | +| 5 | 关羽 | 1 | 22 | 2 | 1 | 一班 | +| 6 | 曹操 | 1 | 20 | NULL | 1 | 一班 | ++----+--------+----------+------+--------+------+--------+ + + +select * from my_student as s right join my_class c on s.class_id = c.id; +mysql> select * from my_student as s right join my_class c on s.class_id = c.id; ++------+--------+----------+------+--------+----+--------+ +| id | name | class_id | age | gender | id | name | ++------+--------+----------+------+--------+----+--------+ +| 1 | 刘备 | 1 | 18 | 2 | 1 | 一班 | +| 2 | 李四 | 1 | 19 | 1 | 1 | 一班 | +| 3 | 王五 | 2 | 20 | 2 | 2 | 二班 | +| 4 | 张飞 | 2 | 21 | 1 | 2 | 二班 | +| 5 | 关羽 | 1 | 22 | 2 | 1 | 一班 | +| 6 | 曹操 | 1 | 20 | NULL | 1 | 一班 | +| NULL | NULL | NULL | NULL | NULL | 3 | 三班 | ++------+--------+----------+------+--------+----+--------+ +``` + +### 4.3、特点 + +外连接中主表的数据一定会保存,连接之后不会出现记录数少于主表(内连接可能少数据) + +左连接和右连接可以相互转换,但是数据对应的位置(字段顺序)会改变 + + +### 4.4、应用 + +获取对应主表以及其他数据(关联) + + +通常使用左连接 + + +## 5、using关键字 + +在连接查询中用来代替对应on关键字进行条件匹配 + +### 5.1、原理 + +1. 在连接查询时,使用on的地方用using代替 +2. 使用using的前提是对应的两张表连接的字段名是同名的(类似自然连接) +3. 如果使用using关键字,那么对应的同名字段,最后在结果中只会保留一个 + +### 5.2、基本语法 + +```sql +表1 [inner, left, right] join 表2 using (同名字段列表); +``` + +```sql +select * from my_student left join my_class using(class_id); + +-- 等价于 +select * from my_student left join my_class on my_student.class_id = my_class.class_id; +``` + +通常不使用 + + + + + + + + + + + + + + + + + + + + + +https://www.bilibili.com/video/BV1Vx411g7uJ?p=46&spm_id_from=pageDriver + -https://www.bilibili.com/video/BV1Vx411g7uJ?p=42&spm_id_from=pageDriver \ No newline at end of file -- GitLab