LeetCode【高频SQL基础50题】
查询
1757.可回收且低脂的产品
表:Products
+-------------+---------+
| Column Name | Type |
+-------------+---------+
| product_id | int |
| low_fats | enum |
| recyclable | enum |
+-------------+---------+
product_id 是该表的主键(具有唯一值的列)。
low_fats 是枚举类型,取值为以下两种 ('Y', 'N'),其中 'Y' 表示该产品是低脂产品,'N' 表示不是低脂产品。
recyclable 是枚举类型,取值为以下两种 ('Y', 'N'),其中 'Y' 表示该产品可回收,而 'N' 表示不可回收。
编写解决方案找出既是低脂又是可回收的产品编号。
返回结果无顺序要求。
通过SQL:
select product_id from Products
where low_fats = 'Y' and recyclable = 'Y'
584. 寻找用户推荐人
表: Customer
+-------------+---------+
| Column Name | Type |
+-------------+---------+
| id | int |
| name | varchar |
| referee_id | int |
+-------------+---------+
在 SQL 中,id 是该表的主键列。
该表的每一行表示一个客户的 id、姓名以及推荐他们的客户的 id。
找出以下客户的姓名:
- 被任何
id != 2的用户推荐。 - 没有被任何用户推荐。
以任意顺序返回结果表。
通过SQL:
select name from Customer
where referee_id != 2 or referee_id is null
595. 大的国家
World表:
+-------------+---------+
| Column Name | Type |
+-------------+---------+
| name | varchar |
| continent | varchar |
| area | int |
| population | int |
| gdp | bigint |
+-------------+---------+
name 是该表的主键(具有唯一值的列)。
这张表的每一行提供:国家名称、所属大陆、面积、人口和 GDP 值。
如果一个国家满足下述两个条件之一,则认为该国是大国:
- 面积至少为300万平方公里(即,
3000000 km2),或者 - 人口至少为2500万(即
25000000)
编写解决方案找出大国的国家名称、人口和面积。
按任意顺序返回结果表。
通过SQL:
select name, population, area from World
where area >= 3000000 or population >= 25000000
1148. 文章浏览 I
Views表:
+---------------+---------+
| Column Name | Type |
+---------------+---------+
| article_id | int |
| author_id | int |
| viewer_id | int |
| view_date | date |
+---------------+---------+
此表可能会存在重复行。(换句话说,在 SQL 中这个表没有主键)
此表的每一行都表示某人在某天浏览了某位作者的某篇文章。
请注意,同一人的 author_id 和 viewer_id 是相同的。
请查询出所有浏览过自己文章的作者。
结果按照作者的id升序排列。
通过SQL:
select distinct author_id id from Views
where author_id = viewer_id
order by author_id asc
1683. 无效的推文
表:Tweets
+----------------+---------+
| Column Name | Type |
+----------------+---------+
| tweet_id | int |
| content | varchar |
+----------------+---------+
在 SQL 中,tweet_id 是这个表的主键。
content 只包含字母数字字符,'!',' ',不包含其它特殊字符。
这个表包含某社交媒体 App 中所有的推文。
查询所有无效推文的编号(ID)。当推文内容中的字符数严格大于15时,该推文是无效的。
以任意顺序返回结果表。
通过SQL:
select tweet_id from Tweets
where char_length(content) > 15
注意:
LENGTH()返回字符串的字节数CHAR_LENGTH()返回字符串的字符数
连接
1378. 使用唯一标识码替换员工ID
Employees表:
+---------------+---------+
| Column Name | Type |
+---------------+---------+
| id | int |
| name | varchar |
+---------------+---------+
在 SQL 中,id 是这张表的主键。
这张表的每一行分别代表了某公司其中一位员工的名字和 ID 。
EmployeeUNI 表:
+---------------+---------+
| Column Name | Type |
+---------------+---------+
| id | int |
| unique_id | int |
+---------------+---------+
在 SQL 中,(id, unique_id) 是这张表的主键。
这张表的每一行包含了该公司某位员工的 ID 和他的唯一标识码(unique ID)。
展示每位用户的唯一标识码(unique ID );如果某位员工没有唯一标识码,使用null填充即可。
你可以以任意顺序返回结果表。
通过SQL:
select unique_id, name
from Employees
left join EmployeeUNI on Employees.id = EmployeeUNI.id
1068. 产品销售分析 I
销售表 Sales:
+-------------+-------+
| Column Name | Type |
+-------------+-------+
| sale_id | int |
| product_id | int |
| year | int |
| quantity | int |
| price | int |
+-------------+-------+
(sale_id, year) 是销售表 Sales 的主键(具有唯一值的列的组合)。
product_id 是关联到产品表 Product 的外键(reference 列)。
该表的每一行显示 product_id 在某一年的销售情况。
注意: price 表示每单位价格。
产品表 Product:
+--------------+---------+
| Column Name | Type |
+--------------+---------+
| product_id | int |
| product_name | varchar |
+--------------+---------+
product_id 是表的主键(具有唯一值的列)。
该表的每一行表示每种产品的产品名称。
编写解决方案,以获取Sales表中所有sale_id对应的product_name以及该产品的所有year和price。
返回结果表无顺序要求。
通过SQL:
select p.product_name, s.year, s.price
from Sales s
join Product p on s.product_id = p.product_id
1581. 进店却未进行过交易的顾客
表:Visits
+-------------+---------+
| Column Name | Type |
+-------------+---------+
| visit_id | int |
| customer_id | int |
+-------------+---------+
visit_id 是该表中具有唯一值的列。
该表包含有关光临过购物中心的顾客的信息。
表:Transactions
+----------------+---------+
| Column Name | Type |
+----------------+---------+
| transaction_id | int |
| visit_id | int |
| amount | int |
+----------------+---------+
transaction_id 是该表中具有唯一值的列。
此表包含 visit_id 期间进行的交易的信息。
有一些顾客可能光顾了购物中心但没有进行交易。请你编写一个解决方案,来查找这些顾客的ID,以及他们只光顾不交易的次数。
返回以任何顺序排序的结果表。
通过SQL:
select v.customer_id, count(*) count_no_trans
from Visits v
left join Transactions t on t.visit_id = v.visit_id
where t.transaction_id is null
group by customer_id
197. 上升的温度
表: Weather
+---------------+---------+
| Column Name | Type |
+---------------+---------+
| id | int |
| recordDate | date |
| temperature | int |
+---------------+---------+
id 是该表具有唯一值的列。
没有具有相同 recordDate 的不同行。
该表包含特定日期的温度信息
编写解决方案,找出与之前(昨天的)日期相比温度更高的所有日期的id。
返回结果无顺序要求。
通过SQL:
select w1.id
from Weather w1
join Weather w2 on w1.recordDate = DATE_ADD(w2.recordDate, INTERVAL 1 DAY)
where w1.temperature > w2.temperature
1661. 每台机器的进程平均运行时间
表: Activity
+----------------+---------+
| Column Name | Type |
+----------------+---------+
| machine_id | int |
| process_id | int |
| activity_type | enum |
| timestamp | float |
+----------------+---------+
该表展示了一家工厂网站的用户活动。
(machine_id, process_id, activity_type) 是当前表的主键(具有唯一值的列的组合)。
machine_id 是一台机器的ID号。
process_id 是运行在各机器上的进程ID号。
activity_type 是枚举类型 ('start', 'end')。
timestamp 是浮点类型,代表当前时间(以秒为单位)。
'start' 代表该进程在这台机器上的开始运行时间戳 , 'end' 代表该进程在这台机器上的终止运行时间戳。
同一台机器,同一个进程都有一对开始时间戳和结束时间戳,而且开始时间戳永远在结束时间戳前面。
现在有一个工厂网站由几台机器运行,每台机器上运行着相同数量的进程。编写解决方案,计算每台机器各自完成一个进程任务的平均耗时。
完成一个进程任务的时间指进程的'end' 时间戳 减去 'start' 时间戳。平均耗时通过计算每台机器上所有进程任务的总耗费时间除以机器上的总进程数量获得。
结果表必须包含machine_id(机器ID)和对应的average time(平均耗时)别名processing_time,且四舍五入保留3位小数。
以任意顺序返回表。
通过SQL:
自连接:
select a1.machine_id, round(avg(a2.timestamp - a1.timestamp), 3) processing_time
from Activity a1
join Activity a2 on a1.machine_id = a2.machine_idand a1.process_id = a2.process_id
where a1.activity_type = 'start' and a2.activity_type = 'end'
group by a1.machine_id
单表:
SELECT machine_id,ROUND(SUM(IF(activity_type = 'start', -timestamp, timestamp))/ COUNT(DISTINCT process_id) ,3) AS 'processing_time'
FROM Activity
GROUP BY machine_id
577. 员工奖金
表:Employee
+-------------+---------+
| Column Name | Type |
+-------------+---------+
| empId | int |
| name | varchar |
| supervisor | int |
| salary | int |
+-------------+---------+
empId 是该表中具有唯一值的列。
该表的每一行都表示员工的 id 和姓名,以及他们经理的 id 和他们的工资。
表:Bonus
+-------------+------+
| Column Name | Type |
+-------------+------+
| empId | int |
| bonus | int |
+-------------+------+
empId 是该表具有唯一值的列。
empId 是 Employee 表中 empId 的外键(reference 列)。
该表的每一行都包含一个员工的 id 和他们各自的奖金。
编写解决方案,报告每个奖金少于1000的员工的姓名和奖金数额。
以任意顺序返回结果表。
通过SQL:
select e.name, b.bonus
from Employee e
left join Bonus b on e.empId = b.empId
where b.bonus < 1000 or b.bonus is null
1280. 学生们参加各科测试的次数
学生表: Students
+---------------+---------+
| Column Name | Type |
+---------------+---------+
| student_id | int |
| student_name | varchar |
+---------------+---------+
在 SQL 中,主键为 student_id(学生ID)。
该表内的每一行都记录有学校一名学生的信息。
科目表: Subjects
+--------------+---------+
| Column Name | Type |
+--------------+---------+
| subject_name | varchar |
+--------------+---------+
在 SQL 中,主键为 subject_name(科目名称)。
每一行记录学校的一门科目名称。
考试表: Examinations
+--------------+---------+
| Column Name | Type |
+--------------+---------+
| student_id | int |
| subject_name | varchar |
+--------------+---------+
这个表可能包含重复数据(换句话说,在 SQL 中,这个表没有主键)。
学生表里的一个学生修读科目表里的每一门科目。
这张考试表的每一行记录就表示学生表里的某个学生参加了一次科目表里某门科目的测试。
查询出每个学生参加每一门科目测试的次数,结果按student_id和subject_name排序。
通过SQL:
select s.student_id, s.student_name, sub.subject_name, count(e.student_id) attended_exams
from Students s
cross join Subjects sub
left join Examinations e on e.student_id = s.student_idand e.subject_name = sub.subject_name
group by s.student_id, s.student_name, sub.subject_name
order by s.student_id, sub.subject_name
570. 至少有5名直接下属的经理
表: Employee
+-------------+---------+
| Column Name | Type |
+-------------+---------+
| id | int |
| name | varchar |
| department | varchar |
| managerId | int |
+-------------+---------+
id 是此表的主键(具有唯一值的列)。
该表的每一行表示雇员的名字、他们的部门和他们的经理的id。
如果managerId为空,则该员工没有经理。
没有员工会成为自己的管理者。
编写一个解决方案,找出至少有五个直接下属的经理。
以任意顺序返回结果表。
通过SQL:
select e.name
from Employee e
join (select managerId, count(*) cntfrom Employeegroup by managerIdhaving cnt >= 5
) tmp
on e.id = tmp.managerId
1934. 确认率
表: Signups
+----------------+----------+
| Column Name | Type |
+----------------+----------+
| user_id | int |
| time_stamp | datetime |
+----------------+----------+
User_id是该表的主键。
每一行都包含ID为user_id的用户的注册时间信息。
表: Confirmations
+----------------+----------+
| Column Name | Type |
+----------------+----------+
| user_id | int |
| time_stamp | datetime |
| action | ENUM |
+----------------+----------+
(user_id, time_stamp)是该表的主键。
user_id是一个引用到注册表的外键。
action是类型为('confirmed', 'timeout')的ENUM
该表的每一行都表示ID为user_id的用户在time_stamp请求了一条确认消息,该确认消息要么被确认('confirmed'),要么被过期('timeout')。
用户的确认率是'confirmed'消息的数量除以请求的确认消息的总数。没有请求任何确认消息的用户的确认率为0。确认率四舍五入到小数点后两位。
编写一个SQL查询来查找每个用户的确认率。
以任意顺序返回结果表。
通过SQL:
select s.user_id,round(avg(if(c.action = "confirmed", 1, 0)), 2) confirmation_rate
from Signups s
left join Confirmations c
on c.user_id = s.user_id
group by s.user_id
知识点:
在MySQL中,布尔表达式(如 c.action = 'confirmed')在数值上下文中会被隐式转换为数值:
- 真(
TRUE)被转换为 1。 - 假(
FALSE)被转换为 0。
因此,表达式c.action = 'confirmed'对于每一行来说,要么是1(如果action是'confirmed'),要么是0(否则)。当你对布尔表达式应用AVG函数时,实际上是在计算这些1和0的平均值。
聚合函数
620. 有趣的电影
表:cinema
+----------------+----------+
| Column Name | Type |
+----------------+----------+
| id | int |
| movie | varchar |
| description | varchar |
| rating | float |
+----------------+----------+
id 是该表的主键(具有唯一值的列)。
每行包含有关电影名称、类型和评级的信息。
评级为 [0,10] 范围内的小数点后 2 位浮点数。
编写解决方案,找出所有影片描述为非boring(不无聊)的并且id为奇数的影片。
返回结果按rating降序排列。
通过SQL:
select *
from cinema
where id % 2 = 1and description != "boring"
order by rating desc
1251. 平均售价
表:Prices
+---------------+---------+
| Column Name | Type |
+---------------+---------+
| product_id | int |
| start_date | date |
| end_date | date |
| price | int |
+---------------+---------+
(product_id,start_date,end_date) 是 prices 表的主键(具有唯一值的列的组合)。
prices 表的每一行表示的是某个产品在一段时期内的价格。
每个产品的对应时间段是不会重叠的,这也意味着同一个产品的价格时段不会出现交叉。
表:UnitsSold
+---------------+---------+
| Column Name | Type |
+---------------+---------+
| product_id | int |
| purchase_date | date |
| units | int |
+---------------+---------+
该表可能包含重复数据。
该表的每一行表示的是每种产品的出售日期,单位和产品 id。
编写解决方案以查找每种产品的平均售价。average_price应该四舍五入到小数点后两位。如果产品没有任何售出,则假设其平均售价为0。
返回结果表无顺序要求。
通过SQL:
select p.product_id,ifnull(round(sum(p.price * u.units) / sum(u.units), 2), 0) average_price
from Prices p
left join UnitsSold u
on u.product_id = p.product_idand u.purchase_date between p.start_date and p.end_date
group by p.product_id
1075. 项目员工 I
项目表Project:
+-------------+---------+
| Column Name | Type |
+-------------+---------+
| project_id | int |
| employee_id | int |
+-------------+---------+
主键为 (project_id, employee_id)。
employee_id 是员工表 Employee 表的外键。
这张表的每一行表示 employee_id 的员工正在 project_id 的项目上工作。
员工表Employee:
+------------------+---------+
| Column Name | Type |
+------------------+---------+
| employee_id | int |
| name | varchar |
| experience_years | int |
+------------------+---------+
主键是 employee_id。数据保证 experience_years 非空。
这张表的每一行包含一个员工的信息。
请写一个SQL语句,查询每一个项目中员工的平均工作年限,精确到小数点后两位。以任意顺序返回结果表。
通过SQL:
select p.project_id,round(avg(e.experience_years), 2) average_years
from Project p
join Employee e on e.employee_id = p.employee_id
group by p.project_id
1633. 各赛事的用户注册率
用户表: Users
+-------------+---------+
| Column Name | Type |
+-------------+---------+
| user_id | int |
| user_name | varchar |
+-------------+---------+
user_id 是该表的主键(具有唯一值的列)。
该表中的每行包括用户 ID 和用户名。
注册表:Register
+-------------+---------+
| Column Name | Type |
+-------------+---------+
| contest_id | int |
| user_id | int |
+-------------+---------+
(contest_id, user_id) 是该表的主键(具有唯一值的列的组合)。
该表中的每行包含用户的 ID 和他们注册的赛事。
编写解决方案统计出各赛事的用户注册百分率,保留两位小数。
返回的结果表按percentage的降序排序,若相同则按contest_id的升序排序。
通过SQL:
select r.contest_id,round(count(*) / (select count(*) from Users) * 100, 2) percentage
from Register r
join Users u on u.user_id = r.user_id
group by r.contest_id
order by percentage desc, contest_id asc
1211. 查询结果的质量和占比
Queries 表:
+-------------+---------+
| Column Name | Type |
+-------------+---------+
| query_name | varchar |
| result | varchar |
| position | int |
| rating | int |
+-------------+---------+
此表可能有重复的行。
此表包含了一些从数据库中收集的查询信息。
“位置”(position)列的值为 1 到 500 。
“评分”(rating)列的值为 1 到 5 。评分小于 3 的查询被定义为质量很差的查询。
将查询结果的质量quality定义为:
各查询结果的评分与其位置之间比率的平均值。
将劣质查询百分比poor_query_percentage定义为:
评分小于3的查询结果占全部查询结果的百分比。
编写解决方案,找出每次的query_name、quality和poor_query_percentage。
quality和poor_query_percentage都应四舍五入到小数点后两位。
以任意顺序返回结果表。
通过SQL:
select query_name,round(avg(rating / position), 2) quality,round(sum(if(rating < 3, 1, 0)) / count(*) * 100, 2) poor_query_percentage
from Queries
group by query_name
1193. 每月交易 I
表:Transactions
+---------------+---------+
| Column Name | Type |
+---------------+---------+
| id | int |
| country | varchar |
| state | enum |
| amount | int |
| trans_date | date |
+---------------+---------+
id 是这个表的主键。
该表包含有关传入事务的信息。
state 列类型为 ["approved", "declined"] 之一。
编写一个sql查询来查找每个月和每个国家/地区的事务数及其总金额、已批准的事务数及其总金额。
以任意顺序返回结果表。
通过SQL:
select date_format(trans_date, '%Y-%m') `month`,country,count(*) trans_count,sum(if(state = 'approved', 1, 0)) approved_count,sum(amount) trans_total_amount,sum(if(state = 'approved', amount, 0)) approved_total_amount
from Transactions
group by `month`, country
1174. 即时食物配送 II
配送表: Delivery
+-----------------------------+---------+
| Column Name | Type |
+-----------------------------+---------+
| delivery_id | int |
| customer_id | int |
| order_date | date |
| customer_pref_delivery_date | date |
+-----------------------------+---------+
delivery_id 是该表中具有唯一值的列。
该表保存着顾客的食物配送信息,顾客在某个日期下了订单,并指定了一个期望的配送日期(和下单日期相同或者在那之后)。
如果顾客期望的配送日期和下单日期相同,则该订单称为 「即时订单」,否则称为「计划订单」。
「首次订单」是顾客最早创建的订单。我们保证一个顾客只会有一个「首次订单」。
编写解决方案以获取即时订单在所有用户的首次订单中的比例。保留两位小数。
通过SQL:
select round(sum(d1.order_date = d1.customer_pref_delivery_date) / count(*) * 100, 2) immediate_percentage
from Delivery d1
where d1.order_date = (select min(d2.order_date)from Delivery d2where d2.customer_id = d1.customer_id
)
550. 游戏玩法分析 IV
Table: Activity
+--------------+---------+
| Column Name | Type |
+--------------+---------+
| player_id | int |
| device_id | int |
| event_date | date |
| games_played | int |
+--------------+---------+
(player_id,event_date)是此表的主键(具有唯一值的列的组合)。
这张表显示了某些游戏的玩家的活动情况。
每一行是一个玩家的记录,他在某一天使用某个设备注销之前登录并玩了很多游戏(可能是 0)。
编写解决方案,报告在首次登录的第二天再次登录的玩家的比率,四舍五入到小数点后两位。换句话说,你需要计算从首次登录后的第二天登录的玩家数量,并将其除以总玩家数。
通过SQL:
select round(sum(date_add(first_date, interval 1 day) = event_date) / count(distinct player_id), 2) fraction
from (select player_id,event_date,min(event_date) over (partition by player_id) first_datefrom Activity
) tmp
排序和分组
2356. 每位教师所教授的科目种类的数量
表: Teacher
+-------------+------+
| Column Name | Type |
+-------------+------+
| teacher_id | int |
| subject_id | int |
| dept_id | int |
+-------------+------+
在 SQL 中,(subject_id, dept_id) 是该表的主键。
该表中的每一行都表示带有 teacher_id 的教师在系 dept_id 中教授科目 subject_id。
查询每位老师在大学里教授的科目种类的数量。
以任意顺序返回结果表。
通过SQL:
select teacher_id,count(distinct subject_id) cnt
from Teacher
group by teacher_id
1141. 查询近30天活跃用户数
表:Activity
+---------------+---------+
| Column Name | Type |
+---------------+---------+
| user_id | int |
| session_id | int |
| activity_date | date |
| activity_type | enum |
+---------------+---------+
该表没有包含重复数据。
activity_type 列是 ENUM(category) 类型, 从 ('open_session', 'end_session', 'scroll_down', 'send_message') 取值。
该表记录社交媒体网站的用户活动。
注意,每个会话只属于一个用户。
编写解决方案,统计截至2019-07-27(包含2019-07-27),近30天的每日活跃用户数(当天只要有一条活动记录,即为活跃用户)。
以任意顺序返回结果表。
通过SQL:
select activity_date `day`, count(distinct user_id) active_users
from Activity
where activity_date between date_sub('2019-07-27', interval 29 day) and '2019-07-27'
group by activity_date
1084. 销售分析 III
表: Product
+--------------+---------+
| Column Name | Type |
+--------------+---------+
| product_id | int |
| product_name | varchar |
| unit_price | int |
+--------------+---------+
product_id 是该表的主键(具有唯一值的列)。
该表的每一行显示每个产品的名称和价格。
表:Sales
+-------------+---------+
| Column Name | Type |
+-------------+---------+
| seller_id | int |
| product_id | int |
| buyer_id | int |
| sale_date | date |
| quantity | int |
| price | int |
+------ ------+---------+
这个表可能有重复的行。
product_id 是 Product 表的外键(reference 列)。
该表的每一行包含关于一个销售的一些信息。
编写解决方案,报告2019年春季才售出的产品。即仅在 2019-01-01(含)至2019-03-31(含)之间出售的商品。
以任意顺序返回结果表。
通过SQL:
select s.product_id,p.product_name
from Sales s
join Product p on p.product_id = s.product_id
group by s.product_id
having min(s.sale_date) >= '2019-01-01'and max(s.sale_date) <= '2019-03-31'
596. 超过 5 名学生的课
表: Courses
+-------------+---------+
| Column Name | Type |
+-------------+---------+
| student | varchar |
| class | varchar |
+-------------+---------+
(student, class)是该表的主键(不同值的列的组合)。
该表的每一行表示学生的名字和他们注册的班级。
查询至少有 5 个学生 的所有班级。
以任意顺序返回结果表。
通过SQL:
select class
from Courses
group by class
having count(*) >= 5
1729. 求关注者的数量
表: Followers
+-------------+------+
| Column Name | Type |
+-------------+------+
| user_id | int |
| follower_id | int |
+-------------+------+
(user_id, follower_id) 是这个表的主键(具有唯一值的列的组合)。
该表包含一个关注关系中关注者和用户的编号,其中关注者关注用户。
编写解决方案,对于每一个用户,返回该用户的关注者数量。
按user_id的顺序返回结果表。
通过SQL:
select user_id,count(*) followers_count
from Followers
group by user_id
order by user_id
619. 只出现一次的最大数字
MyNumbers 表:
+-------------+------+
| Column Name | Type |
+-------------+------+
| num | int |
+-------------+------+
该表可能包含重复项(换句话说,在SQL中,该表没有主键)。
这张表的每一行都含有一个整数。
单一数字是在MyNumbers表中只出现一次的数字。
找出最大的单一数字。如果不存在单一数字,则返回null。
通过SQL:
select max(num) num
from (select num,count(*) cntfrom MyNumbersgroup by numhaving cnt = 1
) tmp
1045. 买下所有产品的客户
Customer 表:
+-------------+---------+
| Column Name | Type |
+-------------+---------+
| customer_id | int |
| product_key | int |
+-------------+---------+
该表可能包含重复的行。
customer_id 不为 NULL。
product_key 是 Product 表的外键(reference 列)。
Product 表:
+-------------+---------+
| Column Name | Type |
+-------------+---------+
| product_key | int |
+-------------+---------+
product_key 是这张表的主键(具有唯一值的列)。
编写解决方案,报告Customer表中购买了Product表中所有产品的客户的id。
返回结果表无顺序要求。
通过SQL:
select customer_id
from Customer
group by customer_id
having count(distinct product_key) = (select count(*) from Product
)
高级查询和连接
1731. 每位经理的下属员工数量
表:Employees
+-------------+----------+
| Column Name | Type |
+-------------+----------+
| employee_id | int |
| name | varchar |
| reports_to | int |
| age | int |
+-------------+----------+
employee_id 是这个表中具有不同值的列。
该表包含员工以及需要听取他们汇报的上级经理的 ID 的信息。 有些员工不需要向任何人汇报(reports_to 为空)。
对于此问题,我们将至少有一个其他员工需要向他汇报的员工,视为一个经理。
编写一个解决方案来返回需要听取汇报的所有经理的ID、名称、直接向该经理汇报的员工人数,以及这些员工的平均年龄,其中该平均年龄需要四舍五入到最接近的整数。
返回的结果集需要按照employee_id进行排序。
通过SQL:
select e2.employee_id,e2.name,count(*) reports_count,round(avg(e1.age)) average_age
from Employees e1
join Employees e2 on e2.employee_id = e1.reports_to
group by e1.reports_to
order by e2.employee_id
1789. 员工的直属部门
表:Employee
+---------------+---------+
| Column Name | Type |
+---------------+---------+
| employee_id | int |
| department_id | int |
| primary_flag | varchar |
+---------------+---------+
这张表的主键为 employee_id, department_id (具有唯一值的列的组合)
employee_id 是员工的ID
department_id 是部门的ID,表示员工与该部门有关系
primary_flag 是一个枚举类型,值分别为('Y', 'N'). 如果值为'Y',表示该部门是员工的直属部门。 如果值是'N',则否
一个员工可以属于多个部门。当一个员工加入超过一个部门的时候,他需要决定哪个部门是他的直属部门。请注意,当员工只加入一个部门的时候,那这个部门将默认为他的直属部门,虽然表记录的值为'N'.
请编写解决方案,查出员工所属的直属部门。
返回结果没有顺序要求。
通过SQL:
select employee_id,department_id
from Employee
where primary_flag = 'Y'
union
select employee_id,department_id
from Employee
group by employee_id
having count(*) = 1
610. 判断三角形
表: Triangle
+-------------+------+
| Column Name | Type |
+-------------+------+
| x | int |
| y | int |
| z | int |
+-------------+------+
在 SQL 中,(x, y, z)是该表的主键列。
该表的每一行包含三个线段的长度。
对每三个线段报告它们是否可以形成一个三角形。
以任意顺序返回结果表。
通过SQL:
select x,y,z,if(x + y > z and x + z > y and y + z > x, 'Yes', 'No') triangle
from Triangle
180. 连续出现的数字
表:Logs
+-------------+---------+
| Column Name | Type |
+-------------+---------+
| id | int |
| num | varchar |
+-------------+---------+
在 SQL 中,id 是该表的主键。
id 是一个自增列。
找出所有至少连续出现三次的数字。
返回的结果表中的数据可以按 任意顺序 排列。
通过SQL:
with ConsecutiveGroups as (select id,num,id - row_number() over (partition by num order by id) as group_idfrom Logs
)
select distinct num ConsecutiveNums
from ConsecutiveGroups
group by num, group_id
having count(*) >= 3
1164. 指定日期的产品价格
产品数据表: Products
+---------------+---------+
| Column Name | Type |
+---------------+---------+
| product_id | int |
| new_price | int |
| change_date | date |
+---------------+---------+
(product_id, change_date) 是此表的主键(具有唯一值的列组合)。
这张表的每一行分别记录了 某产品 在某个日期 更改后 的新价格。
一开始,所有产品价格都为 10。
编写一个解决方案,找出在2019-08-16所有产品的价格。
以任意顺序返回结果表。
通过SQL:
select p.product_id,ifnull(new_price, 10) price
from (select distinct product_id from Products
) p
left join
(select *,row_number() over (partition by product_id order by change_date desc) rnfrom Productswhere change_date <= '2019-08-16'
) tmp
on p.product_id = tmp.product_idand tmp.rn = 1
1204. 最后一个能进入巴士的人
表: Queue
+-------------+---------+
| Column Name | Type |
+-------------+---------+
| person_id | int |
| person_name | varchar |
| weight | int |
| turn | int |
+-------------+---------+
person_id 是这个表具有唯一值的列。
该表展示了所有候车乘客的信息。
表中 person_id 和 turn 列将包含从 1 到 n 的所有数字,其中 n 是表中的行数。
turn 决定了候车乘客上巴士的顺序,其中 turn=1 表示第一个上巴士,turn=n 表示最后一个上巴士。
weight 表示候车乘客的体重,以千克为单位。
有一队乘客在等着上巴士。然而,巴士有1000千克的重量限制,所以其中一部分乘客可能无法上巴士。
编写解决方案找出 最后一个 上巴士且不超过重量限制的乘客,并报告person_name 。题目测试用例确保顺位第一的人可以上巴士且不会超重。
通过SQL:
with t1 as(select *,sum(weight) over(order by turn) sum_weightfrom Queue
)
select person_name
from t1
where t1.sum_weight <= 1000
order by sum_weight desc
limit 1
1907. 按分类统计薪水
表: Accounts
+-------------+------+
| 列名 | 类型 |
+-------------+------+
| account_id | int |
| income | int |
+-------------+------+
在 SQL 中,account_id 是这个表的主键。
每一行都包含一个银行帐户的月收入的信息。
查询每个工资类别的银行账户数量。 工资类别如下:
"Low Salary":所有工资 严格低于20000美元。"Average Salary": 包含 范围内的所有工资[$20000, $50000]。"High Salary":所有工资 严格大于50000美元。
结果表必须包含所有三个类别。 如果某个类别中没有帐户,则报告 0 。
按任意顺序返回结果表。
通过SQL:
select 'Low Salary' category,sum(if(income < 20000, 1, 0)) accounts_count
from Accounts
union all
select 'Average Salary' category,sum(if(income between 20000 and 50000, 1, 0)) accounts_count
from Accounts
union all
select 'High Salary' category,sum(if(income > 50000, 1, 0)) accounts_count
from Accounts
子查询
1978. 上级经理已离职的公司员工
表: Employees
+-------------+----------+
| Column Name | Type |
+-------------+----------+
| employee_id | int |
| name | varchar |
| manager_id | int |
| salary | int |
+-------------+----------+
在 SQL 中,employee_id 是这个表的主键。
这个表包含了员工,他们的薪水和上级经理的id。
有一些员工没有上级经理(其 manager_id 是空值)。
查找这些员工的id,他们的薪水严格少于$30000 并且他们的上级经理已离职。当一个经理离开公司时,他们的信息需要从员工表中删除掉,但是表中的员工的manager_id这一列还是设置的离职经理的id 。
返回的结果按照employee_id 从小到大排序。
通过SQL:
select employee_id
from Employees
where salary < 30000and manager_id not in (select distinct employee_id from Employees)
order by employee_id
626. 换座位
表: Seat
+-------------+---------+
| Column Name | Type |
+-------------+---------+
| id | int |
| student | varchar |
+-------------+---------+
id 是该表的主键(唯一值)列。
该表的每一行都表示学生的姓名和 ID。
ID 序列始终从 1 开始并连续增加。
编写解决方案来交换每两个连续的学生的座位号。如果学生的数量是奇数,则最后一个学生的id不交换。
按id升序 返回结果表。
通过SQL:
select (casewhen mod(s.id, 2) = 1 and s.id != seat_count.cnt then s.id + 1when mod(s.id, 2) = 1 and s.id = seat_count.cnt then s.idelse s.id - 1end) id,student
from Seat s, (select count(*) cnt from Seat
) seat_count
order by id
1341. 电影评分
表:Movies
+---------------+---------+
| Column Name | Type |
+---------------+---------+
| movie_id | int |
| title | varchar |
+---------------+---------+
movie_id 是这个表的主键(具有唯一值的列)。
title 是电影的名字。
每部电影都有一个唯一的 title。
表:Users
+---------------+---------+
| Column Name | Type |
+---------------+---------+
| user_id | int |
| name | varchar |
+---------------+---------+
user_id 是表的主键(具有唯一值的列)。
'name' 列具有唯一值。
表:MovieRating
+---------------+---------+
| Column Name | Type |
+---------------+---------+
| movie_id | int |
| user_id | int |
| rating | int |
| created_at | date |
+---------------+---------+
(movie_id, user_id) 是这个表的主键(具有唯一值的列的组合)。
这个表包含用户在其评论中对电影的评分 rating 。
created_at 是用户的点评日期。
请你编写一个解决方案:
- 查找评论电影数量最多的用户名。如果出现平局,返回字典序较小的用户名。
- 查找在
February 2020平均评分最高 的电影名称。如果出现平局,返回字典序较小的电影名称。
字典序 ,即按字母在字典中出现顺序对字符串排序,字典序较小则意味着排序靠前。
通过SQL:
(
select u.name results
from MovieRating mr
join Movies m on m.movie_id = mr.movie_id
join Users u on u.user_id = mr.user_id
group by mr.user_id
order by count(*) desc, u.name asc
limit 1
)
union all
(
select m.title results
from Movies m
join MovieRating mr on m.movie_id = mr.movie_id
where date_format(mr.created_at, '%Y-%m') = '2020-02'
group by mr.movie_id
order by avg(mr.rating) desc, m.title asc
limit 1
)
1321. 餐馆营业额变化增长
表: Customer
+---------------+---------+
| Column Name | Type |
+---------------+---------+
| customer_id | int |
| name | varchar |
| visited_on | date |
| amount | int |
+---------------+---------+
在 SQL 中,(customer_id, visited_on) 是该表的主键。
该表包含一家餐馆的顾客交易数据。
visited_on 表示 (customer_id) 的顾客在 visited_on 那天访问了餐馆。
amount 是一个顾客某一天的消费总额。
你是餐馆的老板,现在你想分析一下可能的营业额变化增长(每天至少有一位顾客)。
计算以7天(某日期 + 该日期前的 6 天)为一个时间段的顾客消费平均值。average_amount要保留两位小数。
结果按visited_on升序排序。
通过SQL:
select c1.visited_on,sum(c2.amount) amount,round(sum(c2.amount) / 7, 2) average_amount
from (select distinct visited_on from Customer
) c1
join Customer c2
on c2.visited_on between date_sub(c1.visited_on, interval 6 day) and c1.visited_on
where date_sub(c1.visited_on, interval 6 day) >= (select min(visited_on) from Customer)
group by c1.visited_on
order by c1.visited_on
602. 好友申请 II :谁有最多的好友
RequestAccepted 表:
+----------------+---------+
| Column Name | Type |
+----------------+---------+
| requester_id | int |
| accepter_id | int |
| accept_date | date |
+----------------+---------+
(requester_id, accepter_id) 是这张表的主键(具有唯一值的列的组合)。
这张表包含发送好友请求的人的 ID ,接收好友请求的人的 ID ,以及好友请求通过的日期。
编写解决方案,找出拥有最多的好友的人和他拥有的好友数目。
生成的测试用例保证拥有最多好友数目的只有 1 个人。
通过SQL:
select id, count(id) num
from (select accepter_id id from RequestAcceptedunion allselect requester_id id from RequestAccepted
) tmp
group by tmp.id
order by num desc
limit 1
585. 2016年的投资
Insurance 表:
+-------------+-------+
| Column Name | Type |
+-------------+-------+
| pid | int |
| tiv_2015 | float |
| tiv_2016 | float |
| lat | float |
| lon | float |
+-------------+-------+
pid 是这张表的主键(具有唯一值的列)。
表中的每一行都包含一条保险信息,其中:
pid 是投保人的投保编号。
tiv_2015 是该投保人在 2015 年的总投保金额,tiv_2016 是该投保人在 2016 年的总投保金额。
lat 是投保人所在城市的纬度。题目数据确保 lat 不为空。
lon 是投保人所在城市的经度。题目数据确保 lon 不为空。
编写解决方案报告 2016 年 (tiv_2016) 所有满足下述条件的投保人的投保金额之和:
- 他在 2015 年的投保额 (
tiv_2015) 至少跟一个其他投保人在 2015 年的投保额相同。 - 他所在的城市必须与其他投保人都不同(也就是说 (
lat, lon) 不能跟其他任何一个投保人完全相同)。
tiv_2016四舍五入的两位小数 。
通过SQL:
select round(sum(i1.tiv_2016), 2) tiv_2016
from Insurance i1
where tiv_2015 in (select distinct tiv_2015 from Insurancewhere pid != i1.pid
) and (lat, lon) not in (select distinct lat, lon from Insurancewhere pid != i1.pid
)
185. 部门工资前三高的所有员工
表: Employee
+--------------+---------+
| Column Name | Type |
+--------------+---------+
| id | int |
| name | varchar |
| salary | int |
| departmentId | int |
+--------------+---------+
id 是该表的主键列(具有唯一值的列)。
departmentId 是 Department 表中 ID 的外键(reference 列)。
该表的每一行都表示员工的ID、姓名和工资。它还包含了他们部门的ID。
表: Department
+-------------+---------+
| Column Name | Type |
+-------------+---------+
| id | int |
| name | varchar |
+-------------+---------+
id 是该表的主键列(具有唯一值的列)。
该表的每一行表示部门ID和部门名。
公司的主管们感兴趣的是公司每个部门中谁赚的钱最多。一个部门的高收入者是指一个员工的工资在该部门的不同工资中排名前三 。
编写解决方案,找出每个部门中收入高的员工 。
以任意顺序返回结果表。
通过SQL:
关联子查询
select d.name Department, e.name Employee, e.salary Salary
from Employee e
join Department d on e.departmentId = d.id
where (select count(distinct salary)from Employee e2where e2.departmentId = e.departmentId ande2.salary > e.salary
) < 3
窗口函数
WITH RankedSalaries AS (SELECT e.name AS Employee,e.salary AS Salary,d.name AS Department,DENSE_RANK() OVER (PARTITION BY e.departmentId ORDER BY e.salary DESC) as salary_rankFROM Employee eJOIN Department d ON e.departmentId = d.id
)
SELECT Department,Employee,Salary
FROM RankedSalaries
WHERE salary_rank <= 3
ORDER BY Department, Salary DESC;
高级字符串函数 / 正则表达式 / 子句
1667. 修复表中的名字
表: Users
+----------------+---------+
| Column Name | Type |
+----------------+---------+
| user_id | int |
| name | varchar |
+----------------+---------+
user_id 是该表的主键(具有唯一值的列)。
该表包含用户的 ID 和名字。名字仅由小写和大写字符组成。
编写解决方案,修复名字,使得只有第一个字符是大写的,其余都是小写的。
返回按 user_id 排序的结果表。
思路:利用字符串操作函数,先截取,各自转换之后再拼接
通过SQL:
select user_id,concat(upper(substring(name, 1, 1)), lower(substring(name, 2))) name
from Users
order by user_id
注意:
- 对于Mysql操作语句中被操作对象参数来说,下标是从1开始的。
- 对于查询结果(DQL)来说,是从0开始的。
1527. 患某种疾病的患者
患者信息表: Patients
+--------------+---------+
| Column Name | Type |
+--------------+---------+
| patient_id | int |
| patient_name | varchar |
| conditions | varchar |
+--------------+---------+
在 SQL 中,patient_id (患者 ID)是该表的主键。
'conditions' (疾病)包含 0 个或以上的疾病代码,以空格分隔。
这个表包含医院中患者的信息。
查询患有 I 类糖尿病的患者 ID (patient_id)、患者姓名(patient_name)以及其患有的所有疾病代码(conditions)。I 类糖尿病的代码总是包含前缀 DIAB1 。
按任意顺序返回结果表。
思路:利用正则表达式
通过SQL:
select *
from Patients
where conditions regexp '^DIAB1|\\sDIAB1'
196. 删除重复的电子邮箱
表: Person
+-------------+---------+
| Column Name | Type |
+-------------+---------+
| id | int |
| email | varchar |
+-------------+---------+
id 是该表的主键列(具有唯一值的列)。
该表的每一行包含一封电子邮件。电子邮件将不包含大写字母。
编写解决方案删除所有重复的电子邮件,只保留一个具有最小id的唯一电子邮件。
(对于SQL用户,请注意你应该编写一个DELETE语句而不是SELECT 语句。)
(对于Pandas 用户,请注意你应该直接修改Person表。)
运行脚本后,显示的答案是Person表。驱动程序将首先编译并运行您的代码片段,然后再显示Person表。Person表的最终顺序无关紧要 。
通过SQL:
delete from Person
where id not in (select * from (select min(id)from Persongroup by email) tmp
)
176. 第二高的薪水
Employee 表:
+-------------+------+
| Column Name | Type |
+-------------+------+
| id | int |
| salary | int |
+-------------+------+
id 是这个表的主键。
表的每一行包含员工的工资信息。
查询并返回Employee表中第二高的不同薪水 。如果不存在第二高的薪水,查询应该返回null(Pandas 则返回 None) 。
思路一:窗口函数
通过SQL:
select if(count(*) = 0, null, salary) SecondHighestSalary
from (select *,dense_rank() over(order by salary desc) rkfrom Employee
) tmp
where tmp.rk = 2
思路二:排序+limit
通过SQL:
select ifnull(( select distinct salary from Employeeorder by salary desclimit 1, 1)
, null) SecondHighestSalary
1484. 按日期分组销售产品
表 Activities:
+-------------+---------+
| 列名 | 类型 |
+-------------+---------+
| sell_date | date |
| product | varchar |
+-------------+---------+
该表没有主键(具有唯一值的列)。它可能包含重复项。
此表的每一行都包含产品名称和在市场上销售的日期。
编写解决方案找出每个日期、销售的不同产品的数量及其名称。
每个日期的销售产品名称应按词典序排列。
返回按sell_date排序的结果表。
通过SQL:
select sell_date,count(distinct product) num_sold,group_concat(distinct product order by product asc) products
from Activities
group by sell_date
order by sell_date
1327. 列出指定时间段内所有的下单产品
表: Products
+------------------+---------+
| Column Name | Type |
+------------------+---------+
| product_id | int |
| product_name | varchar |
| product_category | varchar |
+------------------+---------+
product_id 是该表主键(具有唯一值的列)。
该表包含该公司产品的数据。
表: Orders
+---------------+---------+
| Column Name | Type |
+---------------+---------+
| product_id | int |
| order_date | date |
| unit | int |
+---------------+---------+
该表可能包含重复行。
product_id 是表单 Products 的外键(reference 列)。
unit 是在日期 order_date 内下单产品的数目。
写一个解决方案,要求获取在 2020 年 2 月份下单的数量不少于 100 的产品的名字和数目。
返回结果表单的顺序无要求 。
通过SQL:
select p.product_name,tmp.sum_unit unit
from (select product_id,sum(unit) sum_unitfrom Orderswhere date_format(order_date, '%Y-%m') = '2020-02'group by product_idhaving sum(unit) >= 100
) tmp
join Products p
on p.product_id = tmp.product_id
1517. 查找拥有有效邮箱的用户
表: Users
+---------------+---------+
| Column Name | Type |
+---------------+---------+
| user_id | int |
| name | varchar |
| mail | varchar |
+---------------+---------+
user_id 是该表的主键(具有唯一值的列)。
该表包含了网站已注册用户的信息。有一些电子邮件是无效的。
编写一个解决方案,以查找具有有效电子邮件的用户。
一个有效的电子邮件具有前缀名称和域,其中:
- 前缀 名称是一个字符串,可以包含字母(大写或小写),数字,下划线
'_',点'.'和(或)破折号'-'。前缀名称必须以字母开头。 - 域为
'@leetcode.com'。
以任何顺序返回结果表。
思路:利用正则表达式,注意有一个数据点要区分大小写,所以用regexp_like函数+c参数用于区分大小写。
通过SQL:
select *
from Users
where regexp_like(mail, '^[A-Za-z][A-Za-z0-9_.-]*@leetcode\\.com$', 'c')
