09-11:解题&子查询

SQL语句的解题顺序

  • 单表 or 多表
  1. 单表
    单表 是否需要分组,分组是否分组前需要条件where,分组后是否需要having
    where 范围 列表 模糊查询
    group by 后的字段 和select后一致,聚合函数除外
    having
    order
  1. 多表
    连接 or 子查询
    几张表的连接 顺序是什么 以要求的内容为主
    ...

解题09-10

  • 1.统计各部门男女人数,要求显示出部门名称
select d.name,t.sex,count(eid) as '人数',count(eid) from (select distinct sex from employee) 
t left join department d on 1=1 left 
join employee e on e.did=d.did and e.sex=t.sex group by d.name,t.sex
  • 查询结果其实也是一张表
select distinct sex from employee
  • 2.找出技术组长入职后一年职员工
select e1.name,e1.pid,e1.jointime,e2.name,e2.jointime 
from position p join employee e1 on p.pid=e1.pid 
join employee e2 on 1=1 
where p.name = '技术组长' and timestampdiff(YEAR,e1.jointime,e2.jointime) =1
  • 所有的子查询都能改写成连接,反之不能

  • 3.找出掌握了驾驶技能的员工名单

select * from employee e1 left join es on e1.eid=es.eid 
left join skill s on es.sid = s.sid 
where s.descript like '驾驶%'
  • 4.统计各部门掌握了驾驶技能员工人数
select d.did,d.name,count(t.did) from department d left join 
(select e.did from skill s join es on es.sid = s.sid and s.descript like '驾驶%' 
join employee e on e.eid = es.eid) t on t.did = d.did 
group by d.did,d.name
  • 5.统计各班身高在175以上的 人数
select c.cno,c.cname,count(s.sno) as '人数' from class c left join student s on s.cno = c.cno 
and s.high > 175 
group by c.cno,c.cname
  • 6.统计各管理员的工作量(统计选课审核分别是那些管理员通过)
select a.adno,a.adname,count(sc.sno) as '工作量' from admin a 
left join sc on substr(sc.adno,4,1) = a.adno 
and sc.scstate=1 
group by a.adno,a.adname
  • 7.找出和陈涛老师 是一个属相的同学名单
select s.name,s.birthday,t.birthday from student s join teacher t 
on (date_format(t.birthday,'%Y') - date_format(s.birthday,'%Y')) % 12 =0 
and tname='陈涛'
  • 8.统计各类别课程的学生人数
select substr(cdesc,1,instr(cdesc,'课程')-1) as '课程名称',count(s.sno) as '人数' 
from course c left join sc on c.cno=sc.cno 
left join student s on s.sno=sc.sno 
group by substr(cdesc,1,instr(cdesc,'课程')-1)
  • 8.1统计各类别有多少门课
select substr(cdesc,1,6),count(*) from course 
group by substr(cdesc,1,6)

  • 字符函数补充
    查找函数select instr('abc','a') 后面在前面出现的位置; select locate('a','abc')前面在后面出现的位置;

新题

  • 统计各门课的男女人数,显示出课程名称
select c.cno,t.sex,c.cname,count(sc.sno) from (select distinct sex from student) t 
left join course c on 1=1 
left join sc on sc.cno=c.cno 
group by t.sex,c.cno,c.cname
  • 找出高于平均选课人数的课程名单
select * from 
(select c.cname,count(c.sno) as 'countnumber' from sc join course c on sc.cno=c.cno 
group by c.cname ) ce 
join 
(select avg(cou) as 'avgnumber' from ( 
select cno,count(sno) as 'cou' from sc 
group by cno) s) k on ce.countnumber > k.avgnumber
  • 找出选择了数据库类科目的学生名单
SELECT c.cdesc,s.name FROM course c JOIN sc 
ON c.cno = sc.cno 
JOIN student s 
ON sc.sno=s.sno 
WHERE c.cdesc LIKE '%数据库%'
  • 统计各班选择电子商务课程的学生人数
select c.cno,c.cname,count(sc.cno) from class c left join student s on c.cno=s.cno 
        left join sc on sc.sno = s.sno 
        left join course co on co.cno = sc.cno 
        and co.cname='电商概论' 
group by c.cno,c.cname
  • 统计各班年龄在27岁以上的人数
select c.cno,c.cname,count(sno) from class c 
left join student s 
on c.cno=s.cno and floor(timestampdiff(DAY,s.birthday,now())/365) >27 
group by c.cno,c.cname
  • 统计各位教师的选课人数
select t.tname,count(sc.scno) from teacher t left join sc on t.tno=sc.tno 
group by t.tname
  • 统计各类别技能掌握的人数
select s.descript,count(e.eid) as '人数' from skill s 
left join es on s.sid=es.sid 
left join employee e on es.eid = e.eid 
group by s.descript

子查询

  • 使用内部查询的结果作为外部查询的条件。
  • 普通子查询,返回值是一个值或者一列值
  • 特殊子查询 all any some
  • 存在子查询 exists
  • 相关子查询
  • 相关存在子查询
  • 查询选择了数据库原理 课程的学生名单
    连接查询:
        三张表连接,如果通篇都没有where子句,on的非主外键 关联的条件不会对
            外连接的结果产生干扰,但是会产生额外的组合:
        select s.sno,s.name,c.cname 
        from student s left join sc on s.sno = sc.sno 
            left join course c on c.cno = sc.cno 
        and cname = '数据库原理';
        三张表连接,一旦有where子句,肯定是内连接的结果:
        select s.sno,s.name,c.cname 
        from student s join sc on s.sno = sc.sno 
            join course c on c.cno = sc.cno 
        where cname = '数据库原理';
        三张表,先两张表组合,组合后的结果再和第三张表组合,筛选后再进行外连接
        的结果:
        select s.sno,s.name,t.cname from student s left join 
        (select cname,sc.sno from sc join 
        course c on sc.cno = c.cno and cname ='数据库原理') t 
        on s.sno = t.sno;
    子查询:
        结果中的字段来自一张表---子查询,来自多张表---连接;
        select sno,name from student 
        where sno in(
            select sno from sc 
            where cno=(
            select cno from course where cname='数据库原理')
        )
  • 找出和陈涛老师同属相的学生名单
 子查询:确定表的内外,结果字段所在表在外---
 SELECT s.name,s.`birthday` FROM student s
    WHERE ((
    SELECT DATE_FORMAT(t.birthday,'%Y') FROM teacher t WHERE tname='陈涛')
    - DATE_FORMAT(s.birthday,'%Y')) % 12 =0;
2:select * from student s 
    where (substr(birthday,1,4) - 
        (select substr(birthday,1,4) from teacher 
            where tname='陈涛')) % 12 =0
  • 找出090102班中比090101班所有同学都高的学生的信息
1:select name,high from student 
    where cno = '090102' and high >=
    (select max(high) from student where cno = '090101')
2:大于any就是大于任意一个,大于all就是大于所有
    select name,high from student 
    where cno = '090101' and high >any
    (select high from student where cno = '090201')
  • 如果条件查询能够查到任意的返回数据,则外部查询执行
select * from student 
where exists (select * from teacher where tno='0009')
  • 普通子查询的执行顺序是,先执行内部查询将内部查询变成一个结果,再和外部查询组合执行;相关子查询,是将
    外部查询的数据,一行一行的送入内部查询组合执行,如果内部查询成立则外部查询的那一行数据保留。

  • 找出该班学生身高在175以上的人数在2人以上的班级的全体学生的名单

先找出身高175以上人数2人以上的班级
    普通子查询解法:
    select * from student
        where cno in(
    select cno from student
    where high >=175
    group by cno
    having count(sno) >=2)
    相关子查询解法:
    select * from student s1
        where exists(
    select cno from student s2
    where high >=175 and s1.cno = s2.cno
    group by cno
    having count(sno) >=2)
  • 找出高于自己班平均分的学生名单(结果既包含个体的属性,又包含了分组的属性)
select * from 
(select name,avgscore,cno from student s1 
where exists(
  select * from student s3
   where(
    s1.avgscore >= (select avg(avgscore) from student s2 
    where s2.cno = s1.cno))
) )t1 join 
(select cno,round(avg(avgscore),2) as '班级平均分',count(*) from student 
group by cno) t2 
on t1.cno = t2.cno
  • 找出每个班最高的同学的身高和姓名还要显示班级号
连接查询:
select t.cno,t.maxhigh,s.name from (select cno,max(high) as maxhigh from student group by cno ) t 
join student s on t.cno = s.cno and t.maxhigh = s.high
相关子查询:
解题思路:
·显示每个班最高身高的同学的班级号和姓名和身高
·判断每个同学是不是该班最高的,如果是留下,如果不是离开
·找出你们班最高的身高,判断你是否和最高的身高相等
select * from student s1 
where exists(
    select * from student s3
    where s1.high =(
      select max(high) from student s2
      where s1.cno = s2.cno )
    ) 
  • 低于各自班平均身高的信息
select * from student s1 
where exists (
  select * from student s3
  where s1.high<(
    select floor(avg(high)) from student s2
    where s2.cno = s1.cno
  )
)
  • 找出可以自驾游的部门
  • 找出可以出国自由行的部门的员工名单

相关子查询总结

  • 当结果需要同时显示分组的聚合属性(max sum min avg count)和个体属性时候
    分别将分组语句的记过和个体查询的结果,以新表重新连接在一起
  • 往往这种 分组和 个体属性同时出现,使用相关子查询更为方便。
  • 每一条外部查询的数据 作为内部查询的条件和内部查询组合执行,如果执行的结果有数据,则外部查询
    这条数据保留,否则 舍弃。
  • 如:高于班级平均分的同学留下,找出你自己班的平均分(每个人自己找),判断高于自己班平均分就留下,
    低于就离开。
  • 完成相关子查询:正常编写内外查询,内外查询之后,使用exists关联,在内部查询中加上外部查询的关联字段,
    例如 内部查询一次只找一个班的最值,外部查询来告知哪些值符合条件

你可能感兴趣的:(09-11:解题&子查询)