【力扣高频 SQL 50 题(基础版)】10~20道题解

138 阅读7分钟

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 的员工的姓名和奖金数额。

以 任意顺序 返回结果表。

select em.name, bo.bonus
from Employee em
left join Bonus bo
on em.empId=bo.empId
where bo.bonus<1000 or bo.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 排序。

select 
    stu.student_id, stu.student_name, sub.subject_name, IFNULL(attended_exams, 0) attended_exams
from 
    Students stu
cross join 
    Subjects sub
left join(
    select student_id, subject_name, count(*) attended_exams
    from Examinations ex
    group by ex.student_id, ex.subject_name
) t1
on stu.student_id=t1.student_id and sub.subject_name=t1.subject_name
order by stu.student_id, sub.subject_name 

570. 至少有5名直接下属的经理

表: Employee

+-------------+---------+
| Column Name | Type    |
+-------------+---------+
| id          | int     |
| name        | varchar |
| department  | varchar |
| managerId   | int     |
+-------------+---------+
id 是此表的主键(具有唯一值的列)。
该表的每一行表示雇员的名字、他们的部门和他们的经理的id。
如果managerId为空,则该员工没有经理。
没有员工会成为自己的管理者。

编写一个解决方案,找出至少有五个直接下属的经理。

以 任意顺序 返回结果表。

select 
    name
from(
    select 
        e1.id, e2.name, count(*) employeenums
    from
        Employee e1
    join
        Employee e2
    on 
        e1.managerId=e2.id
    group by
        e2.id
    ) t1
where employeenums>=5;

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查询来查找每个用户的 确认率 。

以 任意顺序 返回结果表。

select
    si.user_id, round(ifnull(confirmed_nums, 0)/ifnull(all_nums, 1), 2) confirmation_rate 
from
    Signups si
left join(
    select
        co2.user_id, count(*) confirmed_nums
    from
        Confirmations co2
    where 
        co2.action='confirmed' 
    group by
        co2.user_id
    ) as t2
on 
    si.user_id=t2.user_id
left join(
    select
        co3.user_id, count(*) all_nums
    from 
        Confirmations co3
    group by
        co3.user_id) as t1
on
    t1.user_id=si.user_id

620. 有趣的电影

表:cinema

+----------------+----------+
| Column Name    | Type     |
+----------------+----------+
| id             | int      |
| movie          | varchar  |
| description    | varchar  |
| rating         | float    |
+----------------+----------+
id 是该表的主键(具有唯一值的列)。
每行包含有关电影名称、类型和评级的信息。
评级为 [0,10] 范围内的小数点后 2 位浮点数。

编写解决方案,找出所有影片描述为  boring (不无聊) 的并且 id 为奇数 的影片。

返回结果按 rating 降序排列

select
    *
from
    cinema
where
    description!='boring' and mod(id,2)=1
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。

返回结果表 无顺序要求 。

select 
    p.product_id , ifnull(round(sum(price*units)/sum(units),2),0) average_price
from
    Prices p
left join 
    UnitsSold u
on
    p.product_id=u.product_id and (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 语句,查询每一个项目中员工的 平均 工作年限,精确到小数点后两位

以 任意 顺序返回结果表。

# Write your MySQL query statement below
# 查询每个项目中员工的平均工作年限:
    # 先拼接员工和项目表
    # 按照项目分组求experience_years 平均值
    # 最后使用round函数格式化输出
select
    project_id, round(avg(experience_years), 2) average_years 
from
    Project j
left join 
    Employee e
on
    j.employee_id=e.employee_id
group by 
    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 的 升序 排序。

select
    t1.contest_id, round((Register_num/all_people)*100, 2) percentage 
from
    (select
        contest_id, count(*) Register_num
    from
        Register r
    group by 
        r.contest_id) t1
join
    (select 
        count(*) all_people
    from
        Users) t2
order by percentage desc, contest_id asc;

1211. 查询结果的质量和占比

Queries 表: 

+-------------+---------+
| Column Name | Type    |
+-------------+---------+
| query_name  | varchar |
| result      | varchar |
| position    | int     |
| rating      | int     |
+-------------+---------+
此表可能有重复的行。
此表包含了一些从数据库中收集的查询信息。
“位置”(position)列的值为 1500 。
“评分”(rating)列的值为 15 。评分小于 3 的查询被定义为质量很差的查询。

将查询结果的质量 quality 定义为:

各查询结果的评分与其位置之间比率的平均值。

将劣质查询百分比 poor_query_percentage 定义为:

评分小于 3 的查询结果占全部查询结果的百分比。

编写解决方案,找出每次的 query_name 、 quality 和 poor_query_percentage

quality 和 poor_query_percentage 都应 四舍五入到小数点后两位 。

以 任意顺序 返回结果表。

select 
    query_name, 
    round(avg(rating/position), 2) quality, 
    round(sum(if(rating<3, 1, 0))*100/count(*), 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 查询来查找每个月和每个国家/地区的事务数及其总金额、已批准的事务数及其总金额。

以 任意顺序 返回结果表。

select
    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(
    select
        *, date_format(trans_date, "%Y-%m") month
    from
        Transactions t) t1
group by 
    month,country