以下题目均来自力扣
表: UserVisits
+-------------+------+
| Column Name | Type |
+-------------+------+
| user_id | int |
| visit_date | date |
+-------------+------+
该表没有主键。
该表包含用户访问某特定零售商的日期日志。
假设今天的日期是 ‘2021-1-1’ 。
编写 SQL 语句,对于每个 user_id ,求出每次访问及其下一个访问(若该次访问是最后一次,则为今天)之间最大的空档期天数 window 。
返回结果表,按用户编号 user_id 排序。
查询格式如下示例所示:
UserVisits 表:
+---------+------------+
| user_id | visit_date |
+---------+------------+
| 1 | 2020-11-28 |
| 1 | 2020-10-20 |
| 1 | 2020-12-3 |
| 2 | 2020-10-5 |
| 2 | 2020-12-9 |
| 3 | 2020-11-11 |
+---------+------------+
结果表:
+---------+---------------+
| user_id | biggest_window|
+---------+---------------+
| 1 | 39 |
| 2 | 65 |
| 3 | 51 |
+---------+---------------+
对于第一个用户,问题中的空档期在以下日期之间:
- 2020-10-20 至 2020-11-28 ,共计 39 天。
- 2020-11-28 至 2020-12-3 ,共计 5 天。
- 2020-12-3 至 2021-1-1 ,共计 29 天。
由此得出,最大的空档期为 39 天。
对于第二个用户,问题中的空档期在以下日期之间:
- 2020-10-5 至 2020-12-9 ,共计 65 天。
- 2020-12-9 至 2021-1-1 ,共计 23 天。
由此得出,最大的空档期为 65 天。
对于第三个用户,问题中的唯一空档期在 2020-11-11 至 2021-1-1 之间,共计 51 天。
# Write your MySQL query statement below
with tmp as(
select
user_id,
visit_date,
lead(visit_date,1,'2021-1-1') over(partition by user_id order by visit_date) as next_day
from
uservisits
)
select
user_id,
max(datediff(next_day,visit_date)) biggest_window
from
tmp
group by
user_id
;
lead(col,offset,default)
col - 指你要操作的那一列
offset - 偏移几行,如果是1就是下1行,以此类推
default - 如果下一行不存在,用什么值填充
lag(col,offset,default)
col - 指你要操作的那一行
offset - 偏移几行,如果是1就是上1行,以此类推
default - 如果上一行不存在,用default进行填充
表: Boxes
+--------------+------+
| Column Name | Type |
+--------------+------+
| box_id | int |
| chest_id | int |
| apple_count | int |
| orange_count | int |
+--------------+------+
box_id 是该表的主键。
chest_id 是 chests 表的外键。
该表包含大箱子 (box) 中包含的苹果和橘子的个数。每个大箱子中可能包含一个小盒子 (chest) ,小盒子中也包含若干苹果和橘子。
表: Chests
+--------------+------+
| Column Name | Type |
+--------------+------+
| chest_id | int |
| apple_count | int |
| orange_count | int |
+--------------+------+
chest_id 是该表的主键。
该表包含小盒子的信息,以及小盒子中包含的苹果和橘子的个数。
编写 SQL 语句,查询每个大箱子中苹果和橘子的个数。如果大箱子中包含小盒子,还应当包含小盒子中苹果和橘子的个数。
以任意顺序返回结果表。
查询结果的格式如下示例所示:
Boxes 表:
+--------+----------+-------------+--------------+
| box_id | chest_id | apple_count | orange_count |
+--------+----------+-------------+--------------+
| 2 | null | 6 | 15 |
| 18 | 14 | 4 | 15 |
| 19 | 3 | 8 | 4 |
| 12 | 2 | 19 | 20 |
| 20 | 6 | 12 | 9 |
| 8 | 6 | 9 | 9 |
| 3 | 14 | 16 | 7 |
+--------+----------+-------------+--------------+
Chests 表:
+----------+-------------+--------------+
| chest_id | apple_count | orange_count |
+----------+-------------+--------------+
| 6 | 5 | 6 |
| 14 | 20 | 10 |
| 2 | 8 | 8 |
| 3 | 19 | 4 |
| 16 | 19 | 19 |
+----------+-------------+--------------+
结果表:
+-------------+--------------+
| apple_count | orange_count |
+-------------+--------------+
| 151 | 123 |
+-------------+--------------+
大箱子 2 中有 6 个苹果和 15 个橘子。
大箱子 18 中有 4 + 20 (在小盒子中) = 24 个苹果和 15 + 10 (在小盒子中) = 25 个橘子。
大箱子 19 中有 8 + 19 (在小盒子中) = 27 个苹果和 4 + 4 (在小盒子中) = 8 个橘子。
大箱子 12 中有 19 + 8 (在小盒子中) = 27 个苹果和 20 + 8 (在小盒子中) = 28 个橘子。
大箱子 20 中有 12 + 5 (在小盒子中) = 17 个苹果和 9 + 6 (在小盒子中) = 15 个橘子。
大箱子 8 中有 9 + 5 (在小盒子中) = 14 个苹果和 9 + 6 (在小盒子中) = 15 个橘子。
大箱子 3 中有 16 + 20 (在小盒子中) = 36 个苹果和 7 + 10 (在小盒子中) = 17 个橘子。
苹果的总个数 = 6 + 24 + 27 + 27 + 17 + 14 + 36 = 151
橘子的总个数 = 15 + 25 + 8 + 28 + 15 + 15 + 17 = 123
# Write your MySQL query statement below
select
sum(apple_count) apple_count, # 全部苹果数
sum(orange_count) orange_count # 全部橘子树
from
(
select
box_id,
b.chest_id,
b.apple_count+ifnull(c.apple_count,0) apple_count, # 总的苹果数
b.orange_count+ifnull(c.orange_count,0) orange_count # 总的橘子树
from
boxes b
left join # 两表进行左连接
chests c
on
b.chest_id=c.chest_id # 连接条件
) t
;
表: Followers
+-------------+------+
| Column Name | Type |
+-------------+------+
| user_id | int |
| follower_id | int |
+-------------+------+
(user_id, follower_id) 是这个表的主键。
该表包含一个关注关系中关注者和用户的编号,其中关注者关注用户。
写出 SQL 语句,对于每一个用户,返回该用户的关注者数量。
按 user_id
的顺序返回结果表。
查询结果的格式如下示例所示:
Followers 表:
+---------+-------------+
| user_id | follower_id |
+---------+-------------+
| 0 | 1 |
| 1 | 0 |
| 2 | 0 |
| 2 | 1 |
+---------+-------------+
结果表:
+---------+----------------+
| user_id | followers_count|
+---------+----------------+
| 0 | 1 |
| 1 | 1 |
| 2 | 2 |
+---------+----------------+
0 的关注者有 {1}
1 的关注者有 {0}
2 的关注者有 {0,1}
# Write your MySQL query statement below
select
user_id,
count(*) followers_count # 求count
from
followers
group by
user_id # 按照user_id分组
order by
user_id # 排序
;
Table: Employees
+-------------+----------+
| Column Name | Type |
+-------------+----------+
| employee_id | int |
| name | varchar |
| reports_to | int |
| age | int |
+-------------+----------+
employee_id 是这个表的主键.
该表包含员工以及需要听取他们汇报的上级经理的ID的信息。 有些员工不需要向任何人汇报(reports_to 为空)。
对于此问题,我们将至少有一个其他员工需要向他汇报的员工,视为一个经理。
编写SQL查询需要听取汇报的所有经理的ID、名称、直接向该经理汇报的员工人数,以及这些员工的平均年龄,其中该平均年龄需要四舍五入到最接近的整数。
返回的结果集需要按照 employee_id
进行排序。
查询结果的格式如下:
Employees table:
+-------------+---------+------------+-----+
| employee_id | name | reports_to | age |
+-------------+---------+------------+-----+
| 9 | Hercy | null | 43 |
| 6 | Alice | 9 | 41 |
| 4 | Bob | 9 | 36 |
| 2 | Winston | null | 37 |
+-------------+---------+------------+-----+
Result table:
+-------------+-------+---------------+-------------+
| employee_id | name | reports_count | average_age |
+-------------+-------+---------------+-------------+
| 9 | Hercy | 2 | 39 |
+-------------+-------+---------------+-------------+
Hercy 有两个需要向他汇报的员工, 他们是 Alice and Bob. 他们的平均年龄是 (41+36)/2 = 38.5, 四舍五入的结果是 39.
# Write your MySQL query statement below
select
e1.employee_id employee_id,
e1.name name,
count(*) reports_count, # 求count
round(avg(e2.age),0) average_age # 求avg并四舍五入
from
employees e1
join # 自连接
employees e2
on
e1.employee_id=e2.reports_to # 连接条件
group by
e1.employee_id # 分组
order by
employee_id # 排序
;
表: Employees
+-------------+------+
| Column Name | Type |
+-------------+------+
| emp_id | int |
| event_day | date |
| in_time | int |
| out_time | int |
+-------------+------+
(emp_id, event_day, in_time) 是这个表的主键。
该表显示了员工在办公室的出入情况。
event_day 是此事件发生的日期,in_time 是员工进入办公室的时间,而 out_time 是他们离开办公室的时间。
in_time 和 out_time 的取值在1到1440之间。
题目保证同一天没有两个事件在时间上是相交的,并且保证 in_time 小于 out_time。
编写一个SQL查询以计算每位员工每天在办公室花费的总时间(以分钟为单位)。 请注意,在一天之内,同一员工是可以多次进入和离开办公室的。 在办公室里一次进出所花费的时间为out_time 减去 in_time。
返回结果表单的顺序无要求。
查询结果的格式如下:
Employees table:
+--------+------------+---------+----------+
| emp_id | event_day | in_time | out_time |
+--------+------------+---------+----------+
| 1 | 2020-11-28 | 4 | 32 |
| 1 | 2020-11-28 | 55 | 200 |
| 1 | 2020-12-03 | 1 | 42 |
| 2 | 2020-11-28 | 3 | 33 |
| 2 | 2020-12-09 | 47 | 74 |
+--------+------------+---------+----------+
Result table:
+------------+--------+------------+
| day | emp_id | total_time |
+------------+--------+------------+
| 2020-11-28 | 1 | 173 |
| 2020-11-28 | 2 | 30 |
| 2020-12-03 | 1 | 41 |
| 2020-12-09 | 2 | 27 |
+------------+--------+------------+
雇员 1 有三次进出: 有两次发生在 2020-11-28 花费的时间为 (32 - 4) + (200 - 55) = 173, 有一次发生在 2020-12-03 花费的时间为 (42 - 1) = 41。
雇员 2 有两次进出: 有一次发生在 2020-11-28 花费的时间为 (33 - 3) = 30, 有一次发生在 2020-12-09 花费的时间为 (74 - 47) = 27。
# Write your MySQL query statement below
select
event_day day,
emp_id,
sum(out_time-in_time) total_time # 求sum
from
employees
group by
emp_id,event_day # 按照emp_id,event_day进行分组
;
表: LogInfo
+-------------+----------+
| Column Name | Type |
+-------------+----------+
| account_id | int |
| ip_address | int |
| login | datetime |
| logout | datetime |
+-------------+----------+
该表是没有主键的,它可能包含重复项。
该表包含有关Leetflex帐户的登录和注销日期的信息。 它还包含了该账户用于登录和注销的网络地址的信息。
题目确保每一个注销时间都在登录时间之后。
编写一个SQL查询语句,查找那些应该被禁止的Leetflex帐户编号 account_id 。 如果某个帐户在某一时刻从两个不同的网络地址登录了,则这个帐户应该被禁止。
可以以 任何顺序 返回结果。
查询结果格式如下例所示。
示例 1:
输入:
LogInfo table:
+------------+------------+---------------------+---------------------+
| account_id | ip_address | login | logout |
+------------+------------+---------------------+---------------------+
| 1 | 1 | 2021-02-01 09:00:00 | 2021-02-01 09:30:00 |
| 1 | 2 | 2021-02-01 08:00:00 | 2021-02-01 11:30:00 |
| 2 | 6 | 2021-02-01 20:30:00 | 2021-02-01 22:00:00 |
| 2 | 7 | 2021-02-02 20:30:00 | 2021-02-02 22:00:00 |
| 3 | 9 | 2021-02-01 16:00:00 | 2021-02-01 16:59:59 |
| 3 | 13 | 2021-02-01 17:00:00 | 2021-02-01 17:59:59 |
| 4 | 10 | 2021-02-01 16:00:00 | 2021-02-01 17:00:00 |
| 4 | 11 | 2021-02-01 17:00:00 | 2021-02-01 17:59:59 |
+------------+------------+---------------------+---------------------+
输出:
+------------+
| account_id |
+------------+
| 1 |
| 4 |
+------------+
解释:
Account ID 1 --> 该账户从 "2021-02-01 09:00:00" 到 "2021-02-01 09:30:00" 在两个不同的网络地址(1 and 2)上激活了。它应该被禁止.
Account ID 2 --> 该账户在两个不同的网络地址 (6, 7) 激活了,但在不同的时间上.
Account ID 3 --> 该账户在两个不同的网络地址 (9, 13) 激活了,虽然是同一天,但时间上没有交集.
Account ID 4 --> 该账户从 "2021-02-01 17:00:00" 到 "2021-02-01 17:00:00" 在两个不同的网络地址 (10 and 11)上激活了。它应该被禁止.
# Write your MySQL query statement below
select
distinct a.account_id account_id # 去重
from
loginfo a,loginfo b # 自连接
where
a.account_id=b.account_id # 账户相同
and
a.ip_address!=b.ip_address # ip不同
and
a.logout<=b.logout # a的登出小于b的登出时间
and
b.login<=a.logout # b的登入时间小于a的登出时间
;
表: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 语句,查找既是低脂又是可回收的产品编号。
返回结果 无顺序要求 。
查询结果格式如下例所示:
Products 表:
+-------------+----------+------------+
| product_id | low_fats | recyclable |
+-------------+----------+------------+
| 0 | Y | N |
| 1 | Y | Y |
| 2 | N | Y |
| 3 | Y | Y |
| 4 | N | N |
+-------------+----------+------------+
Result 表:
+-------------+
| product_id |
+-------------+
| 1 |
| 3 |
+-------------+
只有产品 id 为 1 和 3 的产品,既是低脂又是可回收的产品。
# Write your MySQL query statement below
select
product_id # 取product_id
from
products
where
low_fats='Y' and recyclable='y' # 条件都是Y
;
表:Tasks
+----------------+---------+
| Column Name | Type |
+----------------+---------+
| task_id | int |
| subtasks_count | int |
+----------------+---------+
task_id 是这个表的主键。
task_id 表示的为主任务的id,每一个task_id被分为了多个子任务(subtasks),subtasks_count表示为子任务的个数(n),它的值表示了子任务的索引从1到n。
本表保证2 <=subtasks_count<= 20。
表: Executed
+---------------+---------+
| Column Name | Type |
+---------------+---------+
| task_id | int |
| subtask_id | int |
+---------------+---------+
(task_id, subtask_id) 是这个表的主键。
每一行表示标记为task_id的主任务与标记为subtask_id的子任务被成功执行。
本表 保证 ,对于每一个task_id,subtask_id <= subtasks_count。
请试写一个SQL查询语句报告没有被执行的(主任务,子任务)对,即没有被执行的(task_id, subtask_id)。
以 任何顺序 返回即可。
查询结果格式如下。
示例 1:
输入:
Tasks 表:
+---------+----------------+
| task_id | subtasks_count |
+---------+----------------+
| 1 | 3 |
| 2 | 2 |
| 3 | 4 |
+---------+----------------+
Executed 表:
+---------+------------+
| task_id | subtask_id |
+---------+------------+
| 1 | 2 |
| 3 | 1 |
| 3 | 2 |
| 3 | 3 |
| 3 | 4 |
+---------+------------+
输出:
+---------+------------+
| task_id | subtask_id |
+---------+------------+
| 1 | 1 |
| 1 | 3 |
| 2 | 1 |
| 2 | 2 |
+---------+------------+
解释:
Task 1 被分成了 3 subtasks (1, 2, 3)。只有 subtask 2 被成功执行, 所以我们返回 (1, 1) 和 (1, 3) 这两个主任务子任务对。
Task 2 被分成了 2 subtasks (1, 2)。没有一个subtask被成功执行, 因此我们返回(2, 1)和(2, 2)。
Task 3 被分成了 4 subtasks (1, 2, 3, 4)。所有的subtask都被成功执行,因此对于Task 3,我们不返回任何值。
# 为了让临时表实现自增长,
# 首先声明其需要存在的列名(task_id, subtask_id)
WITH RECURSIVE TT(task_id, subtask_id) AS (
# 先引入一行数据作为自增长的基础
SELECT task_id, subtasks_count FROM Tasks
# 再让新形成的行加入到现有的表中
UNION
# 新加入的行的逻辑是上一个形成的 id-1
# 因为最初的一行是以最大值给出的
SELECT task_id, (subtask_id-1) AS subtasks_count
FROM TT
WHERE subtask_id >= 2
)
SELECT
*
FROM
TT
WHERE
(task_id, subtask_id)
NOT IN
( SELECT * FROM Executed )
;
表: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 中没有销售。
# Write your MySQL query statement below
select
product_id,
max(case when store='store1' then price end) as store1, # 聚合函数 条件
max(case when store='store2' then price end) as store2, # 聚合函数 条件
max(case store when 'store3' then price end) as store3 # 聚合函数 条件
from
products
group by
product_id # 分组
;
表:Players
+----------------+---------+
| Column Name | Type |
+----------------+---------+
| player_id | int |
| player_name | varchar |
+----------------+---------+
player_id 是这个表的主键
这个表的每一行给出一个网球运动员的 ID 和 姓名
表:Championships
+---------------+---------+
| Column Name | Type |
+---------------+---------+
| year | int |
| Wimbledon | int |
| Fr_open | int |
| US_open | int |
| Au_open | int |
+---------------+---------+
year 是这个表的主键
该表的每一行都包含在每场大满贯网球比赛中赢得比赛的球员的 ID
请写出查询语句,查询出每一个球员赢得大满贯比赛的次数。结果不包含没有赢得比赛的球员的ID 。
结果集 无顺序要求 。
查询结果的格式,如下所示。
示例 1:
输入:
Players 表:
+-----------+-------------+
| player_id | player_name |
+-----------+-------------+
| 1 | Nadal |
| 2 | Federer |
| 3 | Novak |
+-----------+-------------+
Championships 表:
+------+-----------+---------+---------+---------+
| year | Wimbledon | Fr_open | US_open | Au_open |
+------+-----------+---------+---------+---------+
| 2018 | 1 | 1 | 1 | 1 |
| 2019 | 1 | 1 | 2 | 2 |
| 2020 | 2 | 1 | 2 | 2 |
+------+-----------+---------+---------+---------+
输出:
+-----------+-------------+-------------------+
| player_id | player_name | grand_slams_count |
+-----------+-------------+-------------------+
| 2 | Federer | 5 |
| 1 | Nadal | 7 |
+-----------+-------------+-------------------+
解释:
Player 1 (Nadal) 获得了 7 次大满贯:其中温网 2 次(2018, 2019), 法国公开赛 3 次 (2018, 2019, 2020), 美国公开赛 1 次 (2018)以及澳网公开赛 1 次 (2018) 。
Player 2 (Federer) 获得了 5 次大满贯:其中温网 1 次 (2020), 美国公开赛 2 次 (2019, 2020) 以及澳网公开赛 2 次 (2019, 2020) 。
Player 3 (Novak) 没有赢得,因此不包含在结果集中。
# Write your MySQL query statement below
with tmp as( # 临时表tmp
select wimbledon as id from championships
union all
select fr_open from championships
union all # 把得过冠军的都联合在一起
select us_open from championships
union all
select au_open from championships
)
select
player_id,
player_name,
count(*) grand_slams_count # 求数
from
players p
join # 两表内连接
tmp t
on
p.player_id=t.id # 连接条件
group by
p.player_id # 分组
;
Table: 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,查出员工所属的直属部门。
返回结果没有顺序要求。
示例:
Employee table:
+-------------+---------------+--------------+
| employee_id | department_id | primary_flag |
+-------------+---------------+--------------+
| 1 | 1 | N |
| 2 | 1 | Y |
| 2 | 2 | N |
| 3 | 3 | N |
| 4 | 2 | N |
| 4 | 3 | Y |
| 4 | 4 | N |
+-------------+---------------+--------------+
Result table:
+-------------+---------------+
| employee_id | department_id |
+-------------+---------------+
| 1 | 1 |
| 2 | 1 |
| 3 | 3 |
| 4 | 3 |
+-------------+---------------+
- 员工1的直属部门是1
- 员工2的直属部门是1
- 员工3的直属部门是3
- 员工4的直属部门是3
# Write your MySQL query statement below
select
distinct employee_id, # 去重
department_id
from(
select
employee_id,
department_id
from
employee
group by
employee_id # 分组
having
count(*)=1 # 取count为1的肯定是直属部门
union all # 两表结合,当然会有重复的
select
employee_id,
department_id
from
employee
where
primary_flag='Y' # 取primary_flag是Y的,肯定是直属部门
) t
;
表:Products
+-------------+---------+
| Column Name | Type |
+-------------+---------+
| product_id | int |
| store1 | int |
| store2 | int |
| store3 | int |
+-------------+---------+
这张表的主键是product_id(产品Id)。
每行存储了这一产品在不同商店store1, store2, store3的价格。
如果这一产品在商店里没有出售,则值将为null。
请你重构 Products 表,查询每个产品在不同商店的价格,使得输出的格式变为(product_id, store, price) 。如果这一产品在商店里没有出售,则不输出这一行。
输出结果表中的 顺序不作要求 。
查询输出格式请参考下面示例。
示例 1:
输入:
Products table:
+------------+--------+--------+--------+
| product_id | store1 | store2 | store3 |
+------------+--------+--------+--------+
| 0 | 95 | 100 | 105 |
| 1 | 70 | null | 80 |
+------------+--------+--------+--------+
输出:
+------------+--------+-------+
| product_id | store | price |
+------------+--------+-------+
| 0 | store1 | 95 |
| 0 | store2 | 100 |
| 0 | store3 | 105 |
| 1 | store1 | 70 |
| 1 | store3 | 80 |
+------------+--------+-------+
解释:
产品0在store1,store2,store3的价格分别为95,100,105。
产品1在store1,store3的价格分别为70,80。在store2无法买到。
# Write your MySQL query statement below
select
product_id,
'store1' store, # 取store1
store1 price # 取store1的值
from
products
where
store1 is not null # 取store1值不为null的
union all # 联合
select
product_id,
'store2' store2, # 取store2
store2 # 取store2的值
from
products
where
store2 is not null # 取store2值不为null的
union all # 联合
select
product_id, # 取store3
'store3' store3, # 取store3的值
store3
from
products
where
store3 is not null # 取store3值不为null的
;
Table: Playback
+-------------+------+
| Column Name | Type |
+-------------+------+
| session_id | int |
| customer_id | int |
| start_time | int |
| end_time | int |
+-------------+------+
该表主键为:session_id (剧集id)
customer_id 是观看该剧集的观众id
剧集播放时间包含start_time(开始时间) 及 end_time(结束时间)
可以保证的是,start_time(开始时间)<= end_time(结束时间),一个观众观看的两个剧集的时间不会出现重叠。
Table: Ads
+-------------+------+
| Column Name | Type |
+-------------+------+
| ad_id | int |
| customer_id | int |
| timestamp | int |
+-------------+------+
该表的主键为:ad_id(广告id)
customer_id 为 观看广告的用户id
timestamp 表示广告出现的时间点
请查出,所有没有广告出现过的剧集。
如果观众观看了剧集,并且剧集里出现了广告,就一定会有观众观看广告的记录。
返回结果没有顺序要求。
示例:
Playback table:
+------------+-------------+------------+----------+
| session_id | customer_id | start_time | end_time |
+------------+-------------+------------+----------+
| 1 | 1 | 1 | 5 |
| 2 | 1 | 15 | 23 |
| 3 | 2 | 10 | 12 |
| 4 | 2 | 17 | 28 |
| 5 | 2 | 2 | 8 |
+------------+-------------+------------+----------+
Ads table:
+-------+-------------+-----------+
| ad_id | customer_id | timestamp |
+-------+-------------+-----------+
| 1 | 1 | 5 |
| 2 | 2 | 17 |
| 3 | 2 | 20 |
+-------+-------------+-----------+
Result table:
+------------+
| session_id |
+------------+
| 2 |
| 3 |
| 5 |
+------------+
广告1出现在了剧集1的时间段,被观众1看到了。
广告2出现在了剧集4的时间段,被观众2看到了。
广告3出现在了剧集4的时间段,被观众2看到了。
我们可以得出结论,剧集1 、4 内,起码有1处广告。 剧集2 、3 、5 没有广告。
# Write your MySQL query statement below
with tmp as( # 临时表tmp
select
session_id # 确定有广告的session_id
from
ads a
join
playback p
on
a.customer_id=p.customer_id
and
timestamp between start_time and end_time
)
select
t1.session_id
from
(select session_id from playback) t1 # t1作为全部的session_id
left join tmp # 左连接
on t1.session_id=tmp.session_id # 连接条件
where tmp.session_id is null # 去掉有广告的seesion_id
;
表: Contests
+--------------+------+
| Column Name | Type |
+--------------+------+
| contest_id | int |
| gold_medal | int |
| silver_medal | int |
| bronze_medal | int |
+--------------+------+
contest_id 是该表的主键.
该表包含LeetCode竞赛的ID和该场比赛中金牌、银牌、铜牌的用户id。
可以保证,所有连续的比赛都有连续的ID,没有ID被跳过。
Table: Users
+-------------+---------+
| Column Name | Type |
+-------------+---------+
| user_id | int |
| mail | varchar |
| name | varchar |
+-------------+---------+
user_id 是该表的主键.
该表包含用户信息。
编写 SQL 语句来返回面试候选人的 姓名和 邮件.当用户满足以下两个要求中的任意一条,其成为面试候选人:
该用户在连续三场及更多比赛中赢得奖牌。
该用户在三场及更多不同的比赛中赢得金牌(这些比赛可以不是连续的)
可以以任何顺序返回结果。
查询结果格式如下例所示:
Contests表:
+------------+------------+--------------+--------------+
| contest_id | gold_medal | silver_medal | bronze_medal |
+------------+------------+--------------+--------------+
| 190 | 1 | 5 | 2 |
| 191 | 2 | 3 | 5 |
| 192 | 5 | 2 | 3 |
| 193 | 1 | 3 | 5 |
| 194 | 4 | 5 | 2 |
| 195 | 4 | 2 | 1 |
| 196 | 1 | 5 | 2 |
+------------+------------+--------------+--------------+
Users表:
+---------+--------------------+-------+
| user_id | mail | name |
+---------+--------------------+-------+
| 1 | sarah@leetcode.com | Sarah |
| 2 | bob@leetcode.com | Bob |
| 3 | alice@leetcode.com | Alice |
| 4 | hercy@leetcode.com | Hercy |
| 5 | quarz@leetcode.com | Quarz |
+---------+--------------------+-------+
结果表:
+-------+--------------------+
| name | mail |
+-------+--------------------+
| Sarah | sarah@leetcode.com |
| Bob | bob@leetcode.com |
| Alice | alice@leetcode.com |
| Quarz | quarz@leetcode.com |
+-------+--------------------+
Sarah 赢得了3块金牌 (190, 193, and 196),所以我们将她列入结果表。
Bob在连续3场竞赛中赢得了奖牌(190, 191, and 192), 所以我们将他列入结果表。
- 注意他在另外的连续3场竞赛中也赢得了奖牌(194, 195, and 196).
Alice在连续3场竞赛中赢得了奖牌 (191, 192, and 193), 所以我们将她列入结果表。
Quarz在连续5场竞赛中赢得了奖牌(190, 191, 192, 193, and 194), 所以我们将他列入结果表。
# Write your MySQL query statement below
with gold_cn as( # 临时表gold_cn,取得金牌数大于等于三的,这个肯定是候选人
select
gold_medal
from
contests
group by
gold_medal
having
count(*)>=3
),
tmp as( # 临时表 tmp,用做组合表
select
contest_id,
gold_medal all_medal
from
contests
union all
select
contest_id,
silver_medal
from
contests
union all
select
contest_id,
bronze_medal
from
contests
),
tmp1 as( # 临时表tmp1,用作开窗排序
select
contest_id,
all_medal,
rank() over(partition by all_medal order by contest_id) rk
from
tmp
),
tmp2 as( # 临时表tmp2,在临时表tmp1的基础上用contest_id减去rk,用作后续判断连续的
select
contest_id,
all_medal,
rk,
contest_id-rk pp
from
tmp1
),
all_cn as( # 临时表all_cn,在临时表tmp2的基础上求出连续3次或者以上获得奖牌的contest_id
select
all_medal
from
tmp2
group by
pp,all_medal
having
count(*)>=3
)
select
distinct # 去重
name,
mail
from
(select * from gold_cn union all select * from all_cn) n # 都符合候选人的表联合
join # 连接候选人信息表
users u
on
n.gold_medal=u.user_id # 连接条件
;
表:Customers
+--------------+------+
| Column Name | Type |
+--------------+------+
| customer_id | int |
| year | int |
| revenue | int |
+--------------+------+
(customer_id, year) 是这个表的主键。
这个表包含客户 ID 和不同年份的客户收入。
注意,这个收入可能是负数。
写一个 SQL 查询来查询 2021 年具有 正收入 的客户。
可以按 任意顺序 返回结果表。
查询结果格式如下例。
Customers
+-------------+------+---------+
| customer_id | year | revenue |
+-------------+------+---------+
| 1 | 2018 | 50 |
| 1 | 2021 | 30 |
| 1 | 2020 | 70 |
| 2 | 2021 | -50 |
| 3 | 2018 | 10 |
| 3 | 2016 | 50 |
| 4 | 2021 | 20 |
+-------------+------+---------+
Result table:
+-------------+
| customer_id |
+-------------+
| 1 |
| 4 |
+-------------+
客户 1 在 2021 年的收入等于 30 。
客户 2 在 2021 年的收入等于 -50 。
客户 3 在 2021 年没有收入。
客户 4 在 2021 年的收入等于 20 。
因此,只有客户 1 和 4 在 2021 年有正收入。
# Write your MySQL query statement below
select
customer_id
from
customers
where
year=2021
and
revenue>0
;
表: Transactions
+----------------+----------+
| Column Name | Type |
+----------------+----------+
| transaction_id | int |
| day | datetime |
| amount | int |
+----------------+----------+
transaction_id 是此表的主键。
每行包括了该次交易的信息。
写一条 SQL 返回每天交易金额 amount
最大的交易 ID 。如果某天有多个这样的交易,返回这些交易的 ID 。
返回结果根据 transaction_id
升序排列。
查询结果样例如下:
Transactions table:
+----------------+--------------------+--------+
| transaction_id | day | amount |
+----------------+--------------------+--------+
| 8 | 2021-4-3 15:57:28 | 57 |
| 9 | 2021-4-28 08:47:25 | 21 |
| 1 | 2021-4-29 13:28:30 | 58 |
| 5 | 2021-4-28 16:39:59 | 40 |
| 6 | 2021-4-29 23:39:28 | 58 |
+----------------+--------------------+--------+
Result table:
+----------------+
| transaction_id |
+----------------+
| 1 |
| 5 |
| 6 |
| 8 |
+----------------+
"2021-4-3" --> 有一个 id 是 8 的交易,因此,把它加入结果表。
"2021-4-28" --> 有两个交易,id 是 5 和 9 ,交易 5 的金额是 40 ,而交易 9 的数量是 21 。只需要将交易 5 加入结果表,因为它是当天金额最大的交易。
"2021-4-29" --> 有两个交易,id 是 1 和 6 ,这两个交易的金额都是 58 ,因此需要把它们都写入结果表。
最后,把交易 id 按照升序排列。
# Write your MySQL query statement below
# Write your MySQL query statement below
select
distinct
transaction_id
from
transactions
where
(date_format(day,'%Y-%m-%d'),amount) # 子查询,按天来
in
(
select
date_format(day,'%Y-%m-%d') day, # 找到当天的
max(amount) # 最大的
from
transactions
group by
date_format(day,'%Y-%m-%d') # 按天分组
)
order by
transaction_id # 排序
;
Table: Teams
+----------------+---------+
| Column Name | Type |
+----------------+---------+
| team_id | int |
| team_name | varchar |
+----------------+---------+
team_id 是该表主键.
每一行都包含了一个参加联赛的队伍信息.
Table: Matches
+-----------------+---------+
| Column Name | Type |
+-----------------+---------+
| home_team_id | int |
| away_team_id | int |
| home_team_goals | int |
| away_team_goals | int |
+-----------------+---------+
(home_team_id, away_team_id) 是该表主键.
每一行包含了一次比赛信息.
home_team_goals 代表主场队得球数.
away_team_goals 代表客场队得球数.
获得球数较多的队伍为胜者队伍.
写一段SQL,用来报告联赛信息. 统计数据应使用已进行的比赛来构建,其中获胜球队获得三分,而失败球队获得零分. 如果打平,两支球队都得一分.
result表的每行应包含以下信息:
team_name - Teams表中的队伍名字
matches_played - 主场与客场球队进行的比赛次数.
points - 球队获得的总分数.
goal_for - 球队在所有比赛中获取的总进球数
goal_against - 球队在所有比赛中,他的对手球队的所有进球数
goal_diff - goal_for - goal_against.
按分数降序返回结果表。 如果两队或多队得分相同,则按goal_diff 降序排列。 如果仍然存在平局,则以 team_name 按字典顺序排列它们。
查询的结果格式如下例所示:
Teams table:
+---------+-----------+
| team_id | team_name |
+---------+-----------+
| 1 | Ajax |
| 4 | Dortmund |
| 6 | Arsenal |
+---------+-----------+
Matches table:
+--------------+--------------+-----------------+-----------------+
| home_team_id | away_team_id | home_team_goals | away_team_goals |
+--------------+--------------+-----------------+-----------------+
| 1 | 4 | 0 | 1 |
| 1 | 6 | 3 | 3 |
| 4 | 1 | 5 | 2 |
| 6 | 1 | 0 | 0 |
+--------------+--------------+-----------------+-----------------+
Result table:
+-----------+----------------+--------+----------+--------------+-----------+
| team_name | matches_played | points | goal_for | goal_against | goal_diff |
+-----------+----------------+--------+----------+--------------+-----------+
| Dortmund | 2 | 6 | 6 | 2 | 4 |
| Arsenal | 2 | 2 | 3 | 3 | 0 |
| Ajax | 4 | 2 | 5 | 9 | -4 |
+-----------+----------------+--------+----------+--------------+-----------+
Ajax (team_id=1) 有4场比赛: 2败2平. 总分数 = 0 + 0 + 1 + 1 = 2.
Dortmund (team_id=4) 有2场比赛: 2胜. 总分数 = 3 + 3 = 6.
Arsenal (team_id=6) 有2场比赛: 2平. 总分数 = 1 + 1 = 2.
Dortmund 是积分榜上的第一支球队. Ajax和Arsenal 有同样的分数, 但Arsenal的goal_diff高于Ajax, 所以Arsenal在表中的顺序在Ajaxzhi'qian.
# Write your MySQL query statement below
SELECT team_name,
COUNT(*) AS matches_played,
SUM( CASE
WHEN team_id = home_team_id AND home_team_goals > away_team_goals THEN 3
WHEN team_id = home_team_id AND home_team_goals < away_team_goals THEN 0
WHEN team_id = away_team_id AND home_team_goals < away_team_goals THEN 3
WHEN team_id = away_team_id AND home_team_goals > away_team_goals THEN 0
ELSE 1
END ) AS points,
SUM(IF(team_id = home_team_id, home_team_goals, away_team_goals)) AS goal_for,
SUM(IF(team_id = home_team_id, away_team_goals, home_team_goals)) AS goal_against,
(SUM(IF(team_id = home_team_id, home_team_goals, away_team_goals)) - SUM(IF(team_id = home_team_id, away_team_goals, home_team_goals))) AS goal_diff
FROM Teams, Matches
WHERE team_id = home_team_id
OR team_id = away_team_id
GROUP BY team_id
ORDER BY points DESC, goal_diff DESC, team_name
;
Table: Accounts
+----------------+------+
| Column Name | Type |
+----------------+------+
| account_id | int |
| max_income | int |
+----------------+------+
account_id 是表主键。
每行包含一个银行账户每月最大收入的信息。
Table: Transactions
+----------------+----------+
| Column Name | Type |
+----------------+----------+
| transaction_id | int |
| account_id | int |
| type | ENUM |
| amount | int |
| day | datetime |
+----------------+----------+
transaction_id 是表的主键。
每行包含转账信息。
type 是枚举类型(包含'Creditor','Debtor'),其中'Creditor'表示用户向其账户存入资金,'Debtor'表示用户从其账户取出资金。
amount 是转账的存取金额。
写一个SQL查询语句列示所有的可疑账户。
如果一个账户在连续两个及以上月份中总收入超过最大收入(max_income ),那么这个账户可疑。 账户当月总收入是当月存入资金总数(即transactions 表中type字段的’Creditor’)。
返回的结果表以transaction_id 排序。
查询结果格式如下:
Accounts table:
+------------+------------+
| account_id | max_income |
+------------+------------+
| 3 | 21000 |
| 4 | 10400 |
+------------+------------+
Transactions table:
+----------------+------------+----------+--------+---------------------+
| transaction_id | account_id | type | amount | day |
+----------------+------------+----------+--------+---------------------+
| 2 | 3 | Creditor | 107100 | 2021-06-02 11:38:14 |
| 4 | 4 | Creditor | 10400 | 2021-06-20 12:39:18 |
| 11 | 4 | Debtor | 58800 | 2021-07-23 12:41:55 |
| 1 | 4 | Creditor | 49300 | 2021-05-03 16:11:04 |
| 15 | 3 | Debtor | 75500 | 2021-05-23 14:40:20 |
| 10 | 3 | Creditor | 102100 | 2021-06-15 10:37:16 |
| 14 | 4 | Creditor | 56300 | 2021-07-21 12:12:25 |
| 19 | 4 | Debtor | 101100 | 2021-05-09 15:21:49 |
| 8 | 3 | Creditor | 64900 | 2021-07-26 15:09:56 |
| 7 | 3 | Creditor | 90900 | 2021-06-14 11:23:07 |
+----------------+------------+----------+--------+---------------------+
Result table:
+------------+
| account_id |
+------------+
| 3 |
+------------+
对于账户 3:
- 在 2021年6月,用户收入为 107100 + 102100 + 90900 = 300100。
- 在 2021年7月,用户收入为 64900。
可见收入连续两月超过21000的最大收入,因此账户3列入结果表中。
对于账户 4:
- 在 2021年5月,用户收入为 49300。
- 在 2021年6月,用户收入为 10400。
- 在 2021年7月,用户收入为 56300。
可见收入在5月与7月超过了最大收入,但6月没有。因为账户没有没有连续两月超过最大收入,账户4不列入结果表中。
with temp as (
select
account_id,
date_format(day, '%Y%m') yearmonth
from transactions join accounts using(account_id)
where type = 'creditor'
group by account_id, yearmonth
having sum(amount) > max(max_income)
)
select
distinct account_id
from temp where (account_id, period_add(yearmonth, 1)) in (
select account_id, yearmonth from temp
);
表: Days
+-------------+------+
| Column Name | Type |
+-------------+------+
| day | date |
+-------------+------+
day 是这个表的主键。
给定一个Days
表,请你编写SQL查询语句,将Days
表中的每一个日期转化为"day_name, month_name day, year"
格式的字符串。
返回的结果表不计顺序。
例如:
Days table:
+------------+
| day |
+------------+
| 2022-04-12 |
| 2021-08-09 |
| 2020-06-26 |
+------------+
Result table:
+-------------------------+
| day |
+-------------------------+
| Tuesday, April 12, 2022 |
| Monday, August 9, 2021 |
| Friday, June 26, 2020 |
+-------------------------+
请注意,输出对大小写敏感。
select
date_format(day,'%W, %M %e, %Y') `day`
from
days
;
date_format(datetime,fmt)
%Y:4位数表示年份
%y:2位数表示年份
%M:英文月份
%m:2位数表示月份
%b:缩写的英文月份
%c:1位数表示月份
%D:英文后缀表示月中的天数
%d:2位数表示月中的天数
%e:数字形式表示月中的天数
OrdersDetails
表
+-------------+------+
| Column Name | Type |
+-------------+------+
| order_id | int |
| product_id | int |
| quantity | int |
+-------------+------+
(order_id, product_id) 是此表的主键。
单个订单表示为多行,订单中的每个产品对应一行。
此表的每一行都包含订单id中产品id的订购数量。
您正在运行一个电子商务网站,该网站正在寻找不平衡的订单。不平衡订单的订单最大数量严格大于每个订单(包括订单本身)的平均数量。
订单的平均数量计算为(订单中所有产品的总数量)/(订单中不同产品的数量)。订单的最大数量是订单中任何单个产品的最高数量。
编写SQL查询以查找所有不平衡订单的订单id。
按任意顺序返回结果表。
查询结果格式如下例所示。
示例:
输入:
OrdersDetails 表:
+----------+------------+----------+
| order_id | product_id | quantity |
+----------+------------+----------+
| 1 | 1 | 12 |
| 1 | 2 | 10 |
| 1 | 3 | 15 |
| 2 | 1 | 8 |
| 2 | 4 | 4 |
| 2 | 5 | 6 |
| 3 | 3 | 5 |
| 3 | 4 | 18 |
| 4 | 5 | 2 |
| 4 | 6 | 8 |
| 5 | 7 | 9 |
| 5 | 8 | 9 |
| 3 | 9 | 20 |
| 2 | 9 | 4 |
+----------+------------+----------+
输出:
+----------+
| order_id |
+----------+
| 1 |
| 3 |
+----------+
解释:
每份订单的平均数量为:
- order_id=1: (12+10+15)/3 = 12.3333333
- order_id=2: (8+4+6+4)/4 = 5.5
- order_id=3: (5+18+20)/3 = 14.333333
- order_id=4: (2+8)/2 = 5
- order_id=5: (9+9)/2 = 9
每个订单的最大数量为:
- order_id=1: max(12, 10, 15) = 15
- order_id=2: max(8, 4, 6, 4) = 8
- order_id=3: max(5, 18, 20) = 20
- order_id=4: max(2, 8) = 8
- order_id=5: max(9, 9) = 9
订单1和订单3是不平衡的,因为它们的最大数量超过了它们订单的平均数量。
# Write your MySQL query statement below
with tmp as( # 临时表tmp
select
order_id,
max(quantity) mx, # 最大
avg(quantity) ag # 平均
from
ordersdetails
group by
order_id # 按照order_id进行分组
),tmp1 as( # 临时表tmp1
select
t1.order_id,
if(t1.mx>t2.ag,0,1) flag # 标志位,最大的大于平均的
from
tmp t1,tmp t2
)
select
order_id
from
tmp1
group by
order_id # 分组
having
sum(flag)=0 # 条件
;