高频SQL50题
查询
Where&GroupBy&HAVING
1SELECT id, revenue # 某个用户2021年可能有多项记录
2FROM users
3Where year = 2021
4
5SELECT id, SUM(revenue)
6FROM users
7Where year = 2021 # 1. 先筛选出此年份所有记录
8Group By id # 2. 再根据id分组 3. 必须结合SUM() 或者其他聚合函数,因此这个有多列,需要处理为单值。
9
10SELECT id
11FROM users
12Where year = 2021 # 1. 先筛选记录
13Group By id # 2. 分组
14HAVING SUM(revenue) > 1000 # 3. 聚合分组字段记录 并 判断
查找没买过东西的顾客
1# 1. NOT EXISTS
2SELECT `name` AS `Customers`
3FROM `Customers` AS c
4WHERE NOT EXISTS (
5 SELECT `customerId`
6 FROM `Orders` AS o
7 Where o.customerId = c.id
8)
1# 2. Left Join
2# example
3SELECT c.id AS id, c.name, o.id AS oid
4FROM customers AS c LEFT JOIN orders AS o
5on c.id = o.customerId
6
7SELECT `name` as `Customers`
8FROM customers AS c LEFT JOIN orders AS o
9on c.id = o.customerId
10WHERE o.id is NULL
计算特殊奖金
编写解决方案,计算每个雇员的奖金。如果一个雇员的 id 是 奇数 并且他的名字不是以 'M' 开头,那么他的奖金是他工资的 100% ,否则奖金为 0 。
返回的结果按照 employee_id 排序。
IF用法 IF(condition, True, False) AS alias
1select `employee_id`, IF(name not like 'M%' and employee_id%2 = 1, salary, 0) AS `bonus`
2from Employees
3Order by employee_id ASC
购买了产品 A 和产品 B 却没有购买产品 C 的顾客
Where 中 多重 判断
1select customer_id, customer_name
2from Customers as c
3where exists (
4 select o.customer_id
5 from Orders as o
6 where o.customer_id=c.customer_id and product_name = 'A'
7) and exists (
8 select o.customer_id
9 from Orders as o
10 where o.customer_id=c.customer_id and product_name = 'B'
11) and not exists (
12 select o.customer_id
13 from Orders as o
14 where o.customer_id=c.customer_id and product_name = 'C'
15)
16Order By c.customer_id ASC
连表,分组判断
1SELECT c.customer_id, c.customer_name
2FROM `Orders` as o left join `Customers` as c
3on o.customer_id = c.customer_id
4Group By o.customer_id
5HAVING SUM(product_name = 'A') > 0 and SUM(product_name = 'B') > 0 and SUM(product_name = 'C') = 0
6Order By c.customer_id ASC
1[o.id, o.customerId, o.product_name, c.customerId, c.name]
2 1 1 'A' 1 X
3 2 1 'B' 1 X
4 3 2 'A' 2 Y
5 4 2 'B' 2 Y
6 5 2 'C' 2 Y
7
8 Group By c.customerId
9 1 1 'A' 1 X
10 2 1 'B' 1 X
11
12 3 2 'A' 2 Y
13 4 2 'B' 2 Y
14 5 2 'C' 2 Y
15
16 SUM(express condition) ? condition # 对于String是统计条数
每位学生成绩最好的科目
所有有相同科目成绩一样,选择科目id小的
1+---------------+---------+
2| Column Name | Type |
3+---------------+---------+
4| student_id | int |
5| course_id | int |
6| grade | int |
7+---------------+---------+
# 1
1# 查某学生成绩最好的那些科目,因为可能有重复的
2SELECT student_id, MAX(grade) AS grade
3From Enrollments
4Group By student_id
# 2
1# 查某学生最好的那些科目中 courseId最小的
2SELECT student_id, MIN(courseId) AS course_id, grade
3From Enrollments
4# 行 => 最好的那些科目
5Where (student_id, grade) in (
6 SELECT student_id, MAX(grade) AS grade
7 From Enrollments
8 Group By student_id
9)
10Group By student_id
11Order By student_id ASC
连接
Left Join
拓展左边,即使右表某些行不存在(会出现重复行)
=> **Right Join **同理
1SELECT *
2FROM `customers` as c
3LEFT JOIN orders as o
4ON c.id = o.customerId
Inner Join => 只展示左右表均成功对接上的行
没有卖出的商家
写一个解决方案, 报告所有在 2020 年度没有任何卖出的卖家的名字。
返回结果按照 seller_name 升序排列。
1SELECT seller_name
2FROM Seller
3WHERE seller_id not in (
4 SELECT DISTINCT Orders.seller_id
5 FROM Orders
6 WHERE Orders.sale_date like '2020%'
7)
8ORDER By seller_name ASC
排名靠前的旅行者
返回的结果表单,以 travelled_distance 降序排列 ,如果有两个或者更多的用户旅行了相同的距离, 那么再以 name 升序排列 。
1SELECT name, COALESCE(SUM(distance), 0) AS travelled_distance
2From Users Left join Rides
3On Rides.user_id = Users.id
4Group By Rides.user_id
5ORDER BY travelled_distance DESC, name ASC; # 使用别名排序
607. 销售员
编写解决方案,找出没有任何与名为 “RED” 的公司相关的订单的所有销售人员的姓名。
1SELECT name
2FROM SalesPerson
3WHERE sales_id not in (
4 SELECT DISTINCT Orders.sales_id
5 FROM Orders LEFT JOIN Company
6 ON Orders.com_id = Company.com_id
7 WHERE name = 'RED'
8)
计算布尔表达式的值
输入:
Variables 表:
+------+-------+
| name | value |
+------+-------+
| x | 66 |
| y | 77 |
+------+-------+
Expressions 表:
+--------------+----------+---------------+
| left_operand | operator | right_operand |
+--------------+----------+---------------+
| x | > | y |
| x | < | y |
| x | = | y |
| y | > | x |
| y | < | x |
| x | = | x |
+--------------+----------+---------------+
输出:
+--------------+----------+---------------+-------+
| left_operand | operator | right_operand | value |
+--------------+----------+---------------+-------+
| x | > | y | false |
| x | < | y | true |
| x | = | y | false |
| y | > | x | true |
| y | < | x | false |
| x | = | x | true |
+--------------+----------+---------------+-------+
1SELECT e.left_operand, e.operator, e.right_operand,
2CASE e.operator
3 WHEN '>' THEN IF(v1.value>v2.value, 'true', 'false')
4 WHEN '<' THEN IF(v1.value<v2.value, 'true', 'false')
5 ELSE IF(v1.value=v2.value, 'true', 'false')
6END value
7
8FROM Expressions e
9LEFT JOIN Variables v1 ON e.left_operand = v1.name
10LEFT JOIN Variables v2 ON e.right_operand = v2.name
考点:多重连表 e.(…)v1.(…)v2.(…)
条件判断表达式
case [sign]
when exp then result[if(exp, true, false)]
when exp then result
else result
end
查询球队积分
分别查询主队得分和客队得分。再进行汇总统计
IFNULL(SUM(num_points), 0) # IFNULL(Origin, NULL-value)
1SELECT t.team_id, t.team_name, IFNULL(SUM(num_points), 0) as num_points
2FROM Teams AS t
3LEFT JOIN (
4 SELECT host_team AS team_id,
5 CASE
6 WHEN host_goals > guest_goals THEN 3
7 WHEN host_goals = guest_goals THEN 1
8 END AS num_points
9 FROM Matches
10 UNION ALL
11 SELECT guest_team AS team_id,
12 CASE
13 WHEN guest_goals > host_goals THEN 3
14 WHEN host_goals = guest_goals THEN 1
15 END AS num_points
16 FROM Matches
17) AS m ON t.team_id = m.team_id
18Group By t.team_id
19Order BY num_points DESC, t.team_id ASC
# 1. LEFT JOIN 将相关的右表补充至左表 !若1vN则产生重复记录(聚合该记录)
# 2. UNION(ALL) 两张表需字段相同,上下拼接为一张表,ALL则保留重复记录
# 3. case 空条件
when ? then x
…
ELSE y
end
聚合函数
2020最后一次登录
1SELECT MAX(Feild) # <= 只要组内最大的记录
2 Min(Feild) # <= 只要组内最小的记录
3...
4
5Group By
仓库经理
1SELECT Warehouse.name AS warehouse_name,
2SUM(units*Products.Width*Products.Length*Products.Height) AS volume # 聚合组内数据
3FROM Warehouse
4LEFT JOIN Products ON Warehouse.product_id = Products.product_id # 补齐信息
5Group By Warehouse.name # 分组
订单最多的客户
1SELECT customer_number
2FROM Orders
3GROUP BY customer_number
4ORDER BY COUNT(*) DESC # 对组进行排序
5LIMIT 1 # Top位置
6
7
8SELECT o.customer_number
9FROM (
10 SELECT customer_number, COUNT(*) AS count_number
11 FROM Orders
12 GROUP BY customer_number
13) o
14ORDER BY o.count_number DESC
15LIMIT 1
查找每个员工花费的总时间
多次分组 & 聚合
1SELECT `day`, emp_id, SUM(out_time-in_time)
2FROM Employees
3GROUP BY emp_id, event_day
及时食物配送
考点:计算公式
#1 ROUND(X*100, 2) 33.33
#2 SUM(IF(X, 1, 0)) / COUNT(ID)
按列操作
1SELECT ROUND((SUM(IF(order_date = customer_pref_delivery_date, 1, 0)))/COUNT(delivery_id)*100, 2) AS immediate_percentage
2FROM Delivery
苹果和桔子
1SELECT sale_date,
2(SUM(IF(fruit='apples', sold_num, 0)) - SUM(IF(fruit='oranges', sold_num, 0))) AS diff
3FROM Sales
4Group By sale_date
⭐ 分别聚合组内不同条件的记录
两个人的通话记录
考点,多次分组进行聚合统计。
题干中,呼叫与接收不分。
1SELECT from_id AS person1, to_id AS person2, COUNT(*) AS call_count,SUM(duration) AS total_duration
2
3FROM (
4
5 SELECT IF(from_id < to_id, from_id, to_id) AS from_id, IF(from_id < to_id, to_id, from_id) AS to_id, duration
6
7 FROM Calls
8
9) AS c
10
11Group BY from_id, to_id
排序和分组
银行账户概要 II
编写解决方案, 报告余额高于 10000 的所有用户的名字和余额. 账户的余额等于包含该账户的所有交易的总和
1SELECT name, balance
2FROM Users
3LEFT JOIN (
4 SELECT account, SUM(amount) AS balance
5 FROM Transactions
6 Group BY account) AS trans On Users.account = trans.account
7Where balance > 10000
查找重复的电子邮箱
编写解决方案来报告所有重复的电子邮件
1SELECT email AS Email
2FROM Person
3Group By email
4HAVING count(*) > 1
合作过至少三次的演员和导演
编写解决方案找出合作过至少三次的演员和导演的 id 对 (actor_id, director_id)
1SELECT actor_id, director_id
2FROM ActorDirector
3GROUP BY actor_id, director_id
4HAVING COUNT(*) >= 3
消费者下单频率
67月,每个月均消费至少100的用户
1SELECT o.customer_id, name
2FROM () AS o
3LEFT JOIN Customers ON o.customer_id = Customers.customer_id
4
5
6# 其中
7SELECT customer_id, order_date, (quantity*price) AS cost
8FROM Orders
9LEFT JOIN Product ON Orders.product_id = Product.product_id
10WHERE month(order_date) in (6,7)
11Group BY customer_id
12HAVING SUM(IF(month(order_date) = 6, cost, 0)) >= 100 and
13 SUM(IF(month(order_date) = 7, cost, 0)) >= 100
可以放心投资的国家
分步实现:
1️⃣ 将呼叫\接听联合
2️⃣ 将对应人员及其国家准备好
3️⃣ 再次连接,并按国家分组且聚合(HAVING进行条件筛选)
1SELECT name as country
2FROM
3(
4 SELECT caller_id AS call_id, duration FROM Calls
5 UNION ALL
6 SELECT callee_id AS call_id, duration FROM Calls
7) a
8LEFT JOIN
9(
10 SELECT id, Country.name
11 FROM Person
12 LEFT JOIN Country on SUBSTR(phone_number, 1, 3) = country_code
13) b
14ON a.call_id = b.id
15Group BY name
16HAVING AVG(duration) > (SELECT AVG(duration) FROM Calls)
高级查询和连接
HAVING 子句用来对 聚合结果 进行过滤,而 HAVING 子句无法直接使用非聚合列
页面推荐
编写解决方案,向user_id = 1 的用户,推荐其朋友们喜欢的页面。不要推荐该用户已经喜欢的页面。
先find他的所有朋友。 他->朋友 and 朋友 ->
1SELECT DISTINCT page_id as recommended_page
2FROM (SELECT user2_id as user_id
3 FROM Friendship
4 WHERE user1_id = 1
5 UNION
6 SELECT user1_id as user_id
7 FROM Friendship
8 WHERE user2_id = 1) AS fs
9LEFT JOIN Likes ls ON fs.user_id = ls.user_id
10WHERE page_id not in (
11 SELECT page_id
12 FROM Likes
13 WHERE user_id = 1
14)
15ORDER BY recommended_page ASC
树节点
CASE … END 按列来,每次处理列的一个元素
1SELECT id AS `id`,
2CASE
3 WHEN id = 1 THEN "Root"
4 WHEN id in (SELECT atree.p_id FROM tree atree) THEN "Inner"
5 ELSE "Leaf"
6END AS type
7FROM Tree
游戏玩法分析 III
编写一个解决方案,同时报告每组玩家和日期,以及玩家到 目前为止 玩了多少游戏。也就是说,玩家在该日期之前所玩的游戏总数。详细情况请查看示例。
利用笛卡尔积, 自己跟自己所有的记录进行连接。暴力遍历
1SELECT a1.player_id, a1.event_date, SUM(a2.games_played) AS games_played_so_far
2FROM Activity a1, Activity a2 # 笛卡儿积,o(n) x o(n) = o(n^2) 条纪录
3WHERE a1.player_id = a2.player_id and a1.event_date >= a2.event_date # 只要自己和自己进行连接的记录
4GROUP BY a1.player_id, a1.event_date
大满贯数量
编写解决方案,找出每一个球员赢得大满贯比赛的次数。结果不包含没有赢得比赛的球员的ID 。
思路: 行 -> 列 再聚合
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 |
+-----------+-------------+-------------------+
1SELECT res.player_id, ps.player_name, res.grand_slams_count
2FROM (
3 SELECT player_id, COUNT(*) AS grand_slams_count
4 FROM (
5 SELECT Wimbledon player_id
6 FROM Championships
7 UNION ALL
8 SELECT Fr_open player_id
9 FROM Championships
10 UNION ALL
11 SELECT US_open player_id
12 FROM Championships
13 UNION ALL
14 SELECT Au_open player_id
15 FROM Championships
16 ) AS rec
17 GROUP BY rec.player_id
18) AS res
19LEFT JOIN Players AS ps ON res.player_id = ps.player_id
应该被禁止的 Leetflex 账户
编写解决方案,查找那些应该被禁止的Leetflex帐户编号 account_id 。 如果某个帐户在某一时刻从两个不同的网络地址登录了,则这个帐户应该被禁止。
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 |
+------------+------------+---------------------+---------------------+
1AND ((a.login between b.login and b.logout) OR (a.logout between b.login and b.logout))
GROUP BY 分组
HAVING 作用于组,挑选指定的组
子查询
各部门最高收入的员工 (可能有多个)
1SELECT d.name AS Department, e1.name AS Employee, e1.salary AS Salary
2FROM Employee e1
3LEFT JOIN Department d ON e1.departmentId = d.id
4WHERE e1.salary = (
5 SELECT MAX(salary)
6 FROM Employee e2
7 GROUP BY e2.departmentId
8 HAVING e2.departmentId = e1.departmentId
9)
效率不高!!!
优化:
1SELECT d.name AS Department, e1.name AS Employee, e1.salary AS Salary
2FROM Employee e1
3LEFT JOIN Department d ON e1.departmentId = d.id
4WHERE (e1.departmentId,e1.salary) in (
5 SELECT e2.departmentId, MAX(salary)
6 FROM Employee e2
7 GROUP BY e2.departmentId
8)
生成临时表(避免子查询 重复的执行)
1WITH MaxSalaries AS (
2 SELECT departmentId, MAX(salary) AS max_salary
3 FROM Employee
4 GROUP BY departmentId
5)
每件商品的最新订单
可能有多个
1With LatestDate AS (
2 SELECT product_id, MAX(order_date) AS order_date
3 FROM Orders
4 GROUP BY product_id
5)
6
7
8SELECT p.product_name, o.product_id, o.order_id, o.order_date
9FROM Orders AS o
10LEFT JOIN LatestDate AS ld ON o.product_id = ld.product_id
11LEFT JOIN Products AS p ON o.product_id = p.product_id
12WHERE o.order_date = ld.order_date
13ORDER BY p.product_name ASC, o.product_id ASC, o.order_id ASC
最近的三笔订单
学习, 可分组打index标记,标记按照ORDER顺序
1ROW_NUMBER() OVER (
2 PARTITION BY ?
3 ORDER BY ?
4)
1WITH ORDER_INFO AS (
2 SELECT c.name, c.customer_id, o.order_id, o.order_date,
3 ROW_NUMBER() OVER (
4 PARTITION BY o.customer_id
5 ORDER BY o.order_date DESC
6 ) AS row_num
7 FROM Orders AS o
8 LEFT JOIN Customers AS c ON o.customer_id = c.customer_id
9)
10
11SELECT name AS customer_name, customer_id, order_id, order_date
12FROM ORDER_INFO AS o
13WHERE o.row_num <= 3
14ORDER BY customer_name ASC, customer_id ASC, order_date DESC
先生成临时表,避免重复生成子查询
每天的最大金额
先筛选出每天的最大金额,再执行后续的判断
1WITH MAX_AMOUNT AS (
2 SELECT DATE(`day`) AS `day`, MAX(amount) max_amount
3 FROM Transactions AS t
4 GROUP BY DATE(`day`)
5)
6
7
8SELECT transaction_id
9FROM Transactions AS t
10LEFT JOIN MAX_AMOUNT AS ma ON DATE(t.day) = ma.day
11WHERE (DATE(t.day), t.amount) = (ma.day, ma.max_amount)
12ORDER BY transaction_id ASC
直接给每天的 订单,按照金额, 打index标记
❗ RANK 相同值会获得相同的排名
1RANK() OVER (
2)
而 ROW_NUMBER,idx严格递增
1WITH Temp AS (
2 SELECT transaction_id, `day`, amount,
3 rank() OVER (
4 PARTITION BY DATE(`day`)
5 ORDER BY amount DESC
6 ) AS idx
7 FROM Transactions AS t
8)
9
10SELECT transaction_id
11FROM Temp as t
12WHERE idx = 1
13ORDER BY transaction_id ASC
窗口函数和公共表表达式
项目员工 III
找出每个项目 经验最丰富的员工(可能有多个)
直接1. 分项目 2. 项目内按经验程度进行RANK 3. 再筛选
1WITH Temp AS (
2 SELECT p.project_id, p.employee_id,
3 RANK() OVER (
4 PARTITION BY p.project_id
5 ORDER BY e.experience_years DESC
6 ) AS idx
7 FROM Project AS p
8 LEFT JOIN Employee as e ON p.employee_id = e.employee_id
9)
10
11
12SELECT project_id, employee_id
13FROM Temp
14WHERE idx = 1
每位顾客最经常订购的商品
主SQL GROUP BY 之后,与 RANK() 的操作
1SELECT
2 customer_id,
3 product_id,
4 COUNT(*) AS order_count,
5 RANK() OVER (ORDER BY COUNT(*) DESC) AS RK
6FROM Orders
7GROUP BY customer_id, product_id;
结果:
添加 PARTITION BY customer_id 进行隔离
1SELECT
2 customer_id,
3 product_id,
4 COUNT(*) AS order_count,
5 RANK() OVER (PARTITION BY customer_id ORDER BY COUNT(*) DESC) AS RK
6FROM Orders
7GROUP BY customer_id, product_id;
结果:
=> 结论。 1. 先执行主SQL的GROUP BY,进行分区,再RANK(), RANK()按照 ORDER BY(必须聚合为单行)进行排序, 利用PARTITION进行排序隔离。
答案
1WITH Temp AS (
2 SELECT
3 customer_id,
4 product_id,
5 COUNT(*) AS order_count,
6 RANK() OVER (PARTITION BY customer_id ORDER BY COUNT(*) DESC) AS RK
7 FROM Orders
8 GROUP BY customer_id, product_id
9)
10
11SELECT t.customer_id, t.product_id, p.product_name
12FROM Temp AS t
13LEFT JOIN Products AS p ON t.product_id = p.product_id
14WHERE RK = 1 # 最高的 NO.1
访问日期之间最大的空档期
LEAD(column, offset, defualt) OVER (PARTITION BY … ORDER BY …) 找后面的行。其中LEAD表示引领。
LAG(…) 找前面的行, 滞后
1SELECT user_id, MAX(DATEDIFF(after_day, visit_date)) AS biggest_window
2FROM (
3 SELECT user_id, visit_date,
4 LEAD(visit_date, 1, '2021-1-1') OVER (PARTITION BY user_id ORDER BY visit_date ASC) AS after_day
5 FROM UserVisits AS uv
6) AS t
7GROUP BY user_id
考点:行之间的差值
CTE Common Table Expression
向公司 CEO 汇报工作的所有人
查询树状结构节点 列转行
依次暴力枚举
1SELECT employee_id
2FROM (
3 SELECT employee_id
4 FROM Employees
5 WHERE manager_id = 1 and employee_id != 1
6 UNION
7 SELECT employee_id
8 FROM Employees
9 WHERE manager_id in (
10 SELECT employee_id
11 FROM (SELECT employee_id
12 FROM Employees
13 WHERE manager_id = 1 and employee_id != 1) AS e1
14 )
15 UNION
16 SELECT employee_id
17 FROM Employees
18 WHERE manager_id in (
19 SELECT employee_id
20 FROM (SELECT employee_id
21 FROM Employees
22 WHERE manager_id in (
23 SELECT employee_id
24 FROM (SELECT employee_id
25 FROM Employees
26 WHERE manager_id = 1 and employee_id != 1) AS e2
27 )) e3
28 )
29) AS e
太低效了!!! SB操作,疯狂连续查询
优化
1SELECT employee_id
2FROM (
3 SELECT employee_id
4 FROM Employees
5 WHERE manager_id = 1 and employee_id != 1 # ✔️
6 UNION
7
8 SELECT employee_id
9 FROM Employees
10 WHERE manager_id in (
11 SELECT employee_id
12 FROM Employees
13 WHERE manager_id = 1 and employee_id != 1
14 )
15 UNION
16
17 SELECT employee_id
18 FROM Employees
19 WHERE manager_id in (
20 SELECT employee_id
21 FROM Employees
22 WHERE manager_id in (
23 SELECT employee_id
24 FROM Employees
25 WHERE manager_id = 1 and employee_id != 1
26 )
27 )
28) AS e
利用连接来计算
1SELECT DISTINCT e4.employee_id
2FROM Employees e1
3LEFT JOIN Employees e2 ON e1.employee_id = e2.manager_id
4LEFT JOIN Employees e3 ON e2.employee_id = e3.manager_id
5LEFT JOIN Employees e4 ON e3.employee_id = e4.manager_id
6WHERE e1.employee_id = 1 and e4.employee_id != 1
11 Boss => {
2 1 Boss => {
3 1 Boss => {
4 1 Boss
5 2 Bob
6 77 Robert
7 }
8 2 Bob => 4 Daniel
9 77 Robert => null
10 }
11 2 Bob => 4 Daniel => null
12 77 Robert => null => null
13}
寻找连续区间的开始和结束位置
思路:
1data: 1,2,3,7,8,10
2idx : 1,2,3,4,5, 6
3diff: 0,0,0,3,3, 4 <= GROUP BY diff => MIN(idx) AS Start_ID, MAX(idx) AS End_ID
1WITH Temp AS (
2 SELECT log_id,
3 ROW_NUMBER() OVER (ORDER BY log_id ASC) AS idx
4 FROM Logs
5)
6
7SELECT MIN(log_id) AS start_id, MAX(log_id) AS end_id
8FROM (
9 SELECT log_id, (log_id-idx ) AS diff
10 FROM Temp
11) AS t
12GROUP BY diff
查找处于成绩中游的学生
参加的考试,没有一科是最高分或者最低分。科科中等
逻辑: 1. 判断每一科,再统计所有科目
1WITH MAXMIN AS (
2 SELECT exam_id, MIN(score) min_score, MAX(score) max_score
3 FROM Exam
4 GROUP BY exam_id
5)
6
7
8SELECT s.student_id, s.student_name
9FROM (
10 SELECT e.exam_id, e.student_id,
11 CASE
12 WHEN score != min_score and score != max_score THEN 1
13 ELSE 0
14 END AS is_medium
15 FROM Exam AS e
16 LEFT JOIN MAXMIN m ON e.exam_id = m.exam_id
17) AS t
18LEFT JOIN Student AS s ON t.student_id = s.student_id
19GROUP BY t.student_id
20HAVING SUM(t.is_medium) = COUNT(t.is_medium)
21ORDER BY student_id ASC
反过来: 将尖子生和垫底生排除在外即可
寻找没有被执行的任务对
1with recursive all_subtask(task_id, subtask_id) as (
2 SELECT task_id, subtasks_count
3 FROM Tasks
4 UNION ALL
5
6 SELECT task_id, subtask_id-1
7 FROM all_subtask
8 where subtask_id-1 > 0
9)
10
11
12SELECT task_id, subtask_id
13From all_subtask
14WHERE (task_id, subtask_id) not in (SELECT task_id, subtask_id FROM Executed)
1with recursive TableName(param1, param2) AS (
2 SELECT param1, param2 // 基础结果
3 FROM BaseTable
4 UNION ALL
5 // 下面式子会被重复递归
6 SELECT param1, param2-1 // 新的结果
7 FROM TableName // 上一轮的结果
8 where param2-1 > 0 // 递归终止条件
9)