【MySQL】WITH AS 用法以及 ROW_NUMBER 函数 和 自增ID 的巧用

力扣题

1、题目地址

601. 体育馆的人流量

2、模拟表

表:Stadium

Column Name Type
id int
visit_date date
people int
  • visit_date 是该表中具有唯一值的列。
  • 每日人流量信息被记录在这三列信息中:序号 (id)、日期 (visit_date)、 人流量 (people)
  • 每天只有一行记录,日期随着 id 的增加而增加

3、要求

编写解决方案找出每行的人数大于或等于 100 且 id 连续的三行或更多行记录。
返回按 visit_date 升序排列 的结果表。
查询结果格式如下所示。

示例 1:

输入:
Stadium 表:

id visit_date people
1 2017-01-01 10
2 2017-01-02 109
3 2017-01-03 150
4 2017-01-04 99
5 2017-01-05 145
6 2017-01-06 1455
7 2017-01-07 199
8 2017-01-09 188

输出:

id visit_date people
5 2017-01-05 145
6 2017-01-06 1455
7 2017-01-07 199
8 2017-01-09 188

解释:
id 为 5、6、7、8 的四行 id 连续,并且每行都有 >= 100 的人数记录。
请注意,即使第 7 行和第 8 行的 visit_date 不是连续的,输出也应当包含第 8 行,因为我们只需要考虑 id 连续的记录。
不输出 id 为 2 和 3 的行,因为至少需要三条 id 连续的记录。

4、代码编写

1、我的写法

WITH one AS(
    SELECT *, ROW_NUMBER() OVER(ORDER BY id) AS r, id - ROW_NUMBER() OVER(ORDER BY id) AS rk
    FROM Stadium
    WHERE people >= 100
)
SELECT id, visit_date, people
FROM one
WHERE rk IN (
    SELECT rk
    FROM one
    GROUP BY rk
    HAVING COUNT(rk) >= 3
)
| id | visit_date | people |
| -- | ---------- | ------ |
| 5  | 2017-01-05 | 145    |
| 6  | 2017-01-06 | 1455   |
| 7  | 2017-01-07 | 199    |
| 8  | 2017-01-09 | 188    |

2、解析

SELECT *, ROW_NUMBER() OVER(ORDER BY id) AS r, id - ROW_NUMBER() OVER(ORDER BY id) AS rk
FROM Stadium
WHERE people >= 100
| id | visit_date | people | r | rk |
| -- | ---------- | ------ | - | -- |
| 2  | 2017-01-02 | 109    | 1 | 1  |
| 3  | 2017-01-03 | 150    | 2 | 1  |
| 5  | 2017-01-05 | 145    | 3 | 2  |
| 6  | 2017-01-06 | 1455   | 4 | 2  |
| 7  | 2017-01-07 | 199    | 5 | 2  |
| 8  | 2017-01-09 | 188    | 6 | 2  |

会发现一个点,自增ID 减去 row_number 的值一样连续的,我们只需要查找 同一个 rk 值出现大于等于 3 次 就满足条件

5、知识点

1、WITH AS

作用

1、在 SQL 查询中,经常会遇到需要 重复使用的子查询
2、为了 简化查询语句提高可读性,SQL 引入了 WITH AS 语法。
3、通过使用 WITH AS,我们可以创建临时表或视图,将子查询的结果保存起来,并在主查询中使用。

作用解析

1、简化复杂查询:当查询逻辑较为复杂或包含多个嵌套的子查询时,使用 WITH AS 可以将子查询逻辑分解成可读性更高的部分。这样可以降低查询的复杂度,并且更容易理解和维护。

示例1:假设有一个名为"orders"的表,存储了订单信息,包括订单号、客户ID和订单金额。我们想要查询每个客户的订单总金额,同时筛选出总金额大于1000的客户。使用 WITH AS 可以简化查询逻辑:

WITH customer_orders (customer_id, total_amount) AS (
   SELECT customer_id, SUM(order_amount) AS total_amount
   FROM orders
   GROUP BY customer_id
)
SELECT customer_id, total_amount
FROM customer_orders
WHERE total_amount > 1000;

上述示例中,我们创建了名为"customer_orders"的临时表,存储了每个客户的订单总金额。在主查询中,我们可以直接引用"customer_orders"表,并进行筛选操作,使查询逻辑更加清晰。

2、提高查询性能:使用 WITH AS 可以避免在主查询中重复执行相同的子查询,从而提高查询性能。临时表的结果会被缓存,主查询只需要引用临时表即可,避免了重复计算子查询的开销。

示例2:假设我们需要查询员工表中工资高于平均工资的员工信息,并按工资降序排序。使用 WITH AS 可以避免重复计算平均工资:

WITH average_salary AS (
   SELECT AVG(salary) AS avg_salary
   FROM employees
)
SELECT employee_id, first_name, last_name, salary
FROM employees
WHERE salary > (SELECT avg_salary FROM average_salary)
ORDER BY salary DESC;

上述示例中,我们通过创建名为"average_salary"的临时表,保存了员工表中的平均工资。在主查询中,我们直接引用临时表中的平均工资,避免了重复计算的开销,提高了查询性能。

2、ROW_NUMBER 函数

专用窗口函数,按行数进行排序,具体用法可以看参考里面第二个链接和第三个链接

3、参考

SQL 中的 WITH AS 用法:简化查询,提高可读性
MySQL 窗口函数(Rows & Range)—— 滑动窗口函数用法
窗口函数 OVER(PARTITION BY) 详细用法 —— 语法 + 函数 + 开窗范围 ROWS 和 RANGE

你可能感兴趣的:(#,MySQL,mysql)