☰
学习记录怎么做才有效?SQL窗口函数笔记实战
2026/10/19 5:02:13 网站建设 项目流程

很多人做学习记录,最后都做成了一本漂亮摘抄本。我以前也这样:标题写得工工整整,关键词标得五颜六色,回头一看,全是原文搬运,真正进入脑子的没几句。3月10日那天我重新调整了记录方式,把“0310学习记录”从一个普通日期标题,变成了一套能反复调用、能长出新问题的知识资产。这篇文章不聊鸡汤,就把当天的完整记录思路、踩坑过程和复盘方法摊开讲,顺便把那天真正钻研的SQL窗口函数笔记也一并整理出来。如果你记笔记总感觉“记了等于白记”,或者学完新知识一周就忘干净,这篇内容应该能帮上忙。

1. 学习前的“配置”:先想清楚今天要留下什么

我习惯用日期作为文件名,所以我当天的文档就叫“0310学习记录”。但内容不是打开文档直接开始抄,而是先花十几分钟做了一次“学习前配置”。这个动作决定了后面整天的记录质量。

配置的核心是回答三个问题:今天学什么、带着什么问题学、学完之后要能回答什么。我当天给自己定的主题是SQL窗口函数,原始问题是“窗口函数和GROUP BY分组到底有什么区别”,预期产出是“一张能直接套用的函数对比表”。

这三个问题写进文档顶部,后面学习时所有内容都围绕它们展开,跑偏了的东西无论多精彩都先扔进“暂存区”。暂存区这个设计非常实用,它可以防止你为了记而记,也能保证主线不被无关内容带跑。

1.1 为什么问题清单比学习清单更重要

大部分人列的计划是“学习窗口函数”“看完第5章”,这种计划只看动作不看目的。用“问题清单”代替“计划清单”之后,记录方式会自然改变:你不再是知识的搬运工,而是一个带着问题去找答案的人。

举一个对比。如果今天我记录的是“窗口函数可以在不合并行的前提下计算排名”,这句话你明天再看会觉得很眼熟,但不会有任何深入思考。如果记录的是“窗口函数算排名时,哪几个函数对并列值的处理方式不一样”,下次你写排名统计时会立刻想起这个记录,因为它背后有一个你正在处理、或迟早要处理的问题。

问题清单的本质是把学习从记忆动作转成检索动作。记录时脑子里有个问题,笔记内容才是主动筛选过的思考结果,而不是被动录入的文字。

1.2 我给“0310”定的三条过程约束

光有问题还不够,当天的记录过程我也给自己设了三条约束。

第一条:不复制原文。所有笔记必须用自己的话重写,哪怕绕口一点也要重写。复制的笔记永远不会成为你自己的表达,而“用自己的话能说出来”才是真懂的标志。

第二条:每个核心概念必须配一个“最小案例”。概念后面跟着代码、数据或操作步骤,不配案例一律视为没写完。这一条对技术类学习尤其重要,文字描述再丰盛,最后都要落到“跑一下看结果”这一步。

第三条:当天踩到的每一个报错、每一个意外结果都必须记录原样信息。包括错误提示、出错时的数据、当时的推测和最终解决方式。这条约束后面实际帮了大忙。

这三条约束看起来简单,但执行起来有一个明显的心理阻力:记录速度会明显慢下来。我一开始也想过“直接摘一段多快啊”,后来发现慢下来才能把正在学的东西真正变成自己的。这也是学习记录里最反本能的地方:想学得快,先要学会记得慢。

2. 0310的正文主题:用一张对比表吃透窗口函数

当天学习的核心是SQL窗口函数。选择这个主题的原因很实际:处理分组统计时我经常要在“分组后合并行”和“保留明细同时显示排名”之间纠结,普通GROUP BY会把多行压缩成一行,窗口函数却能在不改变明细行数的前提下完成计算。

窗口函数的基本写法和普通函数最大的区别,是多了一个OVER子句。OVER这个关键字就是“窗口”的入口,它决定了函数运算时能看到哪些行、按什么顺序运算。

SELECT 员工姓名, 所属部门, 业绩金额, ROW_NUMBER() OVER (PARTITION BY 所属部门 ORDER BY 业绩金额 DESC) AS 部门排名 FROM 销售业绩表;

这条语句的含义是:先按部门切开数据,每个部门视为一个小窗口,再在窗口内按业绩金额从高到低排序,最后用ROW_NUMBER给每一行标记序号。GROUP BY也能算部门排名,但它会损失明细信息,而且只能在聚合后的结果上操作,没法保留“每个员工原始行”的同时再附带一个排名列。

2.1 OVER 子句是打开窗口的第一把钥匙

很多人在窗口函数上卡住,问题基本都出在没搞懂OVER的组成。OVER后面可以跟两个部分:PARTITION BY和ORDER BY。

PARTITION BY的作用是分组,但它和GROUP BY有一个核心区别:GROUP BY会合并行,PARTITION BY只是把数据切开,每一行原样保留。可以这样理解:PARTITION BY相当于在桌子上放了几块挡板,数据被分到不同区域,但每一张纸都还在;GROUP BY则像把纸张按类别叠起来,原来的单张已经看不见了。

ORDER BY负责决定窗口内的计算顺序。排名类函数必须依赖它。比如计算累计值、移动平均值、当前行与前后行的差值,本质上都是靠ORDER BY确定“当前行”在窗口里的相对位置。

这两种操作组合起来变化非常多。我当天在记录里专门留了一页,把PARTITION BY和ORDER BY的不同组合各跑了一遍:

组合结果典型用处
只有PARTITION BY窗口内不分先后,函数按所有行同层计算需要一次性看全窗口的场景(较少单独用)
只有ORDER BY全局排序,不分组全量排名、全局累计
两者都有先分组,再在组内排序计算部门内排名、组内累计
两者都没有窗口覆盖整张表,不做排序表级汇总列,比如总数带在明细旁边

这张表是我当天记录里最有价值的部分。它的价值不在于内容多深奥,而在于它把一个函数的多种用法一次性对照清楚了。后面不管代码怎么写,一看到OVER,我脑子里先自动反应出这四种组合。

2.2 ROW_NUMBER、RANK、DENSE_RANK 的边界差异

窗口函数里有一组极易混淆的函数,就是ROW_NUMBER、RANK和DENSE_RANK。表面上看都是给行打序号,实际对并列值的处理完全不同。我当天用一组模拟数据跑出来这样的结果:

SELECT 姓名, 分数, ROW_NUMBER() OVER (ORDER BY 分数 DESC) AS 行号, RANK() OVER (ORDER BY 分数 DESC) AS 普通排名, DENSE_RANK() OVER (ORDER BY 分数 DESC) AS 密集排名 FROM 考试分数表;

同样三个人考了90分并列第二,三个函数给出的结果分别是:ROW_NUMBER按物理顺序排,三个人各拿一个不重复的序号,比如2、3、4;RANK会让并列的人共享同一名次,跳过后续名次,结果可能是2、2、2、5;DENSE_RANK同样共享名次,但不跳号,结果是2、2、2、3。

这里最关键的细节是“跳过名次”和“不跳过名次”的区别。做比赛排行、绩效考核时通常用RANK,因为要保留名次间距;做连续编号、数据标记时用ROW_NUMBER,因为每一行必须唯一;需要排名紧凑且并列名次一致时用DENSE_RANK。

我记录这类函数差异时没有把它们当成三个独立函数背,而是放在同一张表里按“并列处理方式”和“是否跳号”两条维度对比。这样记得快、也记得准,下次遇到具体需求不需要翻书,直接回忆这张表就能确定选哪个。

3. 当天踩到的三个坑:错误信息也是学习记录的一部分

学习记录只写“会了的部分”是不完整的。真正让记录值钱的,恰恰是那些自己踩进去的坑。当天我在练习窗口函数时至少踩了三个典型坑,每一个我都把原始信息留在了记录里。

3.1 WHERE 无法直接过滤窗口函数的结果

我最初想写“筛选出部门内排名前两名的员工”,第一反应是写完窗口函数再用WHERE过滤排名。然后立刻报错了。原因是SQL的执行顺序里,WHERE发生在SELECT阶段之前,而窗口函数是在SELECT阶段才计算的。WHERE执行时根本看不到排名这一列,自然没法用它做过滤。

绕了一圈,正确做法是把窗口查询包成一个子查询,再在外层过滤:

SELECT * FROM ( SELECT 姓名, 部门, RANK() OVER (PARTITION BY 部门 ORDER BY 业绩 DESC) AS 组内排名 FROM 业绩表 ) t WHERE 组内排名 <= 2;

这个坑的意义不在于子查询的写法,而在于它把SQL执行顺序这个底层概念具象化了。离开了报错,我可能不会主动去查执行顺序,也就不会理解为什么窗口函数不能出现在WHERE里。

3.2 排序字段里的 NULL 会改写结果

第二个坑是排序字段里出现了空值。按业绩降序排列时,有几个员工的业绩字段是NULL,默认排序下NULL会排在最后。这个行为看起来还合理,但换一个数据库、换一个排序方向,结果可能完全不一样。

各数据库对NULL的排序习惯差异很大。有的默认升序时NULL排在前面,有的默认排在后面。如果业务上要求“业绩为空的员工必须显示在最底部”,就必须显式处理空值。

SELECT 姓名, 业绩, RANK() OVER (ORDER BY CASE WHEN 业绩 IS NULL THEN 0 ELSE 1 END DESC, 业绩 DESC ) AS 排名 FROM 业绩表;

这个坑给我最深的提醒是:写排序时不要默认空值的处理方式,要主动确认数据里有没有空值、需求里有没有明确要求。一个问题如果不亲手碰到,光靠看书是很难留下深层印象的,所以记录里我专门给它标了“高危”两个字。

3.3 记录“执行顺序”而不是“背结论”

这三个坑背后其实共享同一个底层知识:SQL子句执行顺序。当天我把执行顺序明确写在记录里,作为所有排序问题的统一解释:

执行顺序大致是FROM、JOIN、WHERE、GROUP BY、HAVING、SELECT、ORDER BY、LIMIT。窗口函数在SELECT阶段被计算,所以SELECT里的别名不能在WHERE使用,ORDER BY却可以引用SELECT里生成的窗口结果。

这个顺序不需要死记,只需要在踩坑时回头对照一次。我在记录里写的不是“记住:WHERE不能放窗口函数”,而是“WHERE在窗口函数之前执行,所以WHERE天然看不到窗口函数的结果”。原因一旦写下来,类似问题以后就变成推理题而不是背诵题。

4. 晚间复习:把笔记翻译成问题再重启记忆

白天记录的笔记再详细,也只能算是初步加工。我当天晚上做了一件更重要的事:把所有笔记从“陈述句”转成“问句”。这个动作很多人没做过,但它是笔记真正进入长期记忆的关键一步。

比如白天的笔记写着“RANK对并列值共享名次且跳号”,晚上我改写成“当前三名分数相同,RANK给出的序号是几?DENSE_RANK呢?为什么?”改写之后,复习不再是看一遍,而是变成了一次自我测验。

4.1 从“陈述句笔记”到“设问句卡片”

陈述句笔记适合作为原始存档,但不适合作为复习材料。大脑对“读一遍”的内容几乎没有检索压力,对“想出来”的内容才会留下强记忆。所以我把每条核心笔记都翻译成了一个“如果…会怎样”的问题。

例如关于窗口函数范围的问题:“如果PARTITION BY按部门分组,ORDER BY按日期排序,窗口范围是整张表还是部门内所有历史行?”这样的问题在复习时会把记忆重新激活,而不只是再扫一眼熟悉的段落。

这个方法还有一个额外好处:它能逼着我把模糊点提前暴露出来。有些内容白天以为自己懂了,晚上改成问句时才发现答不上来,这就是所谓的“假懂”。晚上复习的价值,很大程度就是把这些假懂拆穿。

4.2 我使用的三遍提取法

当晚我用了三遍提取法复习当天内容,节奏很简单:第一遍在学完半小时后,不看笔记,凭记忆把刚学的三个知识点默写出来,只写关键词就行;第二遍在当天晚上,把所有笔记变成问题,逐个口头回答,答不出来的做标记;第三遍放在三天后,只复习带标记的问题,如果还想得起来,就证明这批知识点已经接入长期记忆。

这个方法看上去没什么技术含量,但坚持下来效果非常扎实。关键在于第二遍的“问答式复习”必须把手挡住,先尝试从大脑里调取信息,再去翻笔记确认。一旦直接翻答案,这一遍就废了。

我见过一些同学复习时把笔记从头到尾朗读几遍,感动了自己,考试时依然一片空白。原因就是朗读用的是眼睛和嘴,没有用大脑。学习记录真正要产出的,不是一个整理好的文档,而是大脑里能迅速调用的信息路径。

5. 一周之后:0310记录如何变成可复用资料

学习记录最忌讳的就是写完就封存。0310这份记录之所以后来能持续发挥价值,是因为我在一周后对它做了两步整理:加索引、建立关联。

如果没有这两步,这份记录就只是一堆零散知识的合集;做了这两步之后,它就成了一个能在未来被快速调用的资料包。

5.1 给记录加索引,让旧笔记接得住新问题

我在文档开头加了一个“索引区”,只保留四类信息:今天学到的核心概念、涉及的SQL关键字、遇到的报错、可复用的代码片段。每类后面都标了对应正文位置。

这个索引不是为了好看,而是为了降低未来的检索成本。一个月后我再遇到“需要保留明细的分组统计”时,不用翻完全文,直接看索引里的“PARTITION BY”就能定位到当时那张对比表。学习记录之所以经常失效,很多时候不是因为没记,而是因为记完找不到。

我在索引区还会顺手加一个“当时感觉”字段,比如“这个点很绕,下次先在纸上画一下窗口范围再写代码”。这种经验性备注在技术文档里找不到,只有自己知道,它才能为未来的自己省时间。

5.2 同一主题的后续扩展方向

学习记录不必只停留在当天。我会在索引区预留一项“后续问题”,把学习时衍生出来的新问号写进去。0310这份记录的后续问题我当时列了:移动平均的计算性能优化、窗口函数与自连接的等价转换、不同数据库对命名窗口的差异支持。

这些后续问题一周后陆续变成新的学习记录主题,每一篇新的记录又会引用回0310这份旧记录。一段时间后,这些记录不再是零散文件,而是一张互相引用的问题网。

这个做法让我养成了一个习惯:学任何一个新知识点,先问它和旧笔记里哪个问题有关。有关联就单独建一条链接,没有关联就标记成素材,等待后续连接。学习记录到了这个阶段,才真正从“抄写”变成了“知识管理”。

6. 学习记录的反本能心得

做了大量学习记录之后,我最大的体会是:学习记录真正难的不是方法,而是对抗本能。

6.1 记录的速度必须低于思考的速度

人的本能是追求高效率,看到一个知识点就急着把它抄下来。但抄的速度一旦超过思考的速度,记录就会变成机械行为。我在0310的记录过程中刻意放慢了很多,每个概念都先自己解释一遍,解释不出来再回看原文。

这种慢其实是一种投资:当时多花五分钟想明白,之后至少省五十分钟重新查资料。很多人觉得记录慢是在浪费时间,恰恰相反,记录里的迂回才是真正省时间的地方。

判断你的记录速度是否过快,有一个简单的自测方法:翻开一周前的笔记,看能否在不用搜索引擎的前提下把当时的核心概念讲清楚。如果你还需要再查一遍,说明当时的记录其实没进入记忆,那篇笔记充其量只是缓存。

6.2 日志是做给自己的,不是做给打卡的

另一个很隐蔽的坑是“表演性记录”。为了显得自己学得很认真,把笔记做得特别美观、特别完整,结果时间全花在排版和美图上,知识本身反而没进脑子。

我在实际操作中发现,真正有用的记录往往是粗糙的。它带着问题意识、报错信息和一堆没头没尾的追问,给人看可能不够精致,但给自己用非常顺手。美观不是学习记录的KPI,关键是被记录的知识是否参与了大脑的结构化过程。

最后分享一个从0310记录里总结出来的小技巧:每篇学习记录结尾不要写“今天学完了什么”,而是写“今天留下了什么疑问”。疑问是下一篇记录的起点,也是旧记录持续生长的养料。我现在的所有学习记录都保留了这一栏,它让每一篇都不是孤立的终点,而是知识网络里的一个节点。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询