Leetcode sql题目记录

文章目录

    • Leetcode sql题目记录
      • 570. 至少有5名直接下属的经理
      • 1934. 确认率
      • 1193. 每月交易I
      • 1174. 即时食物配送II
      • 176. 第二高的薪水
        • (1) 子查询为空但外层用了聚合函数
        • (2)子查询为空而外层没有聚合函数
      • 550. 游戏玩法分析IV
      • 1045. 买下所有产品的客户
      • 180. 连续出现的数字
      • 1164. 指定日期的产品价格
        • (1)非相关子查询 + 等值比较
        • (2)相关子查询
        • (3)窗口函数 + 条件筛选
        • (4)ORDER BY + LIMIT
        • 对比总结
      • 1204.最后一个能进入巴士的人
        • (1)子查询+等值过滤
        • (2)ORDER BY+LIMIT
      • 1907. 按分类统计薪水
      • 626. 换座位
        • (1)嵌套查询
        • (2)CASE WHEN
          • a. 简单 CASE
          • b. 搜索 CASE (最常用)
          • c. 作为一个字段输出
          • d. 在聚合函数里做条件统计
          • e. 排序(ORDER BY)

本博客仅记录高频 SQL 50 题(基础版)的中等难度题目 苯人的解答与学习过程,后续不定期更新

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

表: Employee

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

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

任意顺序 返回结果表。

查询结果格式如下所示。

示例 1:

输入: 
Employee 表:
+-----+-------+------------+-----------+
| id  | name  | department | managerId |
+-----+-------+------------+-----------+
| 101 | John  | A          | Null      |
| 102 | Dan   | A          | 101       |
| 103 | James | A          | 101       |
| 104 | Amy   | A          | 101       |
| 105 | Anne  | A          | 101       |
| 106 | Ron   | B          | 101       |
+-----+-------+------------+-----------+
输出: 
+------+
| name |
+------+
| John |
+------+

解答:

select a.name from Employee a join Employee b on a.id = b.managerId group by a.id having count(*) >= 5;

没有 GROUP BY
HAVING 是对分组后的结果过滤的。你没分组时,MySQL把整张结果集当成一个大组COUNT(a.id) 统计的是所有经理–下属配对的总行数,不是“每个经理的下属数”。因此当测试数据里只有一个经理且刚好有 5 个下属时看起来“正确”,但只要有两个经理,合计行数 ≥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查询来查找每个用户的 确认率 。

以 任意顺序 返回结果表。

查询结果格式如下所示。

示例1:

输入:
Signups 表:
+---------+---------------------+
| user_id | time_stamp          |
+---------+---------------------+
| 3       | 2020-03-21 10:16:13 |
| 7       | 2020-01-04 13:57:59 |
| 2       | 2020-07-29 23:09:44 |
| 6       | 2020-12-09 10:39:37 |
+---------+---------------------+
Confirmations 表:
+---------+---------------------+-----------+
| user_id | time_stamp          | action    |
+---------+---------------------+-----------+
| 3       | 2021-01-06 03:30:46 | timeout   |
| 3       | 2021-07-14 14:00:00 | timeout   |
| 7       | 2021-06-12 11:57:29 | confirmed |
| 7       | 2021-06-13 12:58:28 | confirmed |
| 7       | 2021-06-14 13:59:27 | confirmed |
| 2       | 2021-01-22 00:00:00 | confirmed |
| 2       | 2021-02-28 23:59:59 | timeout   |
+---------+---------------------+-----------+
输出: 
+---------+-------------------+
| user_id | confirmation_rate |
+---------+-------------------+
| 6       | 0.00              |
| 3       | 0.00              |
| 7       | 1.00              |
| 2       | 0.50              |
+---------+-------------------+
解释:
用户 6 没有请求任何确认消息。确认率为 0。
用户 3 进行了 2 次请求,都超时了。确认率为 0。
用户 7 提出了 3 个请求,所有请求都得到了确认。确认率为 1。
用户 2 做了 2 个请求,其中一个被确认,另一个超时。确认率为 1 / 2 = 0.5。

解答:

WITH base AS (SELECT user_id,COUNT(*) AS total,SUM(CASE WHEN action = 'confirmed' THEN 1 ELSE 0 END) AS confirmedFROM ConfirmationsGROUP BY user_id
)
SELECT s.user_id,ROUND(IFNULL(b.confirmed / b.total, 0), 2) AS confirmation_rate
FROM Signups s
LEFT JOIN base bON s.user_id = b.user_id;

1193. 每月交易I

表:Transactions

+---------------+---------+
| Column Name   | Type    |
+---------------+---------+
| id            | int     |
| country       | varchar |
| state         | enum    |
| amount        | int     |
| trans_date    | date    |
+---------------+---------+
id 是这个表的主键。
该表包含有关传入事务的信息。
state 列类型为 ["approved", "declined"] 之一。

编写一个 sql 查询来查找每个月和每个国家/地区的事务数及其总金额、已批准的事务数及其总金额。

任意顺序 返回结果表。

查询结果格式如下所示。

示例 1:

输入:
Transactions table:
+------+---------+----------+--------+------------+
| id   | country | state    | amount | trans_date |
+------+---------+----------+--------+------------+
| 121  | US      | approved | 1000   | 2018-12-18 |
| 122  | US      | declined | 2000   | 2018-12-19 |
| 123  | US      | approved | 2000   | 2019-01-01 |
| 124  | DE      | approved | 2000   | 2019-01-07 |
+------+---------+----------+--------+------------+
输出:
+----------+---------+-------------+----------------+--------------------+-----------------------+
| month    | country | trans_count | approved_count | trans_total_amount | approved_total_amount |
+----------+---------+-------------+----------------+--------------------+-----------------------+
| 2018-12  | US      | 2           | 1              | 3000               | 1000                  |
| 2019-01  | US      | 1           | 1              | 2000               | 2000                  |
| 2019-01  | DE      | 1           | 1              | 2000               | 2000                  |
+----------+---------+-------------+----------------+--------------------+-----------------------+

解答:

多个 CTE 用 WITH a AS (...), b AS (...)

month、country 分组;approved 相关用 CASE WHEN 计数/求和。

取月份用 DATE_FORMAT(trans_date, '%Y-%m') 更稳妥。

WITH base AS (SELECTDATE_FORMAT(trans_date, '%Y-%m') AS month,country,state,amountFROM Transactions
),
seq AS (SELECTmonth,country,COUNT(*) AS trans_count,SUM(CASE WHEN state = 'approved' THEN 1 ELSE 0 END) AS approved_count,SUM(amount) AS trans_total_amount,SUM(CASE WHEN state = 'approved' THEN amount ELSE 0 END) AS approved_total_amountFROM baseGROUP BY month, country
)
SELECT *
FROM seq;

1174. 即时食物配送II

配送表: Delivery

+-----------------------------+---------+
| Column Name                 | Type    |
+-----------------------------+---------+
| delivery_id                 | int     |
| customer_id                 | int     |
| order_date                  | date    |
| customer_pref_delivery_date | date    |
+-----------------------------+---------+
delivery_id 是该表中具有唯一值的列。
该表保存着顾客的食物配送信息,顾客在某个日期下了订单,并指定了一个期望的配送日期(和下单日期相同或者在那之后)。

如果顾客期望的配送日期和下单日期相同,则该订单称为 「即时订单」,否则称为「计划订单」。

首次订单」是顾客最早创建的订单。我们保证一个顾客只会有一个「首次订单」。

编写解决方案以获取即时订单在所有用户的首次订单中的比例。保留两位小数。

结果示例如下所示:

示例 1:

输入:
Delivery 表:
+-------------+-------------+------------+-----------------------------+
| delivery_id | customer_id | order_date | customer_pref_delivery_date |
+-------------+-------------+------------+-----------------------------+
| 1           | 1           | 2019-08-01 | 2019-08-02                  |
| 2           | 2           | 2019-08-02 | 2019-08-02                  |
| 3           | 1           | 2019-08-11 | 2019-08-12                  |
| 4           | 3           | 2019-08-24 | 2019-08-24                  |
| 5           | 3           | 2019-08-21 | 2019-08-22                  |
| 6           | 2           | 2019-08-11 | 2019-08-13                  |
| 7           | 4           | 2019-08-09 | 2019-08-09                  |
+-------------+-------------+------------+-----------------------------+
输出:
+----------------------+
| immediate_percentage |
+----------------------+
| 50.00                |
+----------------------+
解释:
1 号顾客的 1 号订单是首次订单,并且是计划订单。
2 号顾客的 2 号订单是首次订单,并且是即时订单。
3 号顾客的 5 号订单是首次订单,并且是计划订单。
4 号顾客的 7 号订单是首次订单,并且是即时订单。
因此,一半顾客的首次订单是即时的。

解答:

with base as (
select *, row_number() over(partition by customer_id order by order_date) as rn 
from Delivery),
seq as (select round((sum(case when customer_pref_delivery_date = order_date then 1 else 0 end) / count(*)) * 100, 2) as immediate_percentage from base where rn = 1
)
select * from seq;

176. 第二高的薪水

Employee 表:

+-------------+------+
| Column Name | Type |
+-------------+------+
| id          | int  |
| salary      | int  |
+-------------+------+
id 是这个表的主键。
表的每一行包含员工的工资信息。

查询并返回 Employee 表中第二高的 不同 薪水 。如果不存在第二高的薪水,查询应该返回 null(Pandas 则返回 None)

查询结果如下例所示。

示例 1:

输入:
Employee 表:
+----+--------+
| id | salary |
+----+--------+
| 1  | 100    |
| 2  | 200    |
| 3  | 300    |
+----+--------+
输出:
+---------------------+
| SecondHighestSalary |
+---------------------+
| 200                 |
+---------------------+

示例 2:

输入:
Employee 表:
+----+--------+
| id | salary |
+----+--------+
| 1  | 100    |
+----+--------+
输出:
+---------------------+
| SecondHighestSalary |
+---------------------+
| null                |
+---------------------+

解答

SELECT MAX(salary) AS SecondHighestSalary
FROM (SELECT DISTINCT salary,DENSE_RANK() OVER (ORDER BY salary DESC) AS rkFROM Employee
) t
WHERE rk = 2;
(1) 子查询为空但外层用了聚合函数

SQL 的定义是:聚合函数对空输入时,返回 NULL
例子:

SELECT MAX(salary) FROM (SELECT 1 AS salary WHERE 1=0) t;

(SELECT 1 WHERE 1=0) 为空表 → MAX 没有任何值可比较 → 返回 NULL

所以这就是为什么“第二高薪水不存在”时 MAX 可以帮我们自动返回 NULL


(2)子查询为空而外层没有聚合函数

如果你直接:

SELECT salary 
FROM (SELECT salary WHERE 1=0) t;

那结果就是 0 行(即直接返回空结果集,不会自动给你一行 NULL)。


550. 游戏玩法分析IV

Table: Activity

+--------------+---------+
| Column Name  | Type    |
+--------------+---------+
| player_id    | int     |
| device_id    | int     |
| event_date   | date    |
| games_played | int     |
+--------------+---------+
(player_id,event_date)是此表的主键(具有唯一值的列的组合)。
这张表显示了某些游戏的玩家的活动情况。
每一行是一个玩家的记录,他在某一天使用某个设备注销之前登录并玩了很多游戏(可能是 0)。

编写解决方案,报告在首次登录的第二天再次登录的玩家的 比率四舍五入到小数点后两位。换句话说,你需要计算从首次登录后的第二天登录的玩家数量,并将其除以总玩家数。

结果格式如下所示:

示例 1:

输入:
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            |
+-----------+-----------+------------+--------------+
输出:
+-----------+
| fraction  |
+-----------+
| 0.33      |
+-----------+
解释:
只有 ID 为 1 的玩家在第一天登录后才重新登录,所以答案是 1/3 = 0.33

解答:

# Write your MySQL query statement below
with base as(select *,min(event_date) over(partition by player_id)as first from Activity
),
seq as(select player_id, sum(case when datediff(event_date, first) = 1 then 1 else 0 end) as rn from basegroup by player_id
)
select round(IFNULL((sum(rn) / count(distinct player_id)), 0), 2) as fraction from seq;

注意:

  1. 在使用with base as(), seq as() select from seq时,要记得每个嵌套内部的select很重要,前一个select需要包含后一个select的内容。
  2. 使用聚合函数min,max,count后结果会被压缩,如果后续要同行对最大、最小进行比较,要使用窗口函数形式的max,min…

1045. 买下所有产品的客户

Customer 表:

+-------------+---------+
| Column Name | Type    |
+-------------+---------+
| customer_id | int     |
| product_key | int     |
+-------------+---------+
该表可能包含重复的行。
customer_id 不为 NULL。
product_key 是 Product 表的外键(reference 列)。

Product 表:

+-------------+---------+
| Column Name | Type    |
+-------------+---------+
| product_key | int     |
+-------------+---------+
product_key 是这张表的主键(具有唯一值的列)。

编写解决方案,报告 Customer 表中购买了 Product 表中所有产品的客户的 id。

返回结果表 无顺序要求

返回结果格式如下所示。

示例 1:

输入:
Customer 表:
+-------------+-------------+
| customer_id | product_key |
+-------------+-------------+
| 1           | 5           |
| 2           | 6           |
| 3           | 5           |
| 3           | 6           |
| 1           | 6           |
+-------------+-------------+
Product 表:
+-------------+
| product_key |
+-------------+
| 5           |
| 6           |
+-------------+
输出:
+-------------+
| customer_id |
+-------------+
| 1           |
| 3           |
+-------------+
解释:
购买了所有产品(5 和 6)的客户的 id 是 1 和 3 。

解答:

  1. WHERE DISTINCT 是非法语法DISTINCT 只能放在 SELECTCOUNT(DISTINCT ...) 里面,不能直接放在 WHERE
  2. 题目要求的是“买了所有产品的顾客”,所以应该比较顾客买到的 去重后产品数Product 表里的产品总数
SELECT customer_id
FROM Customer
GROUP BY customer_id
HAVING COUNT(DISTINCT product_key) = (SELECT COUNT(*) FROM Product
);

解释一下:

  • GROUP BY customer_id:按顾客分组。
  • COUNT(DISTINCT product_key):统计该顾客买了多少种不同的产品。
  • 子查询 (SELECT COUNT(*) FROM Product):统计总共有多少种产品。
  • HAVING ... = ...:筛选出买全所有产品的顾客。

180. 连续出现的数字

表:Logs

+-------------+---------+
| Column Name | Type    |
+-------------+---------+
| id          | int     |
| num         | varchar |
+-------------+---------+
在 SQL 中,id 是该表的主键。
id 是一个自增列。

找出所有至少连续出现三次的数字。

返回的结果表中的数据可以按 任意顺序 排列。

结果格式如下面的例子所示:

示例 1:

输入:
Logs 表:
+----+-----+
| id | num |
+----+-----+
| 1  | 1   |
| 2  | 1   |
| 3  | 1   |
| 4  | 2   |
| 5  | 1   |
| 6  | 2   |
| 7  | 2   |
+----+-----+
输出:
Result 表:
+-----------------+
| ConsecutiveNums |
+-----------------+
| 1               |
+-----------------+
解释:1 是唯一连续出现至少三次的数字。

解答:

with base as(select *, row_number() over(partition by num order by id) as rn from Logs
),
seq as(select *, id - rn as diff from base 
),
rpq as (select num, count(*) as ct from seq group by num, diff having count(*) >= 3
)
select distinct num as ConsecutiveNums from rpq;

有时候不要忘记distinct


1164. 指定日期的产品价格

产品数据表: Products

+---------------+---------+
| Column Name   | Type    |
+---------------+---------+
| product_id    | int     |
| new_price     | int     |
| change_date   | date    |
+---------------+---------+
(product_id, change_date) 是此表的主键(具有唯一值的列组合)。
这张表的每一行分别记录了 某产品 在某个日期 更改后 的新价格。

一开始,所有产品价格都为 10。

编写一个解决方案,找出在 2019-08-16 所有产品的价格。

任意顺序 返回结果表。

结果格式如下例所示。

示例 1:

输入:
Products 表:
+------------+-----------+-------------+
| 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  |
+------------+-----------+-------------+
输出:
+------------+-------+
| product_id | price |
+------------+-------+
| 2          | 50    |
| 1          | 35    |
| 3          | 10    |
+------------+-------+

解答:

with base as(select *, row_number()over (partition by product_id order by change_date DESC) as rn from Products where change_date <= '2019-08-16'
),
seq as (select product_id, new_price as price from base where rn = 1
)
select product_id, price from seq union all select distinct product_id, 10 as price from (select product_id, min(change_date) as mi from Products group by product_id
)t  where mi > '2019-08-16';

归纳:
想要得到某一列的最大最小值,并用其与某个数进行比较,需要先max、min(窗口或者聚合函数),然后再等值查询,或者rownumber配合ASC、DESC,然后再后续查询中使用rn=1,或者直接使用order by+limit

(1)非相关子查询 + 等值比较

使用场景全局只有一个最值(整个表的最大值/最小值),不依赖分组。

  • 特点:子查询返回单行,可以直接用 = 比较。
  • 示例:找出工资最高的员工
select *
from Employee
where salary = (select max(salary) from Employee);

(2)相关子查询

使用场景分组后的最值(每个客户/部门的最小/最大日期),外层表的条件依赖子查询。

  • 特点:子查询里需要引用外层的列,每行执行一次,保证返回单行。
  • 示例:找每个客户的首单
select *
from Delivery d1
where order_date = (select min(order_date)from Delivery d2where d2.customer_id = d1.customer_id
);

这里子查询里的 d2.customer_id = d1.customer_id 绑定了外层查询的 d1.customer_id

每次外层取一行,子查询就只计算该客户的最小订单日期。

也可以写成这种形式:

select *
from (select customer_id, min(order_date)from Delivery group by customer_id
)t ;

(3)窗口函数 + 条件筛选

使用场景:数据库支持窗口函数(MySQL 8+ / PostgreSQL / Oracle / SQL Server),需要按组取前几名/最值。

也可以使用max、min的窗口函数形式来获取每个组别的最值

  • 特点:写法简洁,可同时保留分组内排序信息。
  • 示例:找每个客户的首单
with t as (select *,row_number() over(partition by customer_id order by order_date) as rnfrom Delivery
)
select *
from t
where rn = 1;
  • 如果要处理并列情况,可以用 rank()dense_rank()

(4)ORDER BY + LIMIT

使用场景只需要全表范围内的最值,且只取前 N 条(不分组)。

  • 特点:简单高效,但无法直接应对「每组最值」问题。
  • 示例:找工资最高的员工(Top 1)
select *
from Employee
order by salary desc
limit 1;
  • 如果需要每组最值,就不适合,只能配合窗口函数或子查询。

对比总结
方法适用场景优点局限
非相关子查询全表唯一最值简单只能处理单个全局最值
相关子查询每组最值(需要依赖外层条件)通用,不要求窗口函数子查询多次执行,性能较差
窗口函数每组最值/前 N 个高效简洁,现代 SQL 推荐需要数据库支持窗口函数
ORDER BY + LIMIT全表前 N 个简洁高效不能分组,只能处理全局最值

👉 快速记忆:

  • 全局最值 → 非相关子查询 或 order by + limit
  • 分组最值 → 相关子查询 或 窗口函数
  • 要前 N 名/并列情况 → 窗口函数最佳

1204.最后一个能进入巴士的人

表: Queue

+-------------+---------+
| Column Name | Type    |
+-------------+---------+
| person_id   | int     |
| person_name | varchar |
| weight      | int     |
| turn        | int     |
+-------------+---------+
person_id 是这个表具有唯一值的列。
该表展示了所有候车乘客的信息。
表中 person_id 和 turn 列将包含从 1 到 n 的所有数字,其中 n 是表中的行数。
turn 决定了候车乘客上巴士的顺序,其中 turn=1 表示第一个上巴士,turn=n 表示最后一个上巴士。
weight 表示候车乘客的体重,以千克为单位。

有一队乘客在等着上巴士。然而,巴士有1000 千克 的重量限制,所以其中一部分乘客可能无法上巴士。

编写解决方案找出 最后一个 上巴士且不超过重量限制的乘客,并报告 person_name 。题目测试用例确保顺位第一的人可以上巴士且不会超重。

返回结果格式如下所示。

示例 1:

输入:
Queue 表
+-----------+-------------+--------+------+
| person_id | person_name | weight | turn |
+-----------+-------------+--------+------+
| 5         | Alice       | 250    | 1    |
| 4         | Bob         | 175    | 5    |
| 3         | Alex        | 350    | 2    |
| 6         | John Cena   | 400    | 3    |
| 1         | Winston     | 500    | 6    |
| 2         | Marie       | 200    | 4    |
+-----------+-------------+--------+------+
输出:
+-------------+
| person_name |
+-------------+
| John Cena   |
+-------------+
解释:
为了简化,Queue 表按 turn 列由小到大排序。
+------+----+-----------+--------+--------------+
| Turn | ID | Name      | Weight | Total Weight |
+------+----+-----------+--------+--------------+
| 1    | 5  | Alice     | 250    | 250          |
| 2    | 3  | Alex      | 350    | 600          |
| 3    | 6  | John Cena | 400    | 1000         | (最后一个上巴士)
| 4    | 2  | Marie     | 200    | 1200         | (无法上巴士)
| 5    | 4  | Bob       | 175    | ___          |
| 6    | 1  | Winston   | 500    | ___          |
+------+----+-----------+--------+--------------+

解答:

PS:SQL 聚合函数(如 MAX())和普通列之间没有自动的“行对齐”关系。

不能直接写成!:

select person_name, max(total_weight) from (select * , sum(weight)over (order by turn) as total_weight from Queue
)t where total_weight <= 1000;-- 结果只会返回
| person_id | person_name | weight | turn |
| --------- | ----------- | ------ | ---- |
| 5         | Alice       | 250    | 1    |
| 4         | Bob         | 175    | 5    |
| 3         | Alex        | 350    | 2    |
| 6         | John Cena   | 400    | 3    |
| 1         | Winston     | 500    | 6    |
| 2         | Marie       | 200    | 4    || person_name | max(total_weight) |
| ----------- | ----------------- |
| Alice       | 1000              |-- 而不是正确输出
| person_name |
| ----------- |
| John Cena   |
(1)子查询+等值过滤
# Write your MySQL query statement below
with base as(select * , sum(weight)over (order by turn) as total_weight from Queue
)
select person_name from base where total_weight = (select max(total_weight) as mx from base where total_weight <= 1000
);

(2)ORDER BY+LIMIT
# Write your MySQL query statement below
select person_name from (select * , sum(weight)over (order by turn) as total_weight from Queue
)t where total_weight <= 1000 order by total_weight DESC limit 1;

1907. 按分类统计薪水

表: Accounts

+-------------+------+
| 列名        | 类型  |
+-------------+------+
| account_id  | int  |
| income      | int  |
+-------------+------+
在 SQL 中,account_id 是这个表的主键。
每一行都包含一个银行帐户的月收入的信息。

查询每个工资类别的银行账户数量。 工资类别如下:

  • "Low Salary":所有工资 严格低于 20000 美元。
  • "Average Salary"包含 范围内的所有工资 [$20000, $50000]
  • "High Salary":所有工资 严格大于 50000 美元。

结果表 必须 包含所有三个类别。 如果某个类别中没有帐户,则报告 0

任意顺序 返回结果表。

查询结果格式如下示例。

示例 1:

输入:
Accounts 表:
+------------+--------+
| account_id | income |
+------------+--------+
| 3          | 108939 |
| 2          | 12747  |
| 8          | 87709  |
| 6          | 91796  |
+------------+--------+
输出:
+----------------+----------------+
| category       | accounts_count |
+----------------+----------------+
| Low Salary     | 1              |
| Average Salary | 0              |
| High Salary    | 3              |
+----------------+----------------+
解释:
低薪: 有一个账户 2.
中等薪水: 没有.
高薪: 有三个账户,他们是 3, 6和 8.

解答:

select 'Low Salary' as category, sum(case when income < 20000 then 1 else 0 end) as accounts_count
from Accounts
Union all
select 'Average Salary' as category, sum(case when income >= 20000 and income <= 50000 then 1 else 0 end) as accounts_count
from Accounts
Union all
select 'High Salary' as category, sum(case when income > 50000 then 1 else 0 end) as accounts_count
from Accounts;

626. 换座位

表: Seat

+-------------+---------+
| Column Name | Type    |
+-------------+---------+
| id          | int     |
| student     | varchar |
+-------------+---------+
id 是该表的主键(唯一值)列。
该表的每一行都表示学生的姓名和 ID。
ID 序列始终从 1 开始并连续增加。

编写解决方案来交换每两个连续的学生的座位号。如果学生的数量是奇数,则最后一个学生的id不交换。

id 升序 返回结果表。

查询结果格式如下所示。

示例 1:

输入: 
Seat 表:
+----+---------+
| id | student |
+----+---------+
| 1  | Abbot   |
| 2  | Doris   |
| 3  | Emerson |
| 4  | Green   |
| 5  | Jeames  |
+----+---------+
输出: 
+----+---------+
| id | student |
+----+---------+
| 1  | Doris   |
| 2  | Abbot   |
| 3  | Green   |
| 4  | Emerson |
| 5  | Jeames  |
+----+---------+
解释:
请注意,如果学生人数为奇数,则不需要更换最后一名学生的座位。

解答:

(1)嵌套查询
# Write your MySQL query statement below
with base as(select *, lead(student, 1)over (order by id) as exchange_nxt, lag(student, 1)over (order by id) as exchange_pre from Seat
)
select id, IFNULL((case when (id % 2) != 0 then exchange_nxt else exchange_pre end), student) as student from base;
(2)CASE WHEN
# Write your MySQL query statement below
select case when id % 2 = 1 and id < (select max(id) from Seat)then id + 1when id % 2 = 0 then id - 1else idend as id, studentfrom Seat
order by id;

在 SQL 里,CASE 可以写两种形式:

a. 简单 CASE

直接对某个表达式的值做匹配:

CASE column_nameWHEN 'A' THEN '类型1'WHEN 'B' THEN '类型2'ELSE '其他'
END
b. 搜索 CASE (最常用)

条件判断灵活,可以写比较、范围等:

CASEWHEN score >= 90 THEN '优秀'WHEN score >= 60 THEN '及格'ELSE '不及格'
END
c. 作为一个字段输出
SELECT name,CASE WHEN age < 18 THEN '未成年'WHEN age < 60 THEN '成年人'ELSE '老年人'END AS age_group
FROM users;
d. 在聚合函数里做条件统计
SELECTSUM(CASE WHEN status = 'success' THEN 1 ELSE 0 END) AS success_count,SUM(CASE WHEN status = 'fail' THEN 1 ELSE 0 END)    AS fail_count
FROM logs;

常用于 条件计数

e. 排序(ORDER BY)
SELECT *
FROM orders
ORDER BYCASE WHEN status = 'vip' THEN 1WHEN status = 'normal' THEN 2ELSE 3END;

补充:

SQL执行顺序:

  • FROM Employee
  • WHERE salary > 5000 (先筛掉工资不够的行)
  • GROUP BY dept (按部门分组)
  • COUNT(*) 统计每组人数
  • HAVING 过滤出人数 ≥3 的部门
  • SELECT 输出 dept, cnt
  • ORDER BY 按 cnt 降序
  • LIMIT 取前 5 个部门

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/921201.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/921201.shtml
英文地址,请注明出处:http://en.pswp.cn/news/921201.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

RAGFlow切分方法详解

RAGFlow 各切分方法的含义如下,结合文档结构、场景特点等设计,以适配不同类型的知识源: 1. General(通用分块) 逻辑:结合文本排版、格式、语义关联等因素确定分割点,再根据“建议文本块大小(Token 数)”,将文本切分为合适的块。 支持格式:DOCX、EXCEL、PPT、IMAGE、…

支付域——支付与交易概念

摘要本文详细阐述了支付域中支付与交易的核心概念及其相互关系。交易是商品或服务交换的过程&#xff0c;包含多个要素并产生订单或合同。支付则是资金流转的过程&#xff0c;是交易的资金结算环节。支付交易结合了两者&#xff0c;根据不同场景提供多样化的支付产品和服务。文…

(自用)cmd常用命令自查文档

&#xff08;自用&#xff09;cmd常用命令自查文档 Windows CMD 常用命令自查1. 文件与目录操作命令说明示例​cd​显示或切换目录​cd​&#xff1b;cd C:\Windows​​dir​列出目录内容​dir​&#xff1b;dir /a​(含隐藏文件)​md​或mkdir​创建目录​md test​&#xff1…

剧本杀APP系统开发:引领娱乐行业新潮流的科技力量

在当今数字化时代&#xff0c;科技的力量正深刻地改变着人们的生活方式和娱乐习惯。娱乐行业也不例外&#xff0c;各种新兴的娱乐形式和平台如雨后春笋般涌现。剧本杀APP系统开发作为科技与娱乐融合的产物&#xff0c;正以其独特的魅力和创新的模式&#xff0c;引领着娱乐行业的…

LangChain框架深度解析:定位、架构、设计逻辑与优化方向

LangChain框架深度解析&#xff1a;定位、架构、设计逻辑与优化方向 引言 在大语言模型&#xff08;LLM&#xff09;应用开发的浪潮中&#xff0c;LangChain作为最具影响力的开发框架之一&#xff0c;为开发者提供了构建复杂AI应用的完整工具链。本文将从框架定位、实现逻辑、设…

面试常备与开发必知:一文掌握MySQL字符串拼接的所有核心技巧

‍ 在 MySQL 中拼接字符串是一个非常常见的操作&#xff0c;主要用于查询时动态组合多个字段或值。以下是几种最核心和常用的方法。一、核心拼接函数1. CONCAT(str1, str2, ...)这是最通用、最常用的字符串拼接函数。它接受两个或多个字符串参数&#xff0c;并将它们按顺…

数据可视化大屏精选开源项目

为您精心挑选和整理了一系列在 GitHub 上广受好评的数据可视化大屏开源项目。这些项目覆盖了不同的技术栈&#xff08;Vue、React、ECharts、D3.js等&#xff09;&#xff0c;适合从初学者到资深开发者不同层次的需求。 我将它们分为以下几类&#xff0c;方便您选择&#xff1…

LeetCode 3516.找到最近的人:计算绝对值大小

【LetMeFly】3516.找到最近的人&#xff1a;计算绝对值大小 力扣题目链接&#xff1a;https://leetcode.cn/problems/find-closest-person/ 给你三个整数 x、y 和 z&#xff0c;表示数轴上三个人的位置&#xff1a; x 是第 1 个人的位置。y 是第 2 个人的位置。z 是第 3 个人…

【面试】MySQL 面试常见优化问题

1. 为什么要建索引&#xff1f;索引一定能提高性能吗&#xff1f;场景&#xff1a;一个表有上千万数据&#xff0c;查询 SELECT * FROM user WHERE age25;。问题&#xff1a;没有索引时会全表扫描&#xff0c;性能差。解决方案&#xff1a;给 age 建立普通索引&#xff0c;加快…

Access开发导出PDF的N种姿势,你get了吗?

目录 基础篇&#xff1a;一行代码搞定 实战篇&#xff1a;让导出更智能 进阶篇&#xff1a;用户体验升级 总结 hi&#xff0c;大家好呀&#xff01; 今天我们来聊聊一个非常实用的功能——如何用VBA将Access中的数据导出为PDF。 相信很多朋友在日常工作中都遇到过这样的需…

JavaAI炫技赛:电商系统商品管理模块的创新设计与实践探索

一、引言电商行业的竞争日益激烈&#xff0c;电商系统商品管理模块的高效性、智能化程度成为企业提升竞争力的关键因素。Java 作为企业级开发的主流语言&#xff0c;凭借其稳定性和强大的生态系统&#xff0c;在电商系统开发中占据重要地位。而 AI 技术的融入&#xff0c;为商品…

关于如何在PostgreSQL中调整数据库参数和配置的综合指南

关于如何在PostgreSQL中调整数据库参数和配置的综合指南 PostgreSQL是一个非常通用的数据库系统,能够在低资源环境和与各种其他应用程序共享的环境中高效运行。为了确保它将在许多不同的环境中正常运行,默认配置非常保守,不太适合高性能生产数据库。加上地理空间数据库具有…

wps的excel如何转为谷歌在线表格

1. 打开 Google Sheets&#xff08;sheets.google.com&#xff09;。 2. 新建一个空白表格。3. 点击菜单 文件 → 导入 (File → Import)。4. 选择在 WPS 保存好的 .xlsx 文件上传。5. 选择 “新建表格” 或 “替换当前表格”&#xff0c;就能直接在 Google Sheets 使用注…

猫头虎AI 荐研|腾讯开源长篇叙事音频生成模型 AudioStory:统一模型,让 AI 会讲故事

&#x1f42f;猫头虎荐研&#xff5c;腾讯开源长篇叙事音频生成模型 AudioStory&#xff1a;统一模型&#xff0c;让 AI 会讲故事 大家好&#xff0c;我是猫头虎 &#x1f42f;&#x1f989;&#xff0c;又来给大家推荐新鲜出炉的 AI 开源项目&#xff01; 这次要聊的是腾讯 A…

收藏!VSCode 开发者工具快捷键大全

一、文件操作快捷键1. 打开与关闭文件Ctrl O&#xff08;Windows/Linux&#xff09;或 Command O&#xff08;Mac&#xff09;&#xff1a;打开文件&#xff0c;可以通过输入文件名快速查找并打开相应文件。Ctrl W&#xff08;Windows/Linux&#xff09;或 Command W&#…

Simulations RL 平台学习笔记

1. 选择标准 1.1 开源项目&#xff0c;&#x1f31f;star数量越多越好 2. 常见平台 2.1 &#x1f31f;18.6k ML-Agents&#xff1a;基于Unity实现 2.2 &#x1f31f;1.2k Godot RL Agents

【国内电子数据取证厂商龙信科技】IOS 逆向脱壳

我们都知道&#xff0c;大多数的 APP 在开发的时候一般都会加上一层壳&#xff0c;例如 爱加密、梆梆、360、网易易盾等等。那 APK 的脱壳我们见得多了&#xff0c;那 IOS 逆向脱壳又是怎样子的呢&#xff1f;首先咱们先了解一下为什么要砸壳&#xff0c;因为 IOS 开发者开发软…

基于STM32单片机温湿度PM2.5粉尘甲醛环境质量wifi手机APP监测系统

1 基于STM32单片机温湿度PM2.5粉尘甲醛环境质量WiFi手机APP监测系统 本系统旨在实现对环境中温度、湿度、PM2.5粉尘浓度以及甲醛浓度的实时监测&#xff0c;并通过WiFi技术将数据传输至手机APP端&#xff0c;实现移动化与可视化的环境质量检测。系统在硬件上主要依赖STM32单片…

用C++实现日期类

在上学的时候&#xff0c;总是在计算还有多少天放假&#xff1b;在上班的时候&#xff0c;总是在计算还有多久发工资&#xff1f;我们一般通过日历得到结果&#xff0c;那自己能不能实现一些基本的功能呢&#xff1f;答案是可以的&#xff01;需要实现内容&#xff1a;1. 日期加…

百度网盘基于Flink的实时计算实践

01 概览 随着数字化转型的来临&#xff0c;企业对于数据服务的实时化需求日益增长&#xff0c;在大规模数据和复杂场景的情况下&#xff0c;Flink在实时计算数据链路中扮演着极为重要的角色&#xff0c;本文介绍了网盘如何通过 Flink 构建实时计算引擎&#xff0c;从而提供高性…