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)的主要内容,如果未能解决你的问题,请参考以下文章

LeetCode-MySQL

最全手机号段数据

PHP手机号正则(多号段)

2018 最新手机号正则(最新最全)

手机号码正则(已测试可以)

国内手机号码段,卫星电话号段