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

力扣题

1、题目地址

601. 体育馆的人流量

2、模拟表

表:Stadium

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

3、要求

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

4、示例

输入:

Stadium 表:

idvisit_datepeople
12017-01-0110
22017-01-02109
32017-01-03150
42017-01-0499
52017-01-05145
62017-01-061455
72017-01-07199
82017-01-09188

输出:

idvisit_datepeople
52017-01-05145
62017-01-061455
72017-01-07199
82017-01-09188

解释:

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

5、代码编写

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不支持直接使用row_number()函数来实现行号的功能。然而,你可以通过其他方法来实现类似的效果。一种常见的方法是使用变量来模拟行号的功能。你可以在查询中使用变量来记录行号,并在需要时进行递增。例如,你可以使用以下查询来实现类似row_number()函数的功能: ``` SELECT @row_number := @row_number + 1 AS row_number, employee_id, employee_name, group_no, salary FROM (SELECT employee_id, employee_name, group_no, salary FROM employee ORDER BY group_no, salary DESC) AS t, (SELECT @row_number := 0) AS r; ``` 在这个查询中,我们使用了一个变量@row_number来记录行号,并在每一行中递增。通过将查询结果与一个初始值为0的变量进行连接,我们可以实现类似row_number()函数的功能。这样,你就可以在MySQL中实现类似的分组顺序编号的功能了。\[1\]\[2\]\[3\] #### 引用[.reference_title] - *1* *2* [MySQL如何实现row_number()及row_number over(partition by column)](https://blog.csdn.net/zhouseawater/article/details/90697305)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [mysqlrow_number函数吗?](https://blog.csdn.net/weixin_32141627/article/details/113192445)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值