分组查询:避免返回列值变更前后的重复列值行
解决思路:过滤掉连续重复的分组编辑记录
嘿,这个需求我之前帮人处理过类似的,先跟你确认下我的理解:你想要的是把同一帖子下同一作者连续编辑的重复行过滤掉——也就是当post_id和author_id的组合连续重复时,只保留其中一条,避免返回这些连续重复的行;而如果作者切换了(哪怕之后又切回原作者),这些新的编辑记录要保留。如果我理解错了,你随时补充说明哈!
方法1:用LAG()窗口函数快速过滤连续重复行
这个方法最直接,用窗口函数LAG()获取当前行的前一行分组信息,对比如果和当前行一致就过滤掉,只保留分组变化的节点和第一行。
拿MySQL举例子,SQL语句是这样的:
SELECT post_id, author_id, edit_message, date FROM ( SELECT post_id, author_id, edit_message, date, -- 获取前一行的分组标识(把post_id和author_id拼起来) LAG(CONCAT(post_id, '-', author_id)) OVER (ORDER BY date) AS prev_group FROM post_edits ) AS sub_query -- 保留第一行,或者和前一行分组不同的行 WHERE prev_group IS NULL OR CONCAT(post_id, '-', author_id) != prev_group;
要是你用的是PostgreSQL这类支持行比较的数据库,还能写得更优雅:
SELECT post_id, author_id, edit_message, date FROM ( SELECT post_id, author_id, edit_message, date, LAG((post_id, author_id)) OVER (ORDER BY date) AS prev_group FROM post_edits ) AS sub_query WHERE prev_group IS NULL OR (post_id, author_id) != prev_group;
方法2:保留每个连续分组的最新编辑记录
如果你不想只留分组的第一条,而是想保留每个连续编辑阶段的最新那条消息,就可以用ROW_NUMBER()窗口函数配合分组ID来实现:
SELECT post_id, author_id, edit_message, date FROM ( SELECT post_id, author_id, edit_message, date, ROW_NUMBER() OVER ( PARTITION BY group_id ORDER BY date DESC ) AS row_num FROM ( SELECT post_id, author_id, edit_message, date, -- 生成连续分组的ID:每次分组变化就加1 SUM(CASE WHEN prev_group = CONCAT(post_id, '-', author_id) THEN 0 ELSE 1 END) OVER (ORDER BY date) AS group_id FROM ( SELECT post_id, author_id, edit_message, date, LAG(CONCAT(post_id, '-', author_id)) OVER (ORDER BY date) AS prev_group FROM post_edits ) AS step1 ) AS step2 ) AS step3 WHERE row_num = 1 ORDER BY date;
简单说下逻辑:
- 最内层先拿到每行的前一行分组;
- 中间层给每个连续的相同分组分配一个唯一ID,分组一变ID就加1;
- 最外层按分组ID拆分,每个分组里按时间倒序排,取第一行就是这个连续编辑阶段的最新记录。
举个实际结果例子
用你给的样本数据,按时间排序后:
- post1, author1, "first author's first edit to post 1", 2018-03-19 12:00:00
- post1, author1, "first author's second edit to post 1", 2018-03-19 12:05:00
- post2, author1, "first author's first edit to post 2", 2018-03-19 12:10:00
- post1, author1, "first author's third edit to post 1", 2018-03-19 12:15:00
- post1, author2, "second author's first edit to post 1", 2018-03-19 12:20:00
- post1, author1, "first author's fourth edit to post 1", ...
用方法1得到的结果是:行1、行3、行4、行5、行6——把连续重复的行2过滤掉了。
用方法2得到的结果是:行2、行3、行4、行5、行6——每个连续分组只留最新的那条。
小提醒
- 要确保你的数据库支持窗口函数哈,比如MySQL 8.0+、PostgreSQL、SQL Server这些都没问题;
- 排序全靠
date列,要是有相同时间的编辑记录,最好加个自增ID当额外排序字段,保证顺序不会乱。
内容的提问来源于stack exchange,提问作者Sean
相关产品推荐
相关产品推荐

