1.连续出现的数字---连续计数
+----+-----+
| Id | Num |
+----+-----+
| 1 | 1 |
| 2 | 1 |
| 3 | 1 |
| 4 | 2 |
| 5 | 1 |
| 6 | 2 |
| 7 | 2 |
+----+-----+
编写一个 SQL 查询,查找所有至少连续出现三次的数字。
+-----------------+
| ConsecutiveNums |
+-----------------+
| 1 |
+-----------------+
详见
Lotus:Leetcode经典SQL刷题笔记(四)-连续区间问题zhuanlan.zhihu.com![a6f940a3da126342be052878c16c3dad.png](https://img-blog.csdnimg.cn/img_convert/a6f940a3da126342be052878c16c3dad.png)
2.游戏玩法介绍---次日登录
Activity table:
+-----------+-----------+------------+--------------+
| player_id | device_id | event_date | games_played |
+-----------+-----------+------------+--------------+
| 1 | 2 | 2016-03-01 | 5 |
| 1 | 2 | 2016-03-02 | 6 |
| 2 | 3 | 2017-06-25 | 1 |
| 3 | 1 | 2016-03-02 | 0 |
| 3 | 4 | 2018-07-03 | 5 |
+-----------+-----------+------------+--------------+
编写一个 SQL 查询,报告在首次登录的第二天再次登录的玩家的分数,四舍五入到小数点后两位。换句话说,您需要计算从首次登录日期开始至少连续两天登录的玩家的数量,然后除以玩家总数。
Result table:
+-----------+
| fraction |
+-----------+
| 0.33 |
+-----------+
只有 ID 为 1 的玩家在第一天登录后才重新登录,所以答案是 1/3 = 0.33
注意:首次登录
详见:
红酥手:leetcode(sql)之游戏玩法zhuanlan.zhihu.com3.好友申请---union all
| requester_id | accepter_id | accept_date|
|--------------|-------------|------------|
| 1 | 2 | 2016_06-03 |
| 1 | 3 | 2016-06-08 |
| 2 | 3 | 2016-06-08 |
| 3 | 4 | 2016-06-09 |
写一个查询语句,求出谁拥有最多的好友和他拥有的好友数目。
| id | num |
|----|-----|
| 3 | 3 |
思路:这个表的结果是接受,那么无论是申请者还是接收者,某人总数最大,那么就拥有最多的好友
使用union all来合并
select distinct a.id,count(1) as num
from
(select requester_id id from request_accepted
union all
select accepter_id id from request_accepted)a
group by a.id
order by count(1) desc limit 1
4.树节点
给定一个表 tree,id 是树节点的编号, p_id 是它父节点的 id
+----+------+
| id | p_id |
+----+------+
| 1 | null |
| 2 | 1 |
| 3 | 1 |
| 4 | 2 |
| 5 | 2 |
+----+------+
树中每个节点属于以下三种类型之一:
叶子:如果这个节点没有任何孩子节点。
根:如果这个节点是整棵树的根,即没有父节点。
内部节点:如果这个节点既不是叶子节点也不是根节点。
写一个查询语句,输出所有节点的编号和节点的类型,并将结果按照节点编号排序。
+----+------+
| id | Type |
+----+------+
| 1 | Root |
| 2 | Inner|
| 3 | Leaf |
| 4 | Leaf |
| 5 | Leaf |
+----+------+
节点 '1' 是根节点,因为它的父节点是 NULL ,同时它有孩子节点 '2' 和 '3' 。
节点 '2' 是内部节点,因为它有父节点 '1' ,也有孩子节点 '4' 和 '5' 。
节点 '3', '4' 和 '5' 都是叶子节点,因为它们都有父节点同时没有孩子节点。
难点:直接定义叶子节点比较困难
解法一:定义完父节点和内部节点,然后else就是子节点
---父节点定义为p_id为null,子节点定义为出现在p_id这一栏
select id,
case when t.p_id is null then 'Root'
when t.id in (select p_id from tree ) then 'Inner'
else 'Leaf'
end as Type
from tree t
解法二:直接定义子节点
select id,
case when t.p_id is null then 'Root'
when id not in (select p_id from tree where p_id is not null) then 'Leaf'
else 'Inner'
end as Type
from tree t
注意条件
5.换座位
+---------+---------+
| id | student |
+---------+---------+
| 1 | Abbot |
| 2 | Doris |
| 3 | Emerson |
| 4 | Green |
| 5 | Jeames |
+---------+---------+
有一张 seat 座位表,平时用来储存学生名字和与他们相对应的座位 id。其中纵列的 id 是连续递增的,小美想改变相邻俩学生的座位。
+---------+---------+
| id | student |
+---------+---------+
| 1 | Doris |
| 2 | Abbot |
| 3 | Green |
| 4 | Emerson |
| 5 | Jeames |
+---------+---------+
如果学生人数是奇数,则不需要改变最后一个同学的座位。
难点:换id而不换学生
SELECT (CASE
WHEN MOD(id,2) = 1 AND id = (SELECT COUNT(*) FROM seat) THEN id
WHEN MOD(id,2) = 1 THEN id+1
ElSE id-1
END) AS id, student
FROM seat
ORDER BY id;
6.小众书籍---条件位置
Books 表:
+---------+--------------------+----------------+
| book_id | name | available_from |
+---------+--------------------+----------------+
| 1 | "Kalila And Demna" | 2010-01-01 |
| 2 | "28 Letters" | 2012-05-12 |
| 3 | "The Hobbit" | 2019-06-10 |
| 4 | "13 Reasons Why" | 2019-06-01 |
| 5 | "The Hunger Games" | 2008-09-21 |
+---------+--------------------+----------------+
Orders 表:
+----------+---------+----------+---------------+
| order_id | book_id | quantity | dispatch_date |
+----------+---------+----------+---------------+
| 1 | 1 | 2 | 2018-07-26 |
| 2 | 1 | 1 | 2018-11-05 |
| 3 | 3 | 8 | 2019-06-11 |
| 4 | 4 | 6 | 2019-06-05 |
| 5 | 4 | 5 | 2019-06-20 |
| 6 | 5 | 9 | 2009-02-02 |
| 7 | 5 | 8 | 2010-04-13 |
+----------+---------+----------+---------------+
筛选出过去一年中订单总量少于10本的书籍 。注意:不考虑上架(available from距今不满一个月的书籍。并且假设今天是2019-06-23。
Result 表:
+-----------+--------------------+
| book_id | name |
+-----------+--------------------+
| 1 | "Kalila And Demna" |
| 2 | "28 Letters" |
| 5 | "The Hunger Games" |
+-----------+--------------------+
难点:条件
详见:
红酥手:leetcode(sql)之条件究竟放在哪里zhuanlan.zhihu.com7.报告的记录
Actions table:
+---------+---------+-------------+--------+--------+
| user_id | post_id | action_date | action | extra |
+---------+---------+-------------+--------+--------+
| 1 | 1 | 2019-07-01 | view | null |
| 1 | 1 | 2019-07-01 | like | null |
| 1 | 1 | 2019-07-01 | share | null |
| 2 | 2 | 2019-07-04 | view | null |
| 2 | 2 | 2019-07-04 | report | spam |
| 3 | 4 | 2019-07-04 | view | null |
| 3 | 4 | 2019-07-04 | report | spam |
| 4 | 3 | 2019-07-02 | view | null |
| 4 | 3 | 2019-07-02 | report | spam |
| 5 | 2 | 2019-07-03 | view | null |
| 5 | 2 | 2019-07-03 | report | racism |
| 5 | 5 | 2019-07-03 | view | null |
| 5 | 5 | 2019-07-03 | report | racism |
+---------+---------+-------------+--------+--------+
Removals table:
+---------+-------------+
| post_id | remove_date |
+---------+-------------+
| 2 | 2019-07-20 |
| 3 | 2019-07-18 |
+---------+-------------+
编写一段SQL来查找:在被报告为垃圾广告的帖子中,被移除的帖子的每日平均占比,四舍五入到小数点后2 位。
Removals table:
+---------+-------------+
| post_id | remove_date |
+---------+-------------+
| 2 | 2019-07-20 |
| 3 | 2019-07-18 |
+---------+-------------+
Result table:
+-----------------------+
| average_daily_percent |
+-----------------------+
| 75.00 |
+-----------------------+
2019-07-04 的垃圾广告移除率是 50%,因为有两张帖子被报告为垃圾广告,但只有一个得到移除。
2019-07-02 的垃圾广告移除率是 100%,因为有一张帖子被举报为垃圾广告并得到移除。
其余几天没有收到垃圾广告的举报,因此平均值为:(50 + 100) / 2 = 75%
注意,输出仅需要一个平均值即可,我们并不关注移除操作的日期。
难点:如何分别计算在不同时间维度下的移除率
详见:
红酥手:leetcode(sql)之时间维度zhuanlan.zhihu.com8.指定日期的产品价格
Products table:
+------------+-----------+-------------+
| product_id | new_price | change_date |
+------------+-----------+-------------+
| 1 | 20 | 2019-08-14 |
| 2 | 50 | 2019-08-14 |
| 1 | 30 | 2019-08-15 |
| 1 | 35 | 2019-08-16 |
| 2 | 65 | 2019-08-17 |
| 3 | 20 | 2019-08-18 |
+------------+-----------+-------------+
写一段 SQL来查找在2019-08-16时全部产品的价格,假设所有产品在修改前的价格都是10。
Result table:
+------------+-------+
| product_id | price |
+------------+-------+
| 2 | 50 |
| 1 | 35 |
| 3 | 10 |
+------------+-------+
难点:如何将未修改的产品挑出来并置其价格为10,而且要选择每个产品最近的时间对应的价格作为最终的价格
详见:
红酥手:leetcode(sql)之打标签zhuanlan.zhihu.com9.每月交易---打标签
Transactions 表:
+------+---------+----------+--------+------------+
| id | country | state | amount | trans_date |
+------+---------+----------+--------+------------+
| 101 | US | approved | 1000 | 2019-05-18 |
| 102 | US | declined | 2000 | 2019-05-19 |
| 103 | US | approved | 3000 | 2019-06-10 |
| 104 | US | approved | 4000 | 2019-06-13 |
| 105 | US | approved | 5000 | 2019-06-15 |
+------+---------+----------+--------+------------+
Chargebacks 表:
+------------+------------+
| trans_id | trans_date |
+------------+------------+
| 102 | 2019-05-29 |
| 101 | 2019-06-30 |
| 105 | 2019-09-18 |
+------------+------------+
编写一个SQL查询,以查找每个月和每个国家/地区的已批准交易的数量及其总金额、退单的数量及其总金额。注意:在您的查询中,给定月份和国家,忽略所有为零的行。
Result 表:
+----------+---------+----------------+-----------------+-------------------+--------------------+
| month | country | approved_count | approved_amount | chargeback_count | chargeback_amount |
+----------+---------+----------------+-----------------+-------------------+--------------------+
| 2019-05 | US | 1 | 1000 | 1 | 2000 |
| 2019-06 | US | 3 | 12000 | 1 | 1000 |
| 2019-09 | US | 0 | 0 | 1 | 5000 |
+----------+---------+----------------+-----------------+-------------------+--------------------+
难点:如何区分两种不同的状态:已批准和退单
详见:
红酥手:leetcode(sql)之打标签zhuanlan.zhihu.com10.查询球队得分
Teams table:
+-----------+--------------+
| team_id | team_name |
+-----------+--------------+
| 10 | Leetcode FC |
| 20 | NewYork FC |
| 30 | Atlanta FC |
| 40 | Chicago FC |
| 50 | Toronto FC |
+-----------+--------------+
Matches table:
+------------+--------------+---------------+-------------+--------------+
| match_id | host_team | guest_team | host_goals | guest_goals |
+------------+--------------+---------------+-------------+--------------+
| 1 | 10 | 20 | 3 | 0 |
| 2 | 30 | 10 | 2 | 2 |
| 3 | 10 | 50 | 5 | 1 |
| 4 | 20 | 30 | 1 | 0 |
| 5 | 50 | 30 | 1 | 0 |
+------------+--------------+---------------+-------------+--------------+
积分规则如下:
赢一场得三分;
平一场得一分;
输一场不得分。
写出一条SQL语句以查询每个队的 team_id,team_name 和 num_points。结果根据 num_points 降序排序,如果有两队积分相同,那么这两队按 team_id 升序排序。
Result table:
+------------+--------------+---------------+
| team_id | team_name | num_points |
+------------+--------------+---------------+
| 10 | Leetcode FC | 7 |
| 20 | NewYork FC | 3 |
| 50 | Toronto FC | 3 |
| 30 | Atlanta FC | 1 |
| 40 | Chicago FC | 0 |
+------------+--------------+---------------+
难点:要计算每个队分别在主场和客场的得分,再求和
详见:
红酥手:leetcode(sql)之打标签zhuanlan.zhihu.com11.找到连续区间的开始和结束数字
Logs 表:
+------------+
| log_id |
+------------+
| 1 |
| 2 |
| 3 |
| 7 |
| 8 |
| 10 |
+------------+
后来一些 ID从Logs表中删除。编写一个 SQL查询得到Logs表中的连续区间的开始数字和结束数字。将查询表按照start_id排序。
结果表:
+------------+--------------+
| start_id | end_id |
+------------+--------------+
| 1 | 3 |
| 7 | 8 |
| 10 | 10 |
+------------+--------------+
结果表应包含 Logs 表中的所有区间。
从 1 到 3 在表中。
从 4 到 6 不在表中。
从 7 到 8 在表中。
9 不在表中。
10 在表中。
难点:状态的改变
详见:
Lotus:Leetcode经典SQL刷题笔记(四)-连续区间问题zhuanlan.zhihu.com![a6f940a3da126342be052878c16c3dad.png](https://img-blog.csdnimg.cn/img_convert/a6f940a3da126342be052878c16c3dad.png)
12.餐馆营业额变化增长
Customer 表:
+-------------+--------------+--------------+-------------+
| customer_id | name | visited_on | amount |
+-------------+--------------+--------------+-------------+
| 1 | Jhon | 2019-01-01 | 100 |
| 2 | Daniel | 2019-01-02 | 110 |
| 3 | Jade | 2019-01-03 | 120 |
| 4 | Khaled | 2019-01-04 | 130 |
| 5 | Winston | 2019-01-05 | 110 |
| 6 | Elvis | 2019-01-06 | 140 |
| 7 | Anna | 2019-01-07 | 150 |
| 8 | Maria | 2019-01-08 | 80 |
| 9 | Jaze | 2019-01-09 | 110 |
| 1 | Jhon | 2019-01-10 | 130 |
| 3 | Jade | 2019-01-10 | 150 |
+-------------+--------------+--------------+-------------+
你是餐馆的老板,现在你想分析一下可能的营业额变化增长(每天至少有一位顾客)写一条 SQL 查询计算以 7 天(某日期 + 该日期前的 6 天)为一个时间段的顾客消费平均值查询结果格式的例子如下:查询结果按 visited_on 排序,average_amount 要 保留两位小数,日期数据的格式为 ('YYYY-MM-DD')
结果表:
+--------------+--------------+----------------+
| visited_on | amount | average_amount |
+--------------+--------------+----------------+
| 2019-01-07 | 860 | 122.86 |
| 2019-01-08 | 840 | 120 |
| 2019-01-09 | 840 | 120 |
| 2019-01-10 | 1000 | 142.86 |
+--------------+--------------+----------------+
第一个七天消费平均值从 2019-01-01 到 2019-01-07 是 (100 + 110 + 120 + 130 + 110 + 140 + 150)/7 = 122.86
第二个七天消费平均值从 2019-01-02 到 2019-01-08 是 (110 + 120 + 130 + 110 + 140 + 150 + 80)/7 = 120
第三个七天消费平均值从 2019-01-03 到 2019-01-09 是 (120 + 130 + 110 + 140 + 150 + 80 + 110)/7 = 120
第四个七天消费平均值从 2019-01-04 到 2019-01-10 是 (130 + 110 + 140 + 150 + 80 + 110 + 130 + 150)/7 = 142.86
注意:结果表中第四个七天消费平均值,分子是8个数字之和,而分母是7,因为2019-01-10这一天有两个值,而且找到visited_on也比较难
解法一:每天至少一个顾客,连续7天,和第一道题连续出现的数字类似 between 0 and 6
select a.visited_on, sum(b.amount) amount, round(avg(b.amount),2) average_amount
from (select visited_on, sum(amount) amount from customer group by visited_on order by
visited_on) a
left join
(select visited_on, sum(amount) amount from customer group by visited_on order by
visited_on) b
on datediff(a.visited_on,b.visited_on) between 0 and 6
group by a.visited_on
having count(*) = 7
解法二: 找出查询表的日期列,和最小日期相比大于7天的日期为要记录的日期
select date_format(a.visited_on,"%Y-%m-%d") as visited_on,
sum(amount) as amount,
round(sum(amount)/7,2) as average_amount
from
(select distinct visited_on
from customer
where visited_on>=adddate(
(select min(visited_on)
from customer),interval 6 day)) as a
left join customer as c
on datediff(a.visited_on,c.visited_on)<=6 and a.visited_on>=c.visited_on
group by a.visited_on
order by a.visited_on,c.visited_on;