暂无图片
暂无图片
2
暂无图片
暂无图片
暂无图片

用 FreeSQL 做可交互 Oracle SQL 教学:Top-N 分析的实战写法

很多数据库技术文章都有一个共同问题:
SQL 是静态的。
作者贴出一段代码,读者只能“看”,却很难真正理解 SQL 在执行时发生了什么。
而 SQL 本质上是一种行为型语言
只有执行、修改、对比结果,才能真正理解它的语义。
这篇文章尝试用一种更实用的方法:
把 Oracle SQL 放到 FreeSQL 可运行环境中,让读者可以直接执行、修改并观察结果变化。
我们用一个非常经典但经常被误解的主题作为案例:

Top-N 查询与窗口函数。

为什么可交互 SQL 比静态示例更有教学价值

在数据库教学中,很多概念其实很难靠“阅读代码”理解。
例如下面这几种典型场景:

语义变化必须通过执行观察

例如:

FETCH FIRST 10 ROWS ONLY

如果改成:

FETCH FIRST 5 ROWS ONLY

语法没有变化,但结果集立即变化。
只有实际运行,读者才能真正理解 SQL 语义与结果之间的关系

窗口函数必须通过结果理解

例如:

ROW_NUMBER()
SUM() OVER()

很多文章会解释语法规则,但读者依然会困惑:

  • 为什么需要 PARTITION BY
  • 排名是如何生成的
  • 累计值为什么会变化

这些问题只有 跑出结果之后对比,才会真正理解。

技术文章的可信度更高

可执行 SQL 的另一个优势是:

读者可以复现。

不是“作者说可以运行”,而是:

我已经执行过,并且给出了结果摘要。

这对于数据库技术文章来说非常重要。

场景拆分:全局 Top-N vs 分组 Top-N

在业务系统中,经常会遇到两种类似但完全不同的问题:

问题一

全公司薪资最高的前 N 人。

问题二

每个部门薪资最高的前 N 人。

这两个问题的 SQL 写法完全不同。

语句一:全局 Top-N

查询薪资最高的前 10 名员工。

SELECT employee_id, last_name, salary
FROM hr.employees
ORDER BY salary DESC
FETCH FIRST 10 ROWS ONLY;

这里的逻辑非常直接:

  1. 全表排序
  2. 取前 10 行

回答的问题是:

整个公司谁的薪资最高

语句二:每部门 Top-3

如果需求变成:

每个部门薪资最高的 3 个人

就不能简单使用 FETCH FIRST,而需要使用 窗口函数

WITH ranked_data AS (
SELECT
department_id,
employee_id,
last_name,
salary,
ROW_NUMBER() OVER (
PARTITION BY department_id
ORDER BY salary DESC
) AS rn
FROM hr.employees
WHERE department_id IS NOT NULL
)
SELECT department_id, employee_id, last_name, salary, rn
FROM ranked_data
WHERE rn <= 3
ORDER BY department_id, rn;

这里发生了三件事情:
PARTITION BY department_id

把数据按部门划分
ORDER BY salary DESC

每个部门内部排序
ROW_NUMBER()

生成部门内部排名
最后只保留 排名 ≤ 3 的员工。

语句三:部门薪资概览

有时候我们并不关心个人排名,而是希望从管理视角观察部门结构。

SELECT
department_id,
COUNT(*) AS emp_count,
ROUND(AVG(salary), 2) AS avg_salary,
MAX(salary) AS max_salary
FROM hr.employees
GROUP BY department_id
ORDER BY avg_salary DESC;

这个查询可以快速回答三个问题:

  • 部门人数
  • 平均薪资
  • 最高薪资

适合用于 部门横向对比分析

语句四:窗口累计分析

窗口函数还可以用于观察 高薪群体对薪资总额的贡献

SELECT
employee_id,
last_name,
salary,
SUM(salary) OVER (ORDER BY salary DESC) AS running_total
FROM hr.employees
ORDER BY salary DESC
FETCH FIRST 15 ROWS ONLY;

这里的 SUM() OVER() 表示:

按照薪资排序进行累计计算。

例如:

24000
24000 + 17000
24000 + 17000 + 17000

可以直观看到 高薪员工对薪资总额的累计贡献

实测验证结果(已执行)

为了保证 SQL 的可复现性,以上语句已经在 FreeSQL 23ai 环境中执行验证。

Q1 连通性验证

SELECT 'Hello FreeSQL' AS msg,
TO_CHAR(SYSDATE,'YYYY-MM-DD HH24:MI:SS') AS run_time
FROM dual;

结果:

MSG       = Hello FreeSQL
RUN_TIME  = 2026-03-09 13:30:56

Q2 全局 Top-N

返回 10 行,前几行为:

(100, King, 24000)
(101, Yang, 17000)
(102, Garcia, 17000)
(145, Singh, 14000)
(146, Partners, 13500)

Q3 每部门 Top-3

返回 25 行,示例:

部门 90
King / Yang / Garcia

部门 80
Singh / Partners / Errazuriz

Q4 部门聚合

返回 12 个部门统计结果,均薪最高的几个部门:

部门 90   19333.33
部门 110  10154
部门 70   10000

Q5 窗口累计

返回 15 行

(100, King, 24000, 24000)
(101, Yang, 17000, 58000)
(102, Garcia, 17000, 58000)
(205, Higgins, 12008, 122516)
(108, Gruenberg, 12008, 122516)

写在最后

很多数据库教学内容的问题不在 SQL 本身,而在 表达方式
静态代码块只能展示:

SQL 是怎么写的。

而可执行 SQL 展示的是:

SQL 执行后到底发生了什么。

对于 Top-N、窗口函数、排名分析 这类主题来说,可交互环境的教学价值明显更高。
技术文章如果能做到 可运行、可验证、可复现,读者的理解成本会大幅降低。
从数据库教育的角度看,这比单纯贴代码更有意义。

「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论