Leetcode--SQL刷题(601-1070)

-- 601 解决连续天数问题,注意FIND_IN_SET()函数的使用
-- 602 可以先试用UNION ALL,然后通过一个GROUP By结束 
-- 603 通过JOIN的方法解决连续性问题 
-- 610 三角形的判断,只考虑相加条件即可 
-- 612 只能使用全连接,注意round(col,2),sqrt(col),pow(col,2)等函数的使用
-- 613 和612题是一个套路,只是需要使用abs(col)方法即可
-- 615 注意date_format(col,'%Y-%m')的使用; GROUP By的新方式;使用JOIN,而不是在SELECT中嵌套子查询
-- 618 透视列的做法;注意max(col)中,如果col不为null,输出就是col
-- 619 注意方法3和方法2的区别,使用max来处理空值的问题
-- 626 MOD(col,2)函数处理奇偶问题;注意不需要JOIN或者子查询,可以直接得到结果
-- 627 善于使用IF函数
-- 1045 这道题非常重要,善用JOIN去解决问题

601.体育馆的人流量
在这里插入图片描述

方法一:自己写的
select id, visit_date, people from stadium
where id in
(select distinct id from
(select a.id
from stadium a join stadium b on a.id=b.id+1
join stadium c on b.id=c.id+1
where a.people>=100 and b.people>=100 and c.people>=100
union all
select b.id
from stadium a join stadium b on a.id=b.id+1
join stadium c on b.id=c.id+1
where a.people>=100 and b.people>=100 and c.people>=100
union all
select c.id
from stadium a join stadium b on a.id=b.id+1
join stadium c on b.id=c.id+1
where a.people>=100 and b.people>=100 and c.people>=100) t1);

方法二:对方法一的改进,但是性能差不多;三种分类情况再理解一下.
select distinct a.* from stadium a,stadium b,stadium c
where a.people>=100 and b.people>=100 and c.people>=100
and (
     (a.id = b.id-1 and b.id = c.id -1) or
     (a.id = b.id-1 and a.id = c.id +1) or
     (a.id = b.id+1 and b.id = c.id +1)
) order by a.id

方法三:使用窗口函数 标准写法 无法运行 不知道性能
select id,visit_date,people from
(
select id
,lead(people,1) over(order by id) ld
,lead(people,2) over(order by id) ld2
,visit_date
,lag(people,1) over(order by id) lg
,lag(people,2) over(order by id) lg2
,people
from stadium
) a
where (a.ld>=100 and a.lg>=100 and a.people>=100)
or (a.ld>=100 and a.ld2>=100 and a.people>=100)
or (a.lg>=100 and a.lg2>=100 and a.people>=100)


方法四: 性能极佳
select id,visit_date,people from stadium ,
(
	select if(count(0)>=3,GROUP_CONCAT(id),NULL) as ids -- 步骤3和步骤4:通过差值分组之后合并连续的ID数
	from 
	(
		SELECT 
			id
			,visit_date
			,people
			,IF(people>99,@num:=@num+1,@num:=0) -- 步骤1:用来连续计数大于99的数
			,IF(@num>0,id-@num,-1) as groupNum -- 步骤2:用来分组的差值
		FROM stadium,(SELECT @num:=0)a -- 定义@num变量
	) temp
	where groupNum>-1 -- -1表示当前数值是小于100的
	group by groupNum -- 步骤3:通过差值分组
)tempId
WHERE tempId.ids is NOT NULL and FIND_IN_SET(id,tempId.ids) -- 步骤5:最终查询数据
order by id 

602.好友申请 II :谁有最多的好友
在这里插入图片描述
在这里插入图片描述

# 0.6510(好像没有别的很好的方法)
SELECT id, count(*) num
FROM
    (select requester_id id from request_accepted
    union all
    select accepter_id  id from request_accepted) t
GROUP BY id
ORDER BY num DESC
LIMIT 1;

603. 连续空余座位
在这里插入图片描述

#  0.6359 学会在自连接中实现相邻id连接,以及abs函数使用
SELECT distinct C1.seat_id
FROM cinema as C1 join cinema as C2
ON (C1.free='1' and C2.free='1' and abs(C1.seat_id-C2.seat_id)=1)
order by C1.seat_id

607. 销售员
在这里插入图片描述
在这里插入图片描述

# 应该没有更简单的方法0.5298
SELECT name 
FROM salesperson s
WHERE sales_id NOT IN
	(SELECT sales_id
	FROM company c,orders o
	WHERE c.com_id=o.com_id and c.name="RED");

608.树节点
在这里插入图片描述
在这里插入图片描述

# 自认为自己的思路无敌 0.9346
# 先判断是否是根节点,再找出中间节点。
SELECT id, (CASE when p_id is null then "Root"
                 when id  in (select p_id from tree) then "Inner"
                 else "Leaf" end) "Type"
FROM 
    tree;

610.判断三角形(这个题表名错了)
在这里插入图片描述

# 方法1 0.7450
SELECT x,y,z, (CASE when (x+y>z) and (x+z>y) and (y+z>x) then "Yes"
                   else "No" end) "triangle"
FROM
    triangle;
#方法2 按理说应该更好一点 但是实际没有0.6694(可能是系统问题)
SELECT x,y,z, (CASE when (x+y<=z) or (x+z<=y) or (y+z<=x) then "No"
                   else "Yes" end) "triangle"
FROM
    triangle;

612. 平面上的最近距离
在这里插入图片描述

# 第一次方法 0.4332,注意 != 判断条件的写法
SELECT  CAST(sqrt(power(a.x-b.x,2)+power(a.y-b.y,2)) AS decimal(10,2)) shortest
FROM 
    point_2d a,point_2d b
WHERE (a.x,a.y) != (b.x,b.y)
ORDER BY shortest
LIMIT 1

其中where判断条件还有两种写法:
WHERE not (a.x=b.x and a.y=b.y)
WHERE a.x != b.x OR a.y != b.y 

# 优化 0.85
SELECT min(round(sqrt(pow(a.x-b.x,2)+pow(a.y-b.y,2)),2)) shortest
FROM
    point_2d a, point_2d b
 WHERE not (a.x=b.x and a.y=b.y)

613. 直线上的最近距离
在这里插入图片描述

# 0.9614 很简单,但是进阶可以考虑一下
SELECT min(abs(a.x-b.x)) shortest
FROM
    point a, point b
 WHERE a.x <> b.x

614. 二级关注者
在这里插入图片描述

# 数据中有重复数据,导致这个方法不能用
SELECT followee as "follower", count(*) num
FROM 
    follow
WHERE followee in (SELECT follower from follow)
GROUP BY followee

# 方法2 修正 0.35
SELECT
    f1.follower, count(distinct(f2.follower)) num
FROM
    follow f1,follow f2
WHERE
    f1.follower=f2.followee
GROUP BY f1.foll**加粗样式**ower;

# 方法3(自己的方法 0.8462) 对方法1的更正, 因为数据中有重复数据。
SELECT followee as "follower", count(distinct follower) num
FROM 
    follow
WHERE followee in (SELECT follower from follow)
GROUP BY followee

615. 平均工资:部门与公司比较
妈的hhhh!mysql中group by中使用别名不报错!
在这里插入图片描述
在这里插入图片描述

# 方法1 0.533(自己做对啦)
# 问题:两个子查询中,分组时多做了一次时间格式化运算(贼SB!)
SELECT t1.pay_month,t1.department_id, (CASE when t1.sal>t2.sal then "higher"
                                           when t1.sal<t2.sal then "lower"
                                           else "same" end) as comparison
FROM
    (SELECT date_format(pay_date,'%Y-%m') pay_month, department_id, avg(amount) sal
    FROM 
        salary s join employee e
    ON s.employee_id=e.employee_id
    GROUP BY date_format(pay_date,'%Y-%m'),department_id) t1,

    (SELECT date_format(pay_date,'%Y-%m') pay_month,avg(amount) sal FROM salary
    GROUP BY date_format(pay_date,'%Y-%m')) t2
WHERE t1.pay_month=t2.pay_month
ORDER BY department_id,pay_month;

# 方法2 0.9353
# 重点注意group by的分组方法
SELECT t1.pay_month,t1.department_id, (CASE when t1.sal>t2.sal then "higher"
                                           when t1.sal<t2.sal then "lower"
                                           else "same" end) as comparison
FROM
    (SELECT date_format(pay_date,'%Y-%m') pay_month, department_id, avg(amount) sal
    FROM 
        salary s join employee e
    ON s.employee_id=e.employee_id
    GROUP BY 1,2) t1,

    (SELECT date_format(pay_date,'%Y-%m') pay_month,avg(amount) sal FROM salary
    GROUP BY 1) t2
WHERE t1.pay_month=t2.pay_month
ORDER BY department_id,pay_month;

提示:从日期中取出年份+月份,也可以使用left/right函数,,,自己理解一下,不推荐。

618. 学生地理信息报告
在这里插入图片描述

# 自己的错误做法:
SELECT max(IF(continent='America',name, null))  `America`,
       max(IF(continent='Asia',name, null)) `Asia`,
       max(IF(continent='Europe',name,null))  `Europe`
FROM 
    student
GROUP BY name
ORDER BY continent,name;

# 这样的输出是:
[["Jack",null,null],
["Jane",null,null],
[null,"Xi",null],
[null,null,"Pascal"]]

# 方法2:重点学习 代码逻辑 0.75
# 思考一下这里为什么加max?如果不加max,那么打印的可能就是组内的null值
SELECT 
    MAX(if(A.continent = 'America',A.NAME,NULL)) AS `America`,
    MAX(if(A.continent = 'Asia',A.NAME,NULL)) AS `Asia`,
    MAX(if(A.continent = 'Europe',A.NAME,NULL)) AS `Europe`
FROM
(
	SELECT S.*,
	@trank:=if(@pre_con = S.continent,
		@trank + 1,
		1
	) AS `trank`,
	@pre_con:=S.continent AS `pre`
	FROM student AS S,(SELECT @pre_con:=NULL,@trank:=0) AS T
	ORDER BY S.continent,S.NAME
) AS A
GROUP BY A.trank

619. 只出现一次的最大数字
在这里插入图片描述

# 方法1 有问题
SELECT if(num is null,null, num) "num"
FROM my_numbers
GROUP BY num Having count(*)=1
ORDER BY num desc
LIMIT 1

在这里插入图片描述

# 方法2:更正方法1:0.8725
# 判断null的方法要注意
SELECT ifNULL
    ((SELECT num
    FROM my_numbers
    GROUP BY num Having count(*)=1
    ORDER BY num desc
    LIMIT 1), null) num;

# 方法3:扩展思路 0.8223
SELECT MAX(num) as num
FROM
    (SELECT num
    FROM my_numbers
    GROUP BY num Having count(*)=1) t

620.有趣的电影
在这里插入图片描述

SELECT
	id,
	movie,
	description,
	rating
FROM
	cinema
WHERE
	id & 1
AND description <> 'boring'
ORDER BY
	rating DESC

这里还是使用<>好一点,not like没有这个快.
掌握位判断的方法,比mod和%都快.
奇数和1位与运算都是1,偶数都是0,因此本题中可以作为筛选条件

626.换座位
在这里插入图片描述
在这里插入图片描述

自己的答案 性能一般 但是值得鼓励
思路:建造辅助列 通过两个排序去做
select cast((case when 1 then @ran:=@ran+1 end) as decimal(10,0)) id, student
from(
select id,student,(case 
when id&1 then @gro:=@gro+1
else @gro
end) num
from seat,(select @gro:=0) t
order by num,id desc) t1, (select @ran:=0) t2;


方法二:逻辑简直无敌!性能极佳!!
逻辑:偶数id-1, 奇数id+1, 最后一个奇数id不变
SELECT (CASE 
            WHEN MOD(id,2) = 1 AND id = (SELECT COUNT(*) FROM seat) THEN id
            WHEN MOD(id,2) = 1 THEN id+1
            ElSE id-1
        END) AS id, student
FROM seat
ORDER BY id;

627.交换工资
在这里插入图片描述

方法1
update salary set sex=
case sex
when 'm' then 'f'
else 'm'
end;

方法2
UPDATE salary 
SET sex = if(sex = "m","f","m");

1045.买下所有产品的客户
在这里插入图片描述
在这里插入图片描述

# 方法1:自己的方法 0.7354(很笨重)
SELECT customer_id
FROM
    (SELECT distinct customer_id,product_key
    FROM customer) T
GROUP BY customer_id
HAVING count(*)=(SELECT count(distinct product_key) FROM product);

# 方法20.9274(还是连表查询更好一点)
SELECT customer_id
FROM
    (select customer_id,count(distinct product_key) as num 
    from Customer
    group by customer_id
    ) t
JOIN 
    (select count(product_key) as num
    from Product) m 
on t.num = m.num;

1050. 合作过至少三次的演员和导演
在这里插入图片描述
在这里插入图片描述

# 很简单的一道题
SELECT actor_id ACTOR_ID,director_id DIRECTOR_ID
FROM actordirector
GROUP BY actor_id,director_id
having count(*)>=3;

1070. 产品销售分析 III
在这里插入图片描述
在这里插入图片描述

# 方法1: 我认为是对的,但是顺序和答案不同。
SELECT product_id, year first_year, quantity, price
FROM
    (SELECT s.*, (case when @pro=product_id then @ran:=@ran+1
                    when @pro:=product_id then @ran:=1 end) ran
    FROM Sales s,(select @pro:=null, @ran:=null) t1
    ORDER BY product_id,year) t2
WHERE ran=1

# 方法2:思路清晰 0.7642(估计第一种更好)
SELECT s.product_id, s.year first_year,quantity,price
FROM
    sales s, (select product_id,min(year) year from sales group by product_id) t
WHERE s.product_id=t.product_id and s.year=t.year;
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值