自连接是指在同一张表连接自身进行查询。是把自己和自己进行笛卡尔积,属于SQL中的一种技巧。
(用的不多,只是用来处理一些特殊场景的问题)
啥时候需要使用自连接?
SQL指定条件,都是按照列和列之间进行指定的。自连接的本质其实是把行和行之间的比较条件,转换成列和列
drop table if exists classes;
drop table if exists student;
drop table if exists course;
drop table if exists score;
create table classes (id int primary key auto_increment, name varchar(20), `desc` varchar(100));
create table student (id int primary key auto_increment, sn varchar(20), name varchar(20), qq_mail varchar(20) ,
classes_id int);
create table course(id int primary key auto_increment, name varchar(20));
create table score(score decimal(3, 1), student_id int, course_id int);
insert into classes(name, `desc`) values
('计算机系2019级1班', '学习了计算机原理、C和Java语言、数据结构和算法'),
('中文系2019级3班','学习了中国传统文学'),
('自动化2019级5班','学习了机械自动化');
insert into student(sn, name, qq_mail, classes_id) values
('09982','黑旋风李逵','[email protected]',1),
('00835','菩提老祖',null,1),
('00391','白素贞',null,1),
('00031','许仙','[email protected]',1),
('00054','不想毕业',null,1),
('51234','好好说话','[email protected]',2),
('83223','tellme',null,2),
('09527','老外学中文','[email protected]',2);
insert into course(name) values
('Java'),('中国传统文化'),('计算机原理'),('语文'),('高阶数学'),('英文');
insert into score(score, student_id, course_id) values
-- 黑旋风李逵
(70.5, 1, 1),(98.5, 1, 3),(33, 1, 5),(98, 1, 6),
-- 菩提老祖
(60, 2, 1),(59.5, 2, 5),
-- 白素贞
(33, 3, 1),(68, 3, 3),(99, 3, 5),
-- 许仙
(67, 4, 1),(23, 4, 3),(56, 4, 5),(72, 4, 6),
-- 不想毕业案列
(81, 5, 1),(37, 5, 5),
-- 好好说话
(56, 6, 2),(43, 6, 4),(79, 6, 6),
-- tellme
(80, 7, 2),(92, 7, 6);
案列1:
显示所有“计算机原理”成绩比“Java”成绩高的成绩信息
在这个问题中,可以看到,这里的条件是按照行的方式来排列的
这个问题下的表,不同科目之间已经不是列与列了,而是行与行
为了解决这个问题,就需要把行,给转换成列 把行转换成列,就可以用到"自连接".
按照student_id进行连接条件之后产生的笛卡尔积:(注意一个表进行自连接操作时需要用as设置别名才可以操作) ,如图所示:
select * from score as s1,score as s2 where s1.student_id=s2.student_id;
本来这里的70.5和98.5是同一列的两个行:
经过了笛卡尔积之后,已经分布到两个列中了:
但是当前这里的这两列,中间还是有着不少的无效数据的.为了能够更好的进行比较,需要再加上一些筛选条件;
比如,就让s1的课程id只保留3的记录,s2的课程id只保留1的记录 :
select * from score as s1,score as s2 where s1.student_id=s2.student_id and s1.course_id=1 and s2.course_id=3;
select s1.student_id,s1.score,s2.score from score as s1,score as s2 where s1.student_id=s2.student_id and s1.course_id=3 and s2.course_id=1 and s1.score>s2.score;
所以ID为1和3的同学“计算机原理”成绩比“Java”成绩高
自连接的关键就是能把行转换为列!
子查询是指嵌入在其他sql语句中的select语句,也叫嵌套查询(套娃查询)
相当于可以理解为后一条SQL语句的返回值作为前一条SQL语句的参数进行查询
select * from student where classes_id=(select classes_id from student where name='不想毕业');
--使用IN
select * from score where course_id in (select id from course where
name='语文' or name='英文');
-- 使用 NOT IN
select * from score where course_id not in (select id from course where
name!='语文' and name!='英文');
-- 插入重复的分数:score, student_id, course_id列重复
insert into score(score, student_id, course_id) values
-- 黑旋风李逵
(70.5, 1, 1),(98.5, 1, 3),
-- 菩提老祖
(60, 2, 1);
-- 查询重复的分数
SELECT
*
FROM
score
WHERE
( score, student_id, course_id ) IN ( SELECT score, student_id,
course_id FROM score GROUP BY score, student_id, course_id HAVING
count( 0 ) > 1 );
-- 使用 EXISTS
select * from score sco where exists (select sco.id from course cou
where (name='语文' or name='英文') and cou.id = sco.course_id);
-- 使用 NOT EXISTS
select * from score sco where not exists (select sco.id from course cou
where (name!='语文' and name!='英文') and cou.id = sco.course_id);
-- 获取“中文系2019级3班”的平均分,将其看作临时表
SELECT
avg( sco.score ) score
FROM
score sco
JOIN student stu ON sco.student_id = stu.id
JOIN classes cls ON stu.classes_id = cls.id
WHERE
cls.NAME = '中文系2019级3班';
查询成绩表中,比以上临时表平均分高的成绩:
SELECT
*
FROM
score sco,
(
SELECT
avg( sco.score ) score
FROM
score sco
JOIN student stu ON sco.student_id = stu.id
JOIN classes cls ON stu.classes_id = cls.id
WHERE
cls.NAME = '中文系2019级3班'
) tmp
WHERE
sco.score > tmp.score;
在实际应用中,为了合并多个select的执行结果,可以使用集合操作符 union,union all。使用UNION和UNION ALL时,前后查询的结果集中,字段需要一致。
select * from course where id<3
union
select * from course where name='英文';
-- 或者使用or来实现
select * from course where id<3 or name='英文';
-- 可以看到结果集中出现重复数据Java
select * from course where id<3
union all
select * from course where name='Java';
INSERT INTO table_name [(column [, column ...])] SELECT ...
select ... from 表1,表2 where 条件
-- inner可以缺省
select ... from 表1 join 表2 on 条件 where 其他条件
select ... from 表1 left/right join 表2 on 条件 where 其他条件
select ... from 表1,表1 where 条件
select ... from 表1 join 表1 on 条件
```sql
-- 单行子查询
select ... from 表1 where 字段1 = (select ... from ...);
-- [NOT] IN
select ... from 表1 where 字段1 in (select ... from ...);
-- [NOT] EXISTS
select ... from 表1 where exists (select ... from ... where 条件);
-- 临时表:form子句中的子查询
select ... from 表1, (select ... from ...) as tmp where 条件
-- UNION:去除重复数据
select ... from ... where 条件
union
select ... from ... where 条件
-- UNION ALL:不去重
select ... from ... where 条件
union all
select ... from ... where 条件
-- 使用UNION和UNION ALL时,前后查询的结果集中,字段需要一致
SQL查询中各个关键字的执行先后顺序: from > on> join > where > group by > with > having >
select > distinct > order by > limit
over