- 练习题目来自:leetcode-cn.com/
每件商品的最新订单
表: Customers
+---------------+---------+
| Column Name | Type |
+---------------+---------+
| customer_id | int |
| name | varchar |
+---------------+---------+
customer_id 是该表主键.
该表包含消费者的信息.
表: Orders
+---------------+---------+
| Column Name | Type |
+---------------+---------+
| order_id | int |
| order_date | date |
| customer_id | int |
| product_id | int |
+---------------+---------+
order_id 是该表主键.
该表包含消费者customer_id产生的订单.
不会有商品被相同的用户在一天内下单超过一次.
表: Products
+---------------+---------+
| Column Name | Type |
+---------------+---------+
| product_id | int |
| product_name | varchar |
| price | int |
+---------------+---------+
product_id 是该表主键.
该表包含所有商品的信息.
写一个SQL 语句, 找到每件商品的最新订单(可能有多个)。
返回的结果以 product_name 升序排列, 如果有排序相同, 再以 product_id 升序排列。如果还有排序相同, 再以 order_id 升序排列。
查询结果格式如下例所示:
Customers
+-------------+-----------+
| customer_id | name |
+-------------+-----------+
| 1 | Winston |
| 2 | Jonathan |
| 3 | Annabelle |
| 4 | Marwan |
| 5 | Khaled |
+-------------+-----------+
Orders
+----------+------------+-------------+------------+
| order_id | order_date | customer_id | product_id |
+----------+------------+-------------+------------+
| 1 | 2020-07-31 | 1 | 1 |
| 2 | 2020-07-30 | 2 | 2 |
| 3 | 2020-08-29 | 3 | 3 |
| 4 | 2020-07-29 | 4 | 1 |
| 5 | 2020-06-10 | 1 | 2 |
| 6 | 2020-08-01 | 2 | 1 |
| 7 | 2020-08-01 | 3 | 1 |
| 8 | 2020-08-03 | 1 | 2 |
| 9 | 2020-08-07 | 2 | 3 |
| 10 | 2020-07-15 | 1 | 2 |
+----------+------------+-------------+------------+
Products
+------------+--------------+-------+
| product_id | product_name | price |
+------------+--------------+-------+
| 1 | keyboard | 120 |
| 2 | mouse | 80 |
| 3 | screen | 600 |
| 4 | hard disk | 450 |
+------------+--------------+-------+
Result
+--------------+------------+----------+------------+
| product_name | product_id | order_id | order_date |
+--------------+------------+----------+------------+
| keyboard | 1 | 6 | 2020-08-01 |
| keyboard | 1 | 7 | 2020-08-01 |
| mouse | 2 | 8 | 2020-08-03 |
| screen | 3 | 3 | 2020-08-29 |
+--------------+------------+----------+------------+
keyboard 的最新订单在2020-08-01, 在这天有两次下单.
mouse 的最新订单在2020-08-03, 在这天只有一次下单.
screen 的最新订单在2020-08-29, 在这天只有一次下单.
hard disk 没有被下单, 我们不把它包含在结果表中.
-
SQL1:
-
select p.product_name, t.product_id, t.order_id, t.order_date from (select product_id, order_id, order_date, RANK() over(partition by product_id order by order_date DESC) rk from Orders) t join Products p using(product_id) where t.rk = 1 order by p.product_name, t.product_id, t.order_id
-
-
SQL2:
-
select p.product_name, o.product_id, o.order_id, o.order_date from Products p join Orders o using(product_id) where (o.product_id, o.order_date) in (select product_id, max(order_date) order_date from Orders group by product_id) order by p.product_name, o.product_id, o.order_id
-
按月统计订单数与顾客数
表:Orders
+---------------+---------+
| Column Name | Type |
+---------------+---------+
| order_id | int |
| order_date | date |
| customer_id | int |
| invoice | int |
+---------------+---------+
order_id 是 Orders 表的主键。
这张表包含顾客(customer_id)所下订单的信息。
写一个查询语句来 按月 统计 金额大于 $20 的唯一 订单数 和唯一 顾客数 。
查询结果无排序要求。
查询结果格式如下面例子所示:
Orders
+----------+------------+-------------+------------+
| order_id | order_date | customer_id | invoice |
+----------+------------+-------------+------------+
| 1 | 2020-09-15 | 1 | 30 |
| 2 | 2020-09-17 | 2 | 90 |
| 3 | 2020-10-06 | 3 | 20 |
| 4 | 2020-10-20 | 3 | 21 |
| 5 | 2020-11-10 | 1 | 10 |
| 6 | 2020-11-21 | 2 | 15 |
| 7 | 2020-12-01 | 4 | 55 |
| 8 | 2020-12-03 | 4 | 77 |
| 9 | 2021-01-07 | 3 | 31 |
| 10 | 2021-01-15 | 2 | 20 |
+----------+------------+-------------+------------+
Result 表:
+---------+-------------+----------------+
| month | order_count | customer_count |
+---------+-------------+----------------+
| 2020-09 | 2 | 2 |
| 2020-10 | 1 | 1 |
| 2020-12 | 2 | 1 |
| 2021-01 | 1 | 1 |
+---------+-------------+----------------+
在 2020 年 09 月,有 2 份来自 2 位不同顾客的金额大于 $20 的订单。
在 2020 年 10 月,有 2 份来自 1 位顾客的订单,并且只有其中的 1 份订单金额大于 $20 。
在 2020 年 11 月,有 2 份来自 2 位不同顾客的订单,但由于金额都小于 $20 ,所以我们的查询结果中不包含这个月的数据。
在 2020 年 12 月,有 2 份来自 1 位顾客的订单,且 2 份订单金额都大于 $20 。
在 2021 年 01 月,有 2 份来自 2 位不同顾客的订单,但只有其中一份订单金额大于 $20 。
- SQL:
-
select date_format(order_date, '%Y-%m') month, count(order_id) order_count, count(distinct customer_id) customer_count from Orders where invoice > 20 group by date_format(order_date, '%Y-%m')
-
仓库经理
表:Warehouse
+--------------+---------+
| Column Name | Type |
+--------------+---------+
| name | varchar |
| product_id | int |
| units | int |
+--------------+---------+
(name, product_id) 是该表主键.
该表的行包含了每个仓库的所有商品信息.
表: Products
+---------------+---------+
| Column Name | Type |
+---------------+---------+
| product_id | int |
| product_name | varchar |
| Width | int |
| Length | int |
| Height | int |
+---------------+---------+
product_id 是该表主键.
该表的行包含了每件商品以英尺为单位的尺寸(宽度, 长度和高度)信息.
写一个 SQL查询来报告,每个仓库的存货量是多少立方英尺:
- 仓库名
- 存货量
返回结果没有顺序要求。
查询结果如下例所示:
Warehouse 表:
+------------+--------------+-------------+
| name | product_id | units |
+------------+--------------+-------------+
| LCHouse1 | 1 | 1 |
| LCHouse1 | 2 | 10 |
| LCHouse1 | 3 | 5 |
| LCHouse2 | 1 | 2 |
| LCHouse2 | 2 | 2 |
| LCHouse3 | 4 | 1 |
+------------+--------------+-------------+
Products 表:
+------------+--------------+------------+----------+-----------+
| product_id | product_name | Width | Length | Height |
+------------+--------------+------------+----------+-----------+
| 1 | LC-TV | 5 | 50 | 40 |
| 2 | LC-KeyChain | 5 | 5 | 5 |
| 3 | LC-Phone | 2 | 10 | 10 |
| 4 | LC-T-Shirt | 4 | 10 | 20 |
+------------+--------------+------------+----------+-----------+
Result 表:
+----------------+------------+
| WAREHOUSE_NAME | VOLUME |
+----------------+------------+
| LCHouse1 | 12250 |
| LCHouse2 | 20250 |
| LCHouse3 | 800 |
+----------------+------------+
Id为1的商品(LC-TV)的存货量为 5x50x40 = 10000
Id为2的商品(LC-KeyChain)的存货量为 5x5x5 = 125
Id为3的商品(LC-Phone)的存货量为 2x10x10 = 200
Id为4的商品(LC-T-Shirt)的存货量为 4x10x20 = 800
仓库LCHouse1: 1个单位的LC-TV + 10个单位的LC-KeyChain + 5个单位的LC-Phone.
总存货量为: 1*10000 + 10*125 + 5*200 = 12250 立方英尺
仓库LCHouse2: 2个单位的LC-TV + 2个单位的LC-KeyChain.
总存货量为: 2*10000 + 2*125 = 20250 立方英尺
仓库LCHouse3: 1个单位的LC-T-Shirt.
总存货量为: 1*800 = 800 立方英尺.
-
SQL1:
-
select w.name warehouse_name, sum(w.units * p.Width * p.Length * p.Height) volume from Warehouse w join Products p using(product_id) group by w.name
-
-
SQL2:
-
select name warehouse_name, sum(units * v) volume from Warehouse w join (select product_id, Width * Length * Height v from Products) t using(product_id) group by name
-
进店却未进行过交易的顾客
表: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 期间进行的交易的信息。
有一些顾客可能光顾了购物中心但没有进行交易。请你编写一个 SQL 查询,来查找这些顾客的 ID ,以及他们只光顾不交易的次数。
返回以任何顺序排序的结果表。
查询结果格式如下例所示:
Visits
+----------+-------------+
| visit_id | customer_id |
+----------+-------------+
| 1 | 23 |
| 2 | 9 |
| 4 | 30 |
| 5 | 54 |
| 6 | 96 |
| 7 | 54 |
| 8 | 54 |
+----------+-------------+
Transactions
+----------------+----------+--------+
| transaction_id | visit_id | amount |
+----------------+----------+--------+
| 2 | 5 | 310 |
| 3 | 5 | 300 |
| 9 | 5 | 200 |
| 12 | 1 | 910 |
| 13 | 2 | 970 |
+----------------+----------+--------+
Result 表:
+-------------+----------------+
| customer_id | count_no_trans |
+-------------+----------------+
| 54 | 2 |
| 30 | 1 |
| 96 | 1 |
+-------------+----------------+
ID = 23 的顾客曾经逛过一次购物中心,并在 ID = 12 的访问期间进行了一笔交易。
ID = 9 的顾客曾经逛过一次购物中心,并在 ID = 13 的访问期间进行了一笔交易。
ID = 30 的顾客曾经去过购物中心,并且没有进行任何交易。
ID = 54 的顾客三度造访了购物中心。在 2 次访问中,他们没有进行任何交易,在 1 次访问中,他们进行了 3 次交易。
ID = 96 的顾客曾经去过购物中心,并且没有进行任何交易。
如我们所见,ID 为 30 和 96 的顾客一次没有进行任何交易就去了购物中心。顾客 54 也两次访问了购物中心并且没有进行任何交易。
-
SQL1:
-
select customer_id, count(customer_id) count_no_trans from Visits where visit_id not in (select visit_id from Transactions) group by customer_id
-
-
SQL2:
-
select customer_id, count(customer_id) count_no_trans from Visits v left join Transactions t using(visit_id) where amount is null group by customer_id
-
每位顾客最经常订购的商品
表:Customers
+---------------+---------+
| Column Name | Type |
+---------------+---------+
| customer_id | int |
| name | varchar |
+---------------+---------+
customer_id 是该表主键
该表包含所有顾客的信息
表:Orders
+---------------+---------+
| Column Name | Type |
+---------------+---------+
| order_id | int |
| order_date | date |
| customer_id | int |
| product_id | int |
+---------------+---------+
order_id 是该表主键
该表包含顾客 customer_id 的订单信息
没有顾客会在一天内订购相同的商品 多于一次
表:Products
+---------------+---------+
| Column Name | Type |
+---------------+---------+
| product_id | int |
| product_name | varchar |
| price | int |
+---------------+---------+
product_id 是该表主键
该表包含了所有商品的信息
写一个 SQL 语句,找到每一个顾客最经常订购的商品。
结果表单应该有每一位至少下过一次单的顾客 customer_id,他最经常订购的商品的product_id和product_name。
返回结果 没有顺序要求。
查询结果格式如下例所示:
Customers
+-------------+-------+
| customer_id | name |
+-------------+-------+
| 1 | Alice |
| 2 | Bob |
| 3 | Tom |
| 4 | Jerry |
| 5 | John |
+-------------+-------+
Orders
+----------+------------+-------------+------------+
| order_id | order_date | customer_id | product_id |
+----------+------------+-------------+------------+
| 1 | 2020-07-31 | 1 | 1 |
| 2 | 2020-07-30 | 2 | 2 |
| 3 | 2020-08-29 | 3 | 3 |
| 4 | 2020-07-29 | 4 | 1 |
| 5 | 2020-06-10 | 1 | 2 |
| 6 | 2020-08-01 | 2 | 1 |
| 7 | 2020-08-01 | 3 | 3 |
| 8 | 2020-08-03 | 1 | 2 |
| 9 | 2020-08-07 | 2 | 3 |
| 10 | 2020-07-15 | 1 | 2 |
+----------+------------+-------------+------------+
Products
+------------+--------------+-------+
| product_id | product_name | price |
+------------+--------------+-------+
| 1 | keyboard | 120 |
| 2 | mouse | 80 |
| 3 | screen | 600 |
| 4 | hard disk | 450 |
+------------+--------------+-------+
Result 表:
+-------------+------------+--------------+
| customer_id | product_id | product_name |
+-------------+------------+--------------+
| 1 | 2 | mouse |
| 2 | 1 | keyboard |
| 2 | 2 | mouse |
| 2 | 3 | screen |
| 3 | 3 | screen |
| 4 | 1 | keyboard |
+-------------+------------+--------------+
Alice (customer 1) 三次订购鼠标, 一次订购键盘, 所以鼠标是 Alice 最经常订购的商品.
Bob (customer 2) 一次订购键盘, 一次订购鼠标, 一次订购显示器, 所以这些都是 Bob 最经常订购的商品.
Tom (customer 3) 只两次订购显示器, 所以显示器是 Tom 最经常订购的商品.
Jerry (customer 4) 只一次订购键盘, 所以键盘是 Jerry 最经常订购的商品.
John (customer 5) 没有订购过商品, 所以我们并没有把 John 包含在结果表中.
-
SQL1:
- 窗口函数
-
select t.customer_id, t.product_id, p.product_name from (select *, rank() over(partition by customer_id order by count(*) DESC) rk from Orders group by customer_id, product_id) t left join Products p on t.product_id = p.product_id where t.rk = 1
-
SQL2:
- 子查询
-
select o.customer_id, o.product_id, p.product_name from Orders o join Products p using(product_id) group by o.customer_id, o.product_id, p.product_name having (o.customer_id, count(*)) in (select customer_id, max(cnt) from (select customer_id, product_id, count(*) cnt from Orders group by customer_id, product_id) t group by customer_id)
没有卖出的卖家
表: Customer
+---------------+---------+
| Column Name | Type |
+---------------+---------+
| customer_id | int |
| customer_name | varchar |
+---------------+---------+
customer_id 是该表主键.
该表的每行包含网上商城的每一位顾客的信息.
表: Orders
+---------------+---------+
| Column Name | Type |
+---------------+---------+
| order_id | int |
| sale_date | date |
| order_cost | int |
| customer_id | int |
| seller_id | int |
+---------------+---------+
order_id 是该表主键.
该表的每行包含网上商城的所有订单的信息.
sale_date 是顾客customer_id和卖家seller_id之间交易的日期.
表: Seller
+---------------+---------+
| Column Name | Type |
+---------------+---------+
| seller_id | int |
| seller_name | varchar |
+---------------+---------+
seller_id 是该表主键.
该表的每行包含每一位卖家的信息.
写一个SQL语句,报告所有在2020年度没有任何卖出的卖家的名字。
返回结果按照seller_name升序排列。
查询结果格式如下例所示:
Customer 表:
+--------------+---------------+
| customer_id | customer_name |
+--------------+---------------+
| 101 | Alice |
| 102 | Bob |
| 103 | Charlie |
+--------------+---------------+
Orders 表:
+-------------+------------+--------------+-------------+-------------+
| order_id | sale_date | order_cost | customer_id | seller_id |
+-------------+------------+--------------+-------------+-------------+
| 1 | 2020-03-01 | 1500 | 101 | 1 |
| 2 | 2020-05-25 | 2400 | 102 | 2 |
| 3 | 2019-05-25 | 800 | 101 | 3 |
| 4 | 2020-09-13 | 1000 | 103 | 2 |
| 5 | 2019-02-11 | 700 | 101 | 2 |
+-------------+------------+--------------+-------------+-------------+
Seller 表:
+-------------+-------------+
| seller_id | seller_name |
+-------------+-------------+
| 1 | Daniel |
| 2 | Elizabeth |
| 3 | Frank |
+-------------+-------------+
Result 表:
+-------------+
| seller_name |
+-------------+
| Frank |
+-------------+
Daniel在2020年3月卖出1次.
Elizabeth在2020年卖出2次, 在2019年卖出1次.
Frank在2019年卖出1次, 在2020年没有卖出.
-
SQL1:
- join方法
-
select s.seller_name from Seller s left join (select distinct seller_id, order_cost from Orders where year(sale_date) = 2020) t using(seller_id) where t.order_cost is null order by seller_name
-
SQL2:
- 子查询
-
select seller_name from Seller where seller_id not in (select distinct seller_id from Orders where year(sale_date) = '2020') order by seller_name
找到遗失的ID
表: Customers
+---------------+---------+
| Column Name | Type |
+---------------+---------+
| customer_id | int |
| customer_name | varchar |
+---------------+---------+
customer_id 是该表主键.
该表第一行包含了顾客的名字和id.
写一个 SQL 语句,找到所有遗失的顾客id.遗失的顾客id是指那些不在Customers表中,值却处于1和表中最大customer_id之间的id。
注意: 最大的customer_id值不会超过100。
返回结果按ids 升序排列。
查询结果格式如下例所示:
Customers 表:
+-------------+---------------+
| customer_id | customer_name |
+-------------+---------------+
| 1 | Alice |
| 4 | Bob |
| 5 | Charlie |
+-------------+---------------+
Result 表:
+-----+
| ids |
+-----+
| 2 |
| 3 |
+-----+
表中最大的customer_id是5, 所以在范围[1,5]内, ID2和3从表中遗失.
-
SQL1:
-
select num ids from (select t1.i + t2.i * 10 num from (select 0 i union all select 1 i union all select 3 i union all select 4 i union all select 5 i union all select 2 i union all select 6 i union all select 7 i union all select 8 i union all select 9 i) t1, (select 0 i union all select 1 i union all select 3 i union all select 4 i union all select 5 i union all select 2 i union all select 6 i union all select 7 i union all select 8 i union all select 9 i) t2) n left join Customers c on c.customer_id = n.num where c.customer_id is null and n.num < (select max(customer_id) from Customers) and n.num > 0 order by num
-
-
SQL2:
-
with recursive t as ( select 1 customer_id union all select customer_id + 1 from t where customer_id < (select max(customer_id) from Customers)) select t.customer_id ids from t left join Customers c using(customer_id) where c.customer_id is null
-
三人国家代表队
表: SchoolA
+---------------+---------+
| Column Name | Type |
+---------------+---------+
| student_id | int |
| student_name | varchar |
+---------------+---------+
student_id 是表的主键
表中的每一行包含了学校A中每一个学生的名字和ID
所有student_name在表中都是独一无二的
表: SchoolB
+---------------+---------+
| Column Name | Type |
+---------------+---------+
| student_id | int |
| student_name | varchar |
+---------------+---------+
student_id 是表的主键
表中的每一行包含了学校B中每一个学生的名字和ID
所有student_name在表中都是独一无二的
表: SchoolC
+---------------+---------+
| Column Name | Type |
+---------------+---------+
| student_id | int |
| student_name | varchar |
+---------------+---------+
student_id 是表的主键
表中的每一行包含了学校C中每一个学生的名字和ID
所有student_name在表中都是独一无二的
有一个国家只有三所学校,这个国家的每一个学生只会注册一所学校。
这个国家正在参加一个竞赛,他们希望从这三所学校中各选出一个学生来组建一支三人的代表队。
例如:
member_A是从SchoolA中选出的member_B是从SchoolB中选出的member_C是从SchoolC中选出的- 被选中的学生具有不同的名字和ID(没有任何两个学生拥有相同的名字、没有任何两个学生拥有相同的ID)
使用上述条件,编写SQL查询语句来找到所有可能的三人国家代表队组合。
查询结果接受任何顺序。
查询结果格式样例:
SchoolA table:
+------------+--------------+
| student_id | student_name |
+------------+--------------+
| 1 | Alice |
| 2 | Bob |
+------------+--------------+
SchoolB table:
+------------+--------------+
| student_id | student_name |
+------------+--------------+
| 3 | Tom |
+------------+--------------+
SchoolC table:
+------------+--------------+
| student_id | student_name |
+------------+--------------+
| 3 | Tom |
| 2 | Jerry |
| 10 | Alice |
+------------+--------------+
预期结果:
+----------+----------+----------+
| member_A | member_B | member_C |
+----------+----------+----------+
| Alice | Tom | Jerry |
| Bob | Tom | Alice |
+----------+----------+----------+
让我们看看有哪些可能的组合:
- (Alice, Tom, Tom) --> 不适用,因为member_B(Tom)和member_C(Tom)有相同的名字和ID
- (Alice, Tom, Jerry) --> 可能的组合
- (Alice, Tom, Alice) --> 不适用,因为member_A和member_C有相同的名字
- (Bob, Tom, Tom) --> 不适用,因为member_B和member_C有相同的名字和ID
- (Bob, Tom, Jerry) --> 不适用,因为member_A和member_C有相同的ID
- (Bob, Tom, Alice) --> 可能的组合.
-
SQL1:
-
select a.student_name member_A, b.student_name member_B, c.student_name member_C from SchoolA a, SchoolB b, SchoolC c where a.student_id != b.student_id and b.student_id != c.student_id and a.student_id != c.student_id and a.student_name != b.student_name and b.student_name != c.student_name and a.student_name != c.student_name
-
-
SQL2:
-
select a.student_name member_A, b.student_name member_B, c.student_name member_C from SchoolA a join (SchoolB b, SchoolC c) on (a.student_id <> b.student_id and b.student_id <> c.student_id and a.student_id <> c.student_id and a.student_name <> b.student_name and b.student_name <> c.student_name and a.student_name <> c.student_name)
-
各赛事的用户注册率
用户表: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 和他们注册的赛事。
写一条 SQL 语句,查询各赛事的用户注册百分率,保留两位小数。
返回的结果表按percentage的降序排序,若相同则按contest_id的升序排序。
查询结果如下示例所示:
Users 表:
+---------+-----------+
| user_id | user_name |
+---------+-----------+
| 6 | Alice |
| 2 | Bob |
| 7 | Alex |
+---------+-----------+
Register 表:
+------------+---------+
| contest_id | user_id |
+------------+---------+
| 215 | 6 |
| 209 | 2 |
| 208 | 2 |
| 210 | 6 |
| 208 | 6 |
| 209 | 7 |
| 209 | 6 |
| 215 | 7 |
| 208 | 7 |
| 210 | 2 |
| 207 | 2 |
| 210 | 7 |
+------------+---------+
结果表:
+------------+------------+
| contest_id | percentage |
+------------+------------+
| 208 | 100.0 |
| 209 | 100.0 |
| 210 | 100.0 |
| 215 | 66.67 |
| 207 | 33.33 |
+------------+------------+
所有用户都注册了 208、209 和 210 赛事,因此这些赛事的注册率为 100% ,我们按 contest_id 的降序排序加入结果表中。
Alice 和 Alex 注册了 215 赛事,注册率为 ((2/3) * 100) = 66.67%
Bob 注册了 207 赛事,注册率为 ((1/3) * 100) = 33.33%
- SQL:
-
select contest_id, round(count(*) / (select count(*) from Users) * 100, 2) percentage from Register group by contest_id order by percentage DESC, contest_id
-
Hopper 公司查询系列
表: Drivers
+-------------+---------+
| Column Name | Type |
+-------------+---------+
| driver_id | int |
| join_date | date |
+-------------+---------+
driver_id是该表的主键。
该表的每一行均包含驾驶员的ID以及他们加入Hopper公司的日期。
表: Rides
+--------------+---------+
| Column Name | Type |
+--------------+---------+
| ride_id | int |
| user_id | int |
| requested_at | date |
+--------------+---------+
ride_id是该表的主键。
该表的每一行均包含行程ID(ride_id),用户ID(user_id)以及该行程的日期(requested_at)。
该表中可能有一些不被接受的乘车请求。
表: AcceptedRides
+---------------+---------+
| Column Name | Type |
+---------------+---------+
| ride_id | int |
| driver_id | int |
| ride_distance | int |
| ride_duration | int |
+---------------+---------+
ride_id是该表的主键。
该表的每一行都包含已接受的行程信息。
表中的行程信息都在“Rides”表中存在。
1、编写SQL查询以报告2020年每个月的以下统计信息:
- 截至某月底,当前在Hopper公司工作的驾驶员数量(
active_drivers)。 - 该月接受的乘车次数(
accepted_rides)。
返回按month 升序排列的结果表,其中month 是月份的数字(一月是1,二月是2,依此类推)。
查询结果格式如下例所示:
表 Drivers:
+-----------+------------+
| driver_id | join_date |
+-----------+------------+
| 10 | 2019-12-10 |
| 8 | 2020-1-13 |
| 5 | 2020-2-16 |
| 7 | 2020-3-8 |
| 4 | 2020-5-17 |
| 1 | 2020-10-24 |
| 6 | 2021-1-5 |
+-----------+------------+
表 Rides:
+---------+---------+--------------+
| ride_id | user_id | requested_at |
+---------+---------+--------------+
| 6 | 75 | 2019-12-9 |
| 1 | 54 | 2020-2-9 |
| 10 | 63 | 2020-3-4 |
| 19 | 39 | 2020-4-6 |
| 3 | 41 | 2020-6-3 |
| 13 | 52 | 2020-6-22 |
| 7 | 69 | 2020-7-16 |
| 17 | 70 | 2020-8-25 |
| 20 | 81 | 2020-11-2 |
| 5 | 57 | 2020-11-9 |
| 2 | 42 | 2020-12-9 |
| 11 | 68 | 2021-1-11 |
| 15 | 32 | 2021-1-17 |
| 12 | 11 | 2021-1-19 |
| 14 | 18 | 2021-1-27 |
+---------+---------+--------------+
表 AcceptedRides:
+---------+-----------+---------------+---------------+
| ride_id | driver_id | ride_distance | ride_duration |
+---------+-----------+---------------+---------------+
| 10 | 10 | 63 | 38 |
| 13 | 10 | 73 | 96 |
| 7 | 8 | 100 | 28 |
| 17 | 7 | 119 | 68 |
| 20 | 1 | 121 | 92 |
| 5 | 7 | 42 | 101 |
| 2 | 4 | 6 | 38 |
| 11 | 8 | 37 | 43 |
| 15 | 8 | 108 | 82 |
| 12 | 8 | 38 | 34 |
| 14 | 1 | 90 | 74 |
+---------+-----------+---------------+---------------+
结果表:
+-------+----------------+----------------+
| month | active_drivers | accepted_rides |
+-------+----------------+----------------+
| 1 | 2 | 0 |
| 2 | 3 | 0 |
| 3 | 4 | 1 |
| 4 | 4 | 0 |
| 5 | 5 | 0 |
| 6 | 5 | 1 |
| 7 | 5 | 1 |
| 8 | 5 | 1 |
| 9 | 5 | 0 |
| 10 | 6 | 0 |
| 11 | 6 | 2 |
| 12 | 6 | 1 |
+-------+----------------+----------------+
截至1月底->两个活跃的驾驶员(10,8),没有被接受的行程。
截至2月底->三个活跃的驾驶员(10,8,5),没有被接受的行程。
截至3月底->四个活跃的驾驶员(10,8,5,7),一个被接受的行程(10)。
截至4月底->四个活跃的驾驶员(10,8,5,7),没有被接受的行程。
截至5月底->五个活跃的驾驶员(10,8,5,7,4),没有被接受的行程。
截至6月底->五个活跃的驾驶员(10,8,5,7,4),一个被接受的行程(13)。
截至7月底->五个活跃的驾驶员(10,8,5,7,4),一个被接受的行程(7)。
截至8月底->五个活跃的驾驶员(10,8,5,7,4),一位接受的行程(17)。
截至9月底->五个活跃的驾驶员(10,8,5,7,4),没有被接受的行程。
截至10月底->六个活跃的驾驶员(10,8,5,7,4,1),没有被接受的行程。
截至11月底->六个活跃的驾驶员(10,8,5,7,4,1),两个被接受的行程(20,5)。
截至12月底->六个活跃的驾驶员(10,8,5,7,4,1),一个被接受的行程(2)。
- SQL:
-
with recursive t as( select 1 month union all select month + 1 from t where month < 12) select month, active_drivers, accepted_rides from (select t.month, ifnull(count(d.driver_id), 0) active_drivers from t left join Drivers d on 202000 + month >= date_format(d.join_date, '%Y%m') group by t.month) t1 left join (select t.month, ifnull(count(ar.ride_id), 0) accepted_rides from t left join (select ride_id, requested_at from AcceptedRides a join Rides r using(ride_id)) ar on 202000 + month = date_format(ar.requested_at, '%Y%m') group by t.month) t2 using(month)
-
2、编写SQL查询以报告2020年每个月的工作驱动因素百分比(working_percentage),其中:
注意:如果一个月内可用驾驶员的数量为零,我们认为working_percentage为0。
返回按month升序排列的结果表,其中month是月份的编号(一月是1,二月是2,等等)。将working_percentage四舍五入至小数点后两位。
查询结果格式如下例所示:
表 Drivers:
+-----------+------------+
| driver_id | join_date |
+-----------+------------+
| 10 | 2019-12-10 |
| 8 | 2020-1-13 |
| 5 | 2020-2-16 |
| 7 | 2020-3-8 |
| 4 | 2020-5-17 |
| 1 | 2020-10-24 |
| 6 | 2021-1-5 |
+-----------+------------+
表 Rides:
+---------+---------+--------------+
| ride_id | user_id | requested_at |
+---------+---------+--------------+
| 6 | 75 | 2019-12-9 |
| 1 | 54 | 2020-2-9 |
| 10 | 63 | 2020-3-4 |
| 19 | 39 | 2020-4-6 |
| 3 | 41 | 2020-6-3 |
| 13 | 52 | 2020-6-22 |
| 7 | 69 | 2020-7-16 |
| 17 | 70 | 2020-8-25 |
| 20 | 81 | 2020-11-2 |
| 5 | 57 | 2020-11-9 |
| 2 | 42 | 2020-12-9 |
| 11 | 68 | 2021-1-11 |
| 15 | 32 | 2021-1-17 |
| 12 | 11 | 2021-1-19 |
| 14 | 18 | 2021-1-27 |
+---------+---------+--------------+
表 AcceptedRides:
+---------+-----------+---------------+---------------+
| ride_id | driver_id | ride_distance | ride_duration |
+---------+-----------+---------------+---------------+
| 10 | 10 | 63 | 38 |
| 13 | 10 | 73 | 96 |
| 7 | 8 | 100 | 28 |
| 17 | 7 | 119 | 68 |
| 20 | 1 | 121 | 92 |
| 5 | 7 | 42 | 101 |
| 2 | 4 | 6 | 38 |
| 11 | 8 | 37 | 43 |
| 15 | 8 | 108 | 82 |
| 12 | 8 | 38 | 34 |
| 14 | 1 | 90 | 74 |
+---------+-----------+---------------+---------------+
结果表:
+-------+--------------------+
| month | working_percentage |
+-------+--------------------+
| 1 | 0.00 |
| 2 | 0.00 |
| 3 | 25.00 |
| 4 | 0.00 |
| 5 | 0.00 |
| 6 | 20.00 |
| 7 | 20.00 |
| 8 | 20.00 |
| 9 | 0.00 |
| 10 | 0.00 |
| 11 | 33.33 |
| 12 | 16.67 |
+-------+--------------------+
截至1月底 --> 2个活跃的驾驶员 (10, 8),无被接受的行程。百分比是0%。
截至2月底 --> 3个活跃的驾驶员 (10, 8, 5),无被接受的行程。百分比是0%。
截至3月底 --> 4个活跃的驾驶员 (10, 8, 5, 7),1个被接受的行程 (10)。百分比是 (1 / 4) * 100 = 25%。
截至4月底 --> 4个活跃的驾驶员 (10, 8, 5, 7),无被接受的行程。百分比是 0%。
截至5月底 --> 5个活跃的驾驶员 (10, 8, 5, 7, 4),无被接受的行程。百分比是 0%。
截至6月底 --> 5个活跃的驾驶员 (10, 8, 5, 7, 4),1个被接受的行程 (10)。 百分比是 (1 / 5) * 100 = 20%。
截至7月底 --> 5个活跃的驾驶员 (10, 8, 5, 7, 4),1个被接受的行程 (8)。百分比是 (1 / 5) * 100 = 20%。
截至8月底 --> 5个活跃的驾驶员 (10, 8, 5, 7, 4),1个被接受的行程 (7)。百分比是 (1 / 5) * 100 = 20%。
截至9月底 --> 5个活跃的驾驶员 (10, 8, 5, 7, 4),无被接受的行程。百分比是 0%。
截至10月底 --> 6个活跃的驾驶员 (10, 8, 5, 7, 4, 1) 无被接受的行程。百分比是 0%。
截至11月底 --> 6个活跃的驾驶员 (10, 8, 5, 7, 4, 1),2个被接受的行程 (1, 7)。百分比是 (2 / 6) * 100 = 33.33%。
截至12月底 --> 6个活跃的驾驶员 (10, 8, 5, 7, 4, 1),1个被接受的行程 (4)。百分比是 (1 / 6) * 100 = 16.67%。
- SQL:
-
with recursive t as( select 1 month union all select month + 1 from t where month < 12) select month, round(ifnull(ifnull(accepted_rides, 0) * 100 / active_drivers, 0), 2) working_percentage from (select t.month, ifnull(count(d.driver_id), 0) active_drivers from t left join Drivers d on 202000 + month >= date_format(d.join_date, '%Y%m') group by t.month) t1 left join (select month(requested_at) month, count(distinct driver_id) accepted_rides from Rides r join AcceptedRides a using(ride_id) where year(requested_at) = 2020 group by month(requested_at)) t2 using(month) order by month
-
3、编写SQL查询以计算从 2020年1月至3月至2020年10月至12月 的每三个月窗口的 average_ride_distance 和 average_ride_duration 。
将 average_ride_distance 和 average_ride_duration 四舍五入至 小数点后两位 。
通过将三个月的总 ride_distance 相加并除以 3 来计算 average_ride_distance 。average_ride_duration 的计算方法与此类似。
返回按 month 升序排列的结果表,其中 month 是起始月份的编号(一月为 1,二月为 2 ...)。
查询结果格式如下例所示:
输入:
Drivers table:
+-----------+------------+
| driver_id | join_date |
+-----------+------------+
| 10 | 2019-12-10 |
| 8 | 2020-1-13 |
| 5 | 2020-2-16 |
| 7 | 2020-3-8 |
| 4 | 2020-5-17 |
| 1 | 2020-10-24 |
| 6 | 2021-1-5 |
+-----------+------------+
Rides table:
+---------+---------+--------------+
| ride_id | user_id | requested_at |
+---------+---------+--------------+
| 6 | 75 | 2019-12-9 |
| 1 | 54 | 2020-2-9 |
| 10 | 63 | 2020-3-4 |
| 19 | 39 | 2020-4-6 |
| 3 | 41 | 2020-6-3 |
| 13 | 52 | 2020-6-22 |
| 7 | 69 | 2020-7-16 |
| 17 | 70 | 2020-8-25 |
| 20 | 81 | 2020-11-2 |
| 5 | 57 | 2020-11-9 |
| 2 | 42 | 2020-12-9 |
| 11 | 68 | 2021-1-11 |
| 15 | 32 | 2021-1-17 |
| 12 | 11 | 2021-1-19 |
| 14 | 18 | 2021-1-27 |
+---------+---------+--------------+
AcceptedRides table:
+---------+-----------+---------------+---------------+
| ride_id | driver_id | ride_distance | ride_duration |
+---------+-----------+---------------+---------------+
| 10 | 10 | 63 | 38 |
| 13 | 10 | 73 | 96 |
| 7 | 8 | 100 | 28 |
| 17 | 7 | 119 | 68 |
| 20 | 1 | 121 | 92 |
| 5 | 7 | 42 | 101 |
| 2 | 4 | 6 | 38 |
| 11 | 8 | 37 | 43 |
| 15 | 8 | 108 | 82 |
| 12 | 8 | 38 | 34 |
| 14 | 1 | 90 | 74 |
+---------+-----------+---------------+---------------+
输出:
+-------+-----------------------+-----------------------+
| month | average_ride_distance | average_ride_duration |
+-------+-----------------------+-----------------------+
| 1 | 21.00 | 12.67 |
| 2 | 21.00 | 12.67 |
| 3 | 21.00 | 12.67 |
| 4 | 24.33 | 32.00 |
| 5 | 57.67 | 41.33 |
| 6 | 97.33 | 64.00 |
| 7 | 73.00 | 32.00 |
| 8 | 39.67 | 22.67 |
| 9 | 54.33 | 64.33 |
| 10 | 56.33 | 77.00 |
+-------+-----------------------+-----------------------+
解释:
到1月底-->平均骑行距离=(0+0+63)/3=21,平均骑行持续时间=(0+0+38)/3=12.67
到2月底-->平均骑行距离=(0+63+0)/3=21,平均骑行持续时间=(0+38+0)/3=12.67
到3月底-->平均骑行距离=(63+0+0)/3=21,平均骑行持续时间=(38+0+0)/3=12.67
到4月底-->平均骑行距离=(0+0+73)/3=24.33,平均骑行持续时间=(0+0+96)/3=32.00
到5月底-->平均骑行距离=(0+73+100)/3=57.67,平均骑行持续时间=(0+96+28)/3=41.33
到6月底-->平均骑行距离=(73+100+119)/3=97.33,平均骑行持续时间=(96+28+68)/3=64.00
到7月底-->平均骑行距离=(100+119+0)/3=73.00,平均骑行持续时间=(28+68+0)/3=32.00
到8月底-->平均骑行距离=(119+0+0)/3=39.67,平均骑行持续时间=(68+0+0)/3=22.67
9月底-->平均骑行距离=(0+0+163)/3=54.33,平均骑行持续时间=(0+0+193)/3=64.33
到10月底-->平均骑行距离=(0+163+6)/3=56.33,平均骑行持续时间=(0+193+38)/3=77.00
-
SQL1:
- 窗口函数
-
with recursive t as( select 1 month union all select month + 1 from t where month < 12) select t.month, round(avg(ifnull(sum(t2.ride_distance), 0)) over(order by t.month RANGE BETWEEN CURRENT ROW and 2 FOLLOWING), 2) average_ride_distance, round(avg(ifnull(sum(t2.ride_duration),0))over(order by t.month RANGE BETWEEN CURRENT ROW and 2 FOLLOWING), 2) average_ride_duration from t left join (select t1.month, a.ride_distance, a.ride_duration from AcceptedRides a join (select r.ride_id, month(r.requested_at) month from Rides r where year(r.requested_at)='2020') t1 using(ride_id)) t2 using(month) group by t.month order by t.month limit 10
-
SQL2:
-
with recursive t as( select 1 month union all select month + 1 from t where month < 12) select t.month, ifnull(round(sum(ride_distance) / 3, 2), 0) average_ride_distance, ifnull(round(sum(ride_duration) / 3, 2), 0) average_ride_duration from Acceptedrides a left join Rides r using(ride_id) right join t on year(requested_at) = 2020 and month(requested_at) between t.month and t.month + 2 group by t.month order by t.month limit 10
-