sql常见面试题(未完待续)

1.长表转宽表

原表结构为:
在这里插入图片描述

SELECT year,
       max(case when month=1 then amount else null end) m1,
	   max(case when month=2 then amount else null end) m2,
	   max(case when month=3 then amount else null end) m3,
	   max(case when month=4 then amount else null end) m4
FROM a
group by year;

在这里插入图片描述

2.考察窗口函数(rows参数)

查询表中连续三个月以上degree均为A的记录(考察窗口函数的使用,尤其是rows参数的用法)
在这里插入图片描述

select name,month,degree,
	   sum(if(degree='A',1,0)) over(partition by name order by month rows between 2 preceding and current row) score1,
	   sum(if(degree='A',1,0)) over(partition by name order by month rows between 1 preceding and 1 following) score2,
	   sum(if(degree='A',1,0)) over(partition by name order by month rows between current row and 2 following) score3
from b;

在这里插入图片描述

select t.name,t.month,t.degree
from(
	select name,month,degree,
		   sum(if(degree='A',1,0)) over(partition by name order by month rows between 2 preceding and current row) score1,
		   sum(if(degree='A',1,0)) over(partition by name order by month rows between 1 preceding and 1 following) score2,
		   sum(if(degree='A',1,0)) over(partition by name order by month rows between current row and 2 following) score3
	from b) t
where t.score1=3 or t.score2=3 or t.score3=3

在这里插入图片描述
网友Pray、PF提供了一种新思路,供大家参考:

select *
from(
			SELECT t2.*,
			month-rnk AS res
			FROM(
						SELECT t.*,
						row_number() over(PARTITION BY NAME ORDER BY month) AS rnk
						FROM(
									SELECT *
									FROM b
									WHERE degree='A'
							) t
				
				) t2
		) t3
where (name,res) in(
select name,res
from(
			SELECT t2.*,
			month-rnk AS res
			FROM(
						SELECT t.*,
						row_number() over(PARTITION BY NAME ORDER BY month) AS rnk
						FROM(
									SELECT *
									FROM b
									WHERE degree='A'
							) t
				
				) t2
	) t3
group by name,res
having count(*) >=3
);

在这里插入图片描述

3.用一条SQL 语句 查询出每门课都大于70分的学生姓名

在这里插入图片描述
方法1:
嵌套子查询,子查询要从反面查才能查全

select distinct username 
from score
where username not in(
					select distinct username
					from score
					where per < 70);

在这里插入图片描述

方法2:
group by方法

SELECT username FROM score
group by username
having min(per)>70;

在这里插入图片描述

4.拷贝表( 拷贝数据, 源表名:a目标表名:b)

create table s1 as
select * from s;

5.复制表( 只复制结构, 源表名:a新表名:b)

目的:让条件不成立为null即可

create table s2 as 
select * from s
where 1=2;

6.删除除了自动编号不同, 其他都相同的学生冗余信息

在这里插入图片描述

delete from s
where auto not in(
		select min(auto) as auto
		from s
		group by sid,sname,cid,cname,sc);

在这里插入图片描述
注:这样写会报错
翻译为:不能先select出同一表中的某些值,再update这个表(在同一语句中)

正确写法如下

delete from s
where auto not in(
select t.auto
from(
	select min(auto) as auto
	from s
	group by sid,sname,cid,cname,sc) t
	);

在这里插入图片描述
也就是说,需要把查询结果当做临时表再查询一次

7.一个叫 team 的表,里面只有一个字段name, 一共有4 条纪录,分别是a,b,c,d, 对应四个球对,现在四个球对进行比赛,用一条sql 语句显示所有可能的比赛组合

在这里插入图片描述

select *
from name n1
join name n2
on n1.name < n2.name
order by n1.name;

在这里插入图片描述

8.从TestDB 数据表中查询出所有月份的发生额都比101 科目相应月份的发生额高的科目。请注意:TestDB 中有很多科目,都有1 -6 月份的发生额。

在这里插入图片描述
方法1:

select t1.*
from testdb t1
join testdb t2
on t1.id <> t2.id and t1.month = t2.month
where t2.id = 101 and t1.sc > t2.sc
order by t1.id;

这里还有个小知识点:表连接 on and 和 on where 的区别
可参照链接: MySQL表连接 on and 和 on where 的区别.

方法2:

select t1.* 
from testdb t1
join(
	select month,max(sc) sc
	from testdb
	where id = 101
	group by month) t2
on t1.month = t2.month
where t1.sc > t2.sc;

在这里插入图片描述
最后结果:

select t1.id
from testdb t1
join testdb t2
on t1.id <> t2.id and t1.month = t2.month
where t2.id = 101 and t1.sc > t2.sc
group by t1.id
having count(t1.id) = 6
order by t1.id;

在这里插入图片描述

9.相邻id进行调换

在这里插入图片描述
方法1:终极无敌究极麻烦法
(用了表的自连接,当时我怎么想的!!!能再麻烦点吗!!)

select s1.id,s2.student
from(
    select *,max(id) over() m
    from seat
)s1 
join seat s2
on s1.id != s2.id or s1.id=s2.id
where if(s1.id mod 2=1,s1.id,null)+1=s2.id or if(s1.id mod 2=0,s1.id,null)-1=s2.id or if(m mod 2=1,(s1.id=m and s1.id=s2.id),null)
order by s1.id

方法2:case-when简洁法
case
when 条件1 then 结果1

else 结果3
end
注:这里可将最大id直接与原表一起from,而不用什么窗口函数

select
    (case 
    when id mod 2=0 then id-1
    when id mod 2=1 and id=m then id
    else id+1
    end) id,
    student
from seat,(select max(id) m from seat) t
order by id

方法3:if语句法
这里mod建议还是用mod函数的形式,易于观看

select if(mod(s.id,2)=0,s.id-1,(if(s.id=t.m,s.id,s.id+1))) id
         ,student
from seat s,(select max(id) m from seat) t
order by id

在这里插入图片描述

10.oppo面试题

用户登陆表表名:user_time,字段名:uid(用户id), time(登陆时间)
1.1求2020-08-01日至2020-08-07日每天的7日留存率(7日留存:一个用户当日活跃,7天后依然活跃)

select fd,count(case when datediff(date_format(u.time,'%Y-%m-%d'),fd)=7 then u.uid else null end)/count(distinct uid) 7_re_rate
from user_time u
left join 
	(select uid,min(date_format(time,'%Y-%m-%d')) fd
	from user_time
	where date_format(time,'%Y-%m-%d') between '2020-08-01' and '2020-08-07'
	group by uid) t
on u.uid = t.uid
group by fd
order by fd;

1.2求每个用户相邻两次登陆时间之差小于3分钟的次数

select uid,count(*)
from(
	select uid,time,lag(time,1) over(partition by uid) l
	from(
		select uid,time
		from user_time
		order by uid,time) t
	) t1
where timestampdiff(minute,l,time) < 3 
group by uid;
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值