目录
二、OVER 与 ROW_NUMBER():窗口函数中的行号
为什么 ,WHERE ROWNUM > 1 永远不会返回任何行
================
前言
在 Oracle 数据库中,ROWNUM 和 OVER 是用于不同目的但经常被混淆的两个概念。简单来说:
-
ROWNUM是一个伪列,它在查询结果集返回时,为每一行分配一个唯一的、递增的行号。 -
OVER是分析函数(窗口函数)的一部分,它与ROW_NUMBER()、RANK()等函数配合,在保留所有原始行的基础上,进行分组、排序和编号。
下面详细拆解这两个概念。
================
一、ROWNUM:结果集的行号伪列
1. 基本特性
-
ROWNUM是 Oracle 特有的,在查询返回行的过程中动态生成。 -
第一行
ROWNUM = 1,第二行ROWNUM = 2,依次类推。 -
关键点:
ROWNUM是在WHERE条件过滤之后、ORDER BY排序之前分配的。也就是说,如果用了ORDER BY,排序会改变行的物理顺序,但ROWNUM仍然是按照原始获取顺序分配的(除非使用子查询)。
2. 常用场景:限制返回的行数
-- 返回前 5 行(不等同于排序后的前 5)
SELECT * FROM employees WHERE ROWNUM <= 5;
注意:WHERE ROWNUM > 1 永远不会返回任何行,因为第一行被过滤后,第二行不会变成第一行(ROWNUM 始终从 1 开始)。所以要实现真正的分页,需要嵌套子查询。
3. 分页的正确写法(结合 ROWNUM)
SELECT * FROM (
SELECT e.*, ROWNUM rn FROM (
SELECT * FROM employees ORDER BY salary DESC
) e WHERE ROWNUM <= 20
) WHERE rn > 10;
4. ROWNUM 的局限
-
无法直接实现“每组内排名”。
-
与
ORDER BY同时使用时容易出错(因为先分配ROWNUM再排序)。 -
属于 Oracle 特有,不兼容其他数据库(如 PostgreSQL、MySQL 用
LIMIT)。
二、OVER 与 ROW_NUMBER():窗口函数中的行号
OVER 是分析函数的子句,用于定义窗口(即数据分组和排序的范围)。最常用的与行号相关的函数是 ROW_NUMBER()。
1. 基本语法
ROW_NUMBER() OVER ( [PARTITION BY 列1, 列2...] ORDER BY 列3 [ASC|DESC] )
-
PARTITION BY:可选,将数据分成独立的分组(如部门、类别)。 -
ORDER BY:在每个组内指定排序规则。 -
ROW_NUMBER():为每个组内的行分配一个唯一的、从1开始的连续编号。
=====
2. 典型例子:各部门按工资排序,从高到低编号
SELECT
employee_id,
department_id,
salary,
ROW_NUMBER() OVER (PARTITION BY department_id ORDER BY salary DESC) AS rn
FROM employees;
结果:每个部门内部,工资最高的人 rn=1,次高 rn=2,等等。
===
3. 与 ROWNUM 的核心区别
| 特性 | ROWNUM | ROW_NUMBER() OVER |
|---|---|---|
| 分配时机 | 在 WHERE 后、ORDER BY 前 | 在整个查询的最后阶段(SELECT 时计算) |
| 分组支持 | 无 | 支持 PARTITION BY 分组内部编号 |
| 是否唯一 | 整个结果集唯一且递增 | 每个分组内唯一,不同分组编号独立 |
| 顺序控制 | 受限于执行顺序,容易出错 | 通过 ORDER BY 明确控制 |
| 标准兼容 | Oracle 专有 | SQL:2003 标准,多数数据库支持 |
====
三、其它
OVER 英文 在这里如何解析

====
PARTITION BY 对应的英文是什么

====
什么叫 分析函数,为什又叫窗口函数

====
为什么 ,WHERE ROWNUM > 1 永远不会返回任何行

----

---


====
Oracle 中 PARTITION BY 的作用是什么



====
四、使用
删除要求
一条 SQL 语句(不使用 WITH),基于表中 DDD 字段实际存在的月份,删除“按月份排序后第 13 个最新月份”之前的所有数据。如果不同月份总数不足 13 个,则不删除任何数据。
DELETE FROM your_table
WHERE DDD < (
SELECT mon
FROM (
SELECT DISTINCT TRUNC(DDD, 'MM') AS mon,
ROW_NUMBER() OVER (ORDER BY TRUNC(DDD, 'MM') DESC) AS rn
FROM your_table
)
WHERE rn = 13
);
SQL 中使用了 TRUNC(DDD, 'MM'),这个函数会保留年份和月份(例如 2025-05-01、2024-12-01),因此按它降序排序时,年份不同的月份会自动按时间顺序排列
===========
| 测试分类 | Pattern ID | 测试场景描述 |
|---|---|---|
| 基本功能 | P1 | 少于13个不同月份(全保留) |
| 基本功能 | P2 | 恰好13个不同月份(全保留) |
| 基本功能 | P3 | 多于13个不同月份,连续无空月(删除最早一个月) |
| 边界值 | P4 | 跨年连续超过13个月(删除最早一个月) |
| 边界值 | P5 | 边界月份(第13个月)内有多条记录,且第14个月也有多条(整月原子删除) |
| 空月/稀疏数据 | P6 | 存在空月但总月份数少于13(全保留) |
| 空月/稀疏数据 | P7 | 存在空月且总月份数多于13(删除最早的实际月份) |
| 异常/极端 | P8 | 表中只有一个月的数据(全保留) |
| 异常/极端 | P9 | 表为空(无操作) |
===
删除效果举例
| No. | 月份(YYYY-MM) | 记录条数 | 是否删除 |
|---|---|---|---|
| 1 | 2026-03 | 2 | 保留 |
| 2 | 2026-02 | 2 | 保留 |
| 3 | 2026-01 | 2 | 保留 |
| 4 | 2025-12 | 2 | 保留 |
| 5 | 2025-11 | 2 | 保留 |
| 6 | 2025-10 | 2 | 保留 |
| 7 | 2025-09 | 2 | 保留 |
| 8 | 2025-08 | 2 | 保留 |
| 9 | 2025-07 | 2 | 保留 |
| 10 | 2025-06 | 2 | 保留 |
| 11 | 2025-05 | 2 | 保留 |
| 12 | 2025-04 | 2 | 保留 |
| 13 | 2025-03 | 2 | 保留 |
| 14 | 2025-02 | 10 | 删除 |
| 15 | 2025-01 | 10 | 删除 |
| 16 | 2024-12 | 10 | 删除 |
===
-
总数据条数:13 × 2 + 3 × 10 = 26 + 30 = 56
-
预期保留条数:26(No.1 ~ No.13)
-
预期删除条数:30(No.14 ~ No.16)
删除逻辑说明:
由于总共有 16 个不同月份,排序后最新的 13 个月(No.1~No.13)保留,剩下的 3 个月(No.14~No.16)全部删除。这与“保留最近 13 个有数据的月份”的规则一致。
====


2295

被折叠的 条评论
为什么被折叠?



