Bootstrap

一些SQL练习题的体会


SQL语句的报错汇总

相关的表内容如下:
在这里插入图片描述
在这里插入图片描述

1052 - Column ‘xxx’ in IN/ALL/ANY subquery is ambiguous

题目:查询" 01 “课程⽐” 02 "课程成绩⾼的学⽣的信息及课程分数

出错的情况:

select student.SId,student.Sname,student.Sage,student.Ssex,s3.CId,s3.score
from student 
where SId in 
	(select s1.SId 
	from sc as s1 
	INNER JOIN sc as s2 on s1.SId=s2.SId 
	where s1.score>s2.score and s1.CId=1 and s2.CId=2) and s3.CId in (1,2);
select student.SId,student.Sname,student.Sage,student.Ssex,s3.CId,s3.score
from student 
inner join sc as s3 on student.SId=s3.SId 
where SId in 
	(select s1.SId 
	from sc as s1 
	INNER JOIN sc as s2 on s1.SId=s2.SId 
	where s1.score>s2.score and s1.CId=1 and s2.CId=2) and s3.CId in (1,2);

第一部分的SQL语句是没有报错的,只是没有返回题目要求的课程分数信息
在试图加上分数时改写成了第二部分的SQL语句,结果报错,错误信息为

> 1052 - Column 'SId' in IN/ALL/ANY subquery is ambiguous
> 时间: 0s

原因:sc表与student表中都有SId字段,这时候where子句里的SId如果不加表名
SQL无法判断该字段属于哪个表,只要加上表名.字段名即可

select student.SId,student.Sname,student.Sage,student.Ssex,s3.CId,s3.score
from student 
inner join sc as s3 on student.SId=s3.SId 
where student.SId and s3.SId in 
	(select s1.SId 
	from sc as s1 
	INNER JOIN sc as s2 on s1.SId=s2.SId 
	where s1.score>s2.score and s1.CId=1 and s2.CId=2) and s3.CId in (1,2);

1248 - Every derived table must have its own alias

原因:如同字面意思,子查询产生的表必须要有一个名字,否则报错

(select sc.cid,round(avg(sc.score),2) as avg_sc 
from sc 
group by cid 
order by avg_sc desc) as b

子查询与联结查询

上文有提到过,子查询的效率是最低的,因此应该尽量替换成效果相同的联结查询

select stu.* from student as stu
where SId in 
	(select SId from sc where CId in 
		(select TId from teacher where Tname="张三")
	);
select stu.* from student as stu
inner join sc on stu.SId=sc.SId
inner join teacher on sc.CId=teacher.TId and Tname="张三";

外部联结的注意事项

使用left join … on …时,如果像第一段代码这样加where,结果是联结完的表进行筛选
这样一来,left join失去了意义,student表里的学生信息不会完全显示

select stu.SId,stu.Sname,sc2.score as CId1,sc3.score as CId2,sc4.score as CId3,
round(avg(sc1.score),2) as avg_score
from student as stu
left join sc as sc1 on stu.SId=sc1.SId
left join sc as sc2 on stu.SId=sc2.SId
left join sc as sc3 on stu.SId=sc3.SId
left join sc as sc4 on stu.SId=sc4.SId
where sc2.CId=1 and sc3.CId=2 and sc4.CId=3
group by SId order by avg_score desc;

在这里插入图片描述

为了让student表里的学生信息完全显示,建议使用left join … on … and …

select stu.SId,stu.Sname,sc2.score as CId1,sc3.score as CId2,sc4.score as CId3,
round(avg(sc1.score),2) as avg_score
from student as stu
left join sc as sc1 on stu.SId=sc1.SId
left join sc as sc2 on stu.SId=sc2.SId and sc2.CId=1
left join sc as sc3 on stu.SId=sc3.SId and sc3.CId=2
left join sc as sc4 on stu.SId=sc4.SId and sc4.CId=3
group by SId order by avg_score desc;

在这里插入图片描述


UNION联合查询的注意事项

使用union做联合查询时,只可以在结尾的select语句添加group by,order by等子句
为了避开SQL语法上的这个格式,可以使用以下的方法应对这个问题

select * from
(select sid,cid,score from sc 
group by sid,cid having cid=1 
order by score desc limit 3) as s1
union
select * from
(select sid,cid,score from sc 
group by sid,cid having cid=2 
order by score desc limit 3) as s2
union
select * from
(select sid,cid,score from sc 
group by sid,cid having cid=3 
order by score desc limit 3) as s3;

即把分好组排完序的表,用作子查询并起名为新表,再用union把这三个select联合查询

(select sid,cid,score from sc 
group by sid,cid having cid=1 
order by score desc limit 3)
union
(select sid,cid,score from sc 
group by sid,cid having cid=2 
order by score desc limit 3)
union
(select sid,cid,score from sc 
group by sid,cid having cid=3 
order by score desc limit 3);

in的技巧

当where里的条件字段与某个表中的字段相同时,可以将条件字段括起来这样写

select * from zhubo 
where (zhubo_id,level) in (select zhubo_id,max(level) from zhubo group by zhubo_id);

如果不用这个技巧的笨重写法或许是这样写的

select * from zhubo 
where zhubo_id in (select zhubo_id from zhubo group by zhubo_id) and
level in (select max(level) from zhubo group by zhubo_id);

as的注意事项

as用于给表起别名,可以用来简化SQL语句。不过需要注意,如果给某个表起了别名,再用回原来的名字去查找字段是不行的


SQL语句中的行转列

SQL查询里的行转列并不复杂,不过需要用到case when

class_idgraderate
1primary70%
1middle65%
1high72%
2primary69%
2middle63%
2high74%
class_idprimarymiddlehigh
170%65%72%
269%63%74%
select class_id,
max(CASE WHEN grade = 'primary' THEN rate ELSE 0 END) as 'primary',
max(CASE WHEN grade = 'middle' THEN rate ELSE 0 END) as 'middle',
max(CASE WHEN grade = 'high' THEN rate ELSE 0 END) as 'high'
from mst_class
group by class_id;

update语句里嵌入select

update语句里是可以写子查询语句的

UPDATE usrinfo 
set age=(select age from test where username="aaa") 
where username="aaa";

但是这个子查询语句是不可以从update的这张表里进行查询的
如果子查询里涉及到联结update的这张表会出现错误,因此需要其他的写法

update mst_b as up,(
    select mst_a.key,mst_a.value from mst_a join mst_b on mst_a.key = mst_b.key
    ) as b
set up.value = b.value where up.key = b.key

MySQL里update是可以对多个表进行更改的,利用这一点,可以将子查询的表拽入
用于实现某些复杂的联结查询与表更改的需求


;