LeetCode-MySQL练习2(180/181/1777/182/196/197/1179)(行转列)(datediff/timestampdiff)
Posted Zephyr丶J
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LeetCode-MySQL练习2(180/181/1777/182/196/197/1179)(行转列)(datediff/timestampdiff)相关的知识,希望对你有一定的参考价值。
mysql练习2
180. 连续出现的数字
题目描述
表:Logs
+-------------+---------+
| Column Name | Type |
+-------------+---------+
| id | int |
| num | varchar |
+-------------+---------+
id 是这个表的主键。
编写一个 SQL 查询,查找所有至少连续出现三次的数字。
返回的结果表中的数据可以按 任意顺序 排列。
查询结果格式如下面的例子所示:
Logs 表:
+----+-----+
| Id | Num |
+----+-----+
| 1 | 1 |
| 2 | 1 |
| 3 | 1 |
| 4 | 2 |
| 5 | 1 |
| 6 | 2 |
| 7 | 2 |
+----+-----+
Result 表:
+-----------------+
| ConsecutiveNums |
+-----------------+
| 1 |
+-----------------+
1 是唯一连续出现至少三次的数字。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/consecutive-numbers
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
# 看成三个表,然后根据id关系和num关系确定条件
select distinct l1.Num as ConsecutiveNums
from Logs l1, Logs l2, Logs l3
where l1.Id = l2.Id - 1 and l2.Id = l3.Id - 1 and l1.Num = l2.Num and l2.Num = l3.Num;
下面一堆开窗函数啥的,感觉我们应该没必要会这个吧。。
181. 超过经理收入的员工
题目描述
Employee 表包含所有员工,他们的经理也属于员工。每个员工都有一个 Id,此外还有一列对应员工的经理的 Id。
+----+-------+--------+-----------+
| Id | Name | Salary | ManagerId |
+----+-------+--------+-----------+
| 1 | Joe | 70000 | 3 |
| 2 | Henry | 80000 | 4 |
| 3 | Sam | 60000 | NULL |
| 4 | Max | 90000 | NULL |
+----+-------+--------+-----------+
给定 Employee 表,编写一个 SQL 查询,该查询可以获取收入超过他们经理的员工的姓名。在上面的表格中,Joe 是唯一一个收入超过他的经理的员工。
+----------+
| Employee |
+----------+
| Joe |
+----------+
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/employees-earning-more-than-their-managers
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
终于有个会的,但是这样会产生笛卡尔积
select e1.Name as Employee from Employee e1, Employee e2
where e1.ManagerId = e2.Id and e1.Salary > e2.Salary;
或者连接join
select e1.Name as Employee from Employee e1
join Employee e2
on e1.ManagerId = e2.Id and e1.Salary > e2.Salary;
1777. 每家商店的产品价格
题目描述
表:Products
+-------------+---------+
| Column Name | Type |
+-------------+---------+
| product_id | int |
| store | enum |
| price | int |
+-------------+---------+
(product_id,store) 是这个表的主键。
store 字段是枚举类型,它的取值为以下三种 ('store1', 'store2', 'store3') 。
price 是该商品在这家商店中的价格。
写出一个 SQL 查询语句,查找每种产品在各个商店中的价格。
可以以 任何顺序 输出结果。
查询结果格式如下例所示:
Products 表:
+-------------+--------+-------+
| product_id | store | price |
+-------------+--------+-------+
| 0 | store1 | 95 |
| 0 | store3 | 105 |
| 0 | store2 | 100 |
| 1 | store1 | 70 |
| 1 | store3 | 80 |
+-------------+--------+-------+
Result 表:
+-------------+--------+--------+--------+
| product_id | store1 | store2 | store3 |
+-------------+--------+--------+--------+
| 0 | 95 | 100 | 105 |
| 1 | 70 | null | 80 |
+-------------+--------+--------+--------+
产品 0 的价格在商店 1 为 95 ,商店 2 为 100 ,商店 3 为 105 。
产品 1 的价格在商店 1 为 70 ,商店 3 的产品 1 价格为 80 ,但在商店 2 中没有销售。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/products-price-for-each-store
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
相当于行转列:
思路就是先找出每个产品的价格,然后再和产品号连接
注意left join,不能是join,因为join的话,如果连接的表中有产品没有,那么这一行的产品就不会显示
select distinct p.product_id, p1.price as store1, p2.price store2, p3.price store3
from Products p
left join (select * from Products where store = "store1") p1 on p.product_id = p1.product_id
left join (select * from Products where store = "store2") p2 on p.product_id = p2.product_id
left join (select * from Products where store = "store3") p3 on p.product_id = p3.product_id;
或者用group by去重
select
p.product_id,
a.price store1,
b.price store2,
c.price store3
from
Products p
left join
(select * from Products where store = 'store1') a on p.product_id = a.product_id
left join
(select * from Products where store = 'store2') b on p.product_id = b.product_id
left join
(select * from Products where store = 'store3') c on p.product_id = c.product_id
group by
1
182. 查找重复的电子邮箱
题目描述
编写一个 SQL 查询,查找 Person 表中所有重复的电子邮箱。
示例:
+----+---------+
| Id | Email |
+----+---------+
| 1 | a@b.com |
| 2 | c@d.com |
| 3 | a@b.com |
+----+---------+
根据以上输入,你的查询应返回以下结果:
+---------+
| Email |
+---------+
| a@b.com |
+---------+
说明:所有电子邮箱都是小写字母。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/duplicate-emails
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
select Email from Person group by Email having count(Email) > 1;
自连接:
select distinct p1.Email from Person p1, Person p2 where p1.Id <> p2.Id and p1.Email = p2.Email;
196. 删除重复的电子邮箱
题目描述
编写一个 SQL 查询,来删除 Person 表中所有重复的电子邮箱,重复的邮箱里只保留 Id 最小 的那个。
+----+------------------+
| Id | Email |
+----+------------------+
| 1 | john@example.com |
| 2 | bob@example.com |
| 3 | john@example.com |
+----+------------------+
Id 是这个表的主键。
例如,在运行你的查询语句之后,上面的 Person 表应返回以下几行:
+----+------------------+
| Id | Email |
+----+------------------+
| 1 | john@example.com |
| 2 | bob@example.com |
+----+------------------+
提示:
执行 SQL 之后,输出是整个 Person 表。
使用 delete 语句。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/delete-duplicate-emails
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
# 删除其他人p1的id大于其他人id的email
delete p1 from Person p1, Person p2
where p1.Email = p2.Email and p1.Id > p2.Id;
注意:DELETE p1
在DELETE官方文档中,给出了这一用法,比如下面这个DELETE语句👇
DELETE t1 FROM t1 LEFT JOIN t2 ON t1.id=t2.id WHERE t2.id IS NULL;
这种DELETE方式很陌生,竟然和SELETE的写法类似。它涉及到t1和t2两张表,DELETE t1表示要删除t1的一些记录,具体删哪些,就看WHERE条件,满足就删;
这里删的是t1表中,跟t2匹配不上的那些记录。
所以,官方sql中,DELETE p1就表示从p1表中删除满足WHERE条件的记录。
197. 上升的温度
题目描述
表 Weather
+---------------+---------+
| Column Name | Type |
+---------------+---------+
| id | int |
| recordDate | date |
| temperature | int |
+---------------+---------+
id 是这个表的主键
该表包含特定日期的温度信息
编写一个 SQL 查询,来查找与之前(昨天的)日期相比温度更高的所有日期的 id 。
返回结果 不要求顺序 。
查询结果格式如下例:
Weather
+----+------------+-------------+
| id | recordDate | Temperature |
+----+------------+-------------+
| 1 | 2015-01-01 | 10 |
| 2 | 2015-01-02 | 25 |
| 3 | 2015-01-03 | 20 |
| 4 | 2015-01-04 | 30 |
+----+------------+-------------+
Result table:
+----+
| id |
+----+
| 2 |
| 4 |
+----+
2015-01-02 的温度比前一天高(10 -> 25)
2015-01-04 的温度比前一天高(20 -> 30)
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/rising-temperature
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
判断日期差值:datediff(date1, date2) = x
date1比date2大,x为正;否则为负
select a.id from Weather a
join Weather b
on datediff(a.recordDate, b.recordDate) = 1 and a.Temperature > b.Temperature;
另一个关于时间计算的函数是:
timestampdiff(时间类型, 日期1, 日期2)
这个函数和上面diffdate的正、负号规则刚好相反。
日期1大于日期2,结果为负,日期1小于日期2,结果为正。
在“时间类型”的参数位置,通过添加“day”, “hour”, “second”等关键词,来规定计算天数差、小时数差、还是分钟数差。
select a.id from Weather a
join Weather b
on timestampdiff(day, a.recordDate, b.recordDate) = -1 and a.Temperature > b.Temperature;
1179. 重新格式化部门表
题目描述
部门表 Department:
+---------------+---------+
| Column Name | Type |
+---------------+---------+
| id | int |
| revenue | int |
| month | varchar |
+---------------+---------+
(id, month) 是表的联合主键。
这个表格有关于每个部门每月收入的信息。
月份(month)可以取下列值 ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]。
编写一个 SQL 查询来重新格式化表,使得新的表中有一个部门 id 列和一些对应 每个月 的收入(revenue)列。
查询结果格式如下面的示例所示:
Department 表:
+------+---------+-------+
| id | revenue | month |
+------+---------+-------+
| 1 | 8000 | Jan |
| 2 | 9000 | Jan |
| 3 | 10000 | Feb |
| 1 | 7000 | Feb |
| 1 | 6000 | Mar |
+------+---------+-------+
查询得到的结果表:
+------+-------------+-------------+-------------+-----+-------------+
| id | Jan_Revenue | Feb_Revenue | Mar_Revenue | ... | Dec_Revenue |
+------+-------------+-------------+-------------+-----+-------------+
| 1 | 8000 | 7000 | 6000 | ... | null |
| 2 | 9000 | null | null | ... | null |
| 3 | null | 10000 | null | ... | null |
+------+-------------+-------------+-------------+-----+-------------+
注意,结果表有 13 列 (1个部门 id 列 + 12个月份的收入列)。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/reformat-department-table
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
好好理解一下,因为group by只能select 分组的字段
所以需要加聚合函数,使其能够输出revenue
同时,在聚合函数中,判断月份的关系,就可以得到答案
select id,
sum(case when month = "Jan" then revenue end) as Jan_Revenue,
sum(case when month = "Feb" then revenue end) as Feb_Revenue,
sum(case when month = "Mar" then revenue end) as Mar_Revenue,
sum(case when month = "Apr" then revenue end) as Apr_Revenue,
sum(case when month = "May" then revenue end) as May_Revenue,
sum(case when month = "Jun" then revenue end) as Jun_Revenue,
sum(case when month = "Jul" then revenue end) as Jul_Revenue,
sum(case when month = "Aug" then revenue end) as Aug_Revenue,
sum(case when month = "Sep" then revenue end) as Sep_Revenue,
sum(case when month = "Oct" then revenue end) as Oct_Revenue,
sum(case when month = "Nov" then revenue end) as Nov_Revenue,
sum(case when month = "Dec" then revenue end) as Dec_Revenue
from Department
group by id;
SELECT id,
max(IF(`month`='Jan',revenue,NULL)) Jan_Revenue,
max(IF(`month`='Feb',revenue,NULL)) Feb_Revenue,
max(IF(`month`='Mar',revenue,NULL)) Mar_Revenue,
max(IF(`month`='Apr',revenue,NULL)) Apr_Revenue,
max(IF(`month`='May',revenue,NULL)) May_Revenue,
max(IF(`month`='Jun',revenue,NULL)) Jun_Revenue,
max(IF(`month`='Jul',revenue,NULL)) Jul_Revenue,
max(IF(`month`='Aug',revenue,NULL)) Aug_Revenue,
max(IF(`month`='Sep',revenue,NULL)) Sep_Revenue,
max(IF(`month`='Oct',revenue,NULL)) Oct_Revenue,
max(IF(`month`='Nov',revenue,NULL)) Nov_Revenue,
max(IF(`month`='Dec',revenue,NULL)) Dec_Revenue
FROM Department
group by id;
以上是关于LeetCode-MySQL练习2(180/181/1777/182/196/197/1179)(行转列)(datediff/timestampdiff)的主要内容,如果未能解决你的问题,请参考以下文章