将两张表的数据与另外一张表彼此交叉
笛卡尔积:
表1 cross join 表2;
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)
基本没有实际意义
等价于
select * from my_student, tb_teacher;
从一张表中取出所有的记录,去另外一张表中匹配,利用匹配条件进行匹配,成功则保留,失败则放弃
表1 inner join 表2 on 匹配条件
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 | +----+--------+----+--------+----------+------+--------+
内连接通常是在对数据有精确要求的地方使用,必须保证两张表中都能进行数据匹配,内连接匹配到才会保存
按照某一张表作为主表(表中所有记录在最后都会保留)根据条件取连接另外一张表,从而得到目标数据
外连接分为两种:
-- 左连接 主表 left join 从表 on 连接条件; -- 右连接 从表 right join 主表 on 连接条件;
左表的数据在前,右表的数据在后
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 | 三班 | +------+--------+----------+------+--------+----+--------+
外连接中主表的数据一定会保存,连接之后不会出现记录数少于主表(内连接可能少数据)
左连接和右连接可以相互转换,但是数据对应的位置(字段顺序)会改变
获取对应主表以及其他数据(关联)
通常使用左连接
在连接查询中用来代替对应on关键字进行条件匹配
表1 [inner, left, right] join 表2 using (同名字段列表);
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;
这个方法通常不使用