首先鸭哥给出表结构:
select *
from student
where name like "猴%"
select *
from student
where name like "%猴"
select *
from student
where name like "%猴%"
select sum(成绩)
from score
where 课程号=’0002‘
select count(distinct 学号) as 学生人数
from score
select 课程号,max(成绩) as 最高分,min(最低分) as 最低分
from score
group by 课程号
select 课程,count(学号)
from score
group by 课程号;
select 性别,count(*)
from student
group by 性别
select 学号,avg(成绩)
from score
where 成绩>60
group by 学号
select by 学号,count(课程号) as 选修科目数
from score
group by 学号
having count(课程号)>=2;
select 姓名,count(姓名) as 人数
from student
group by 姓名
having count(姓名)>=2
select 课程
from score
where 成绩<60
order by 成绩 desc;
select 课程号,avg(成绩) as 平均成绩
from score
group by 课程号
order by 平均成绩 asc,课程号 desc;
select 学号
from score
where 课程号='0004' and 成绩<60
order by 成绩 desc;
select 课程号,count(学号)
from score
group by 课程号
having count(课程号)>2
order by count(学号) desc,课程号 asc;
select 学号,avg(成绩)
from score
where 成绩<60
group by 学号
having count(课程号)>2
select score.学号,student.姓名
from score INNER JOIN student on student.学号=score.学号
group by 学号
having max(成绩)<60
select 学号,姓名
from student
where in (
select 学号
from score
group by 学号
having max(成绩)<60
)
select 学号,姓名
from student
where 学号 in(
select 学号
from score
group by 学号
having count(课程号)< (select count(课程号) from course)
);
select 学号,姓名
from student
where 学号 in(
select 学号
from score
group by 学号
having count(课程号) =2);
)
select 学号,姓名
from student
where year (出生日期)=1990;
【面试题类型】topN问题
工作中会经常遇到这样的业务问题:
如何找到每个类别下用户最喜欢的产品是哪个?
如果找到每个类别下用户点击最多的5个商品是什么?
这类问题其实就是常见的:分组取每组最大值、最小值,每组最大的N条(top N)记录。
select 课程号,max(成绩) as 最大成绩
from score
group by 课程号;
这样子没有学号。为了查询出学号、课程号和成绩,要查询score表的所有内容,但是这里group by 是课程号了,所以学号是select不出来的。
可以用关联子查询
select *
from score as a
where 成绩 =(
select max(成绩)
from score b
where a.课程号=b.课程号
group by 课程号
)
select *
from score as a
where 成绩={
select min(成绩)
from score as b
where b.课程号=a.课程号
group by 课程号);
案例:查询各科成绩前两名的记录
(select * from score where 课程号 = '0001' order by 成绩 desc limit 2)
union all
(select * from score where 课程号 = '0002' order by 成绩 desc limit 2)
union all
(select * from score where 课程号 = '0003' order by 成绩 desc limit 2);
这个应该有其他更好的写法,自定义变量。
用到多表查询
1.我们先来拆解问题:不是近视眼的学生都有谁?
两种写法
select 学号,姓名
from 学生表
where 学号 not in (
select 学号
from 近视学生表
)
select a.学号,a.姓名 as 不近视学生名单
from 学生表 a
left join 近视学生表 b
on a.学号=b.学生学号
where b.学生学号 is null
运行图:
某网站包含两个表,顾客姓名表(表名Customers)和 购买记录表(表名Orders)。找出所有从不订购任何东西的客户。(“顾客姓名表”中的ID与“购买记录”表中的学生学号CustomerId一一对应)
select a.id,a.name
from customer c
left join order o on o.id=c.id
where o.customerid=null
select a.学号,a.姓名,count(c.学号),sum(c.成绩)
from student a
left join score c
on a.学号=c.学号
group by a.学号
select a.学号,a.姓名,avg(c.成绩) as 平均成绩
from student a
left join score c
on a.学号=c.学号
group by a.学号
having avg(成绩)>85
select a.学号,a.姓名,c.课程号,c.课程名称
from studnet a
inner join score b on b.学号=a.学号
inner join course c on c=课程号=b.课程号
select 课程号,
sum(case when 成绩>=60 then 1 else 0 end) as 及格人数
sum(case when 成绩<60 then 1 else 0 end) as 不及格人数
from score
group by 课程号
select a.课程号,b.课程名称,
sum(case when 成绩 between 85 and 100 then 1 else 0 end ) as '[100-85]'
sum(case when 成绩>=70 and 成绩<85 then 1 else 0 end ) as '[70-85]'
sum(case when 成绩›=60 and 成绩‹70 then 1 else 0 end) as '[70-60]',
sum(case when 成绩‹60 then 1 else 0 end) as '[‹60]'
from score as a right join course as b
on a.课程号=b.课程号
group by a.课程号
select a.学号,a.姓名
from student as a inner join score as b on a.学号=b.学号
where b.课程号=’0003‘ and b.成绩>80;
使用sql实现将该表行转列为下面的表结构
select 学号,
max(case 课程号 when '0001' then 成绩 else 0 end) as '课程号0001',
max(case 课程号 when '0002' then 成绩 else 0 end) as '课程号0002',
max(case 课程号 when '0003' then 成绩 else 0 end) as '课程号0003'
from score
GROUP BY 学号;
这个题比较绕,如果不加max就会把0包括,max()函数就可以消除多余行,但是多余行又有其他数据,所以要一起加max,单个加还会报错。因为是计算每个学号学生的成绩所以按学号来分组。
1. select子句中尽量避免使用*,多表连接用*更慢。
2. where子句比较符号左侧避免函数:尽量避免在where条件子句中,比较符号的左侧出现表达式、函数等操作。因为这会导致数据库引擎进行全表扫描,从而增加运行时间。
where 成绩 + 5 › 90 (表达式在比较符号的左侧)
优化方法:
where 成绩 › 90 – 5(表达式在比较符号的右侧)
3. 尽量避免使用in和not in:in和not in也会导致数据库进行全表搜索,增加运行时间。
可以使用between代替。
比如,我想看看第8、9个人的学号和成绩,大多数同学会用这个语句:
select 学号, 成绩
from 成绩表
where 学号 in (8, 9)
这一类语句,优化方法如下:
select 学号, 成绩
from 成绩表
where 学号 between 8 and 9
4. 尽量避免使用or
or同样会导致数据库进项全表搜索。在工作中,如果你只想用or从几十万语句中取几条出来,是非常划不来的,怎么办呢?下面的方法可替代or。
从成绩表中选出成绩是是88分或89分学生的学号:
select 学号
from 成绩表
where 成绩 = 88 or 成绩 = 89
优化后:
select 学号 from 成绩表 where 成绩 = 88
union
select 学号 from 成绩表 where 成绩 = 89
5.使用limit子句限制返回的数据行数
如果前台只需要显示15行数据,而你的查询结果集返回了1万行,那么这适合最好使用limt子句来限制查询返回的数据行数。