导读:本期聚焦于小伙伴创作的《SQL如何实现带有分组逻辑的数据分页?窗口函数配合WHERE过滤怎么用》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《SQL如何实现带有分组逻辑的数据分页?窗口函数配合WHERE过滤怎么用》有用,将其分享出去将是对创作者最好的鼓励。

在业务开发中,经常会遇到需要先对数据按某个字段分组,再对每个分组内的数据排序,最后实现分页查询的场景,比如查询每个分类下最新的10条商品,或者每个用户最近的操作记录。传统的分页方式如果直接加GROUP BY再LIMIT,往往无法得到正确的分组内分页结果,这时候使用窗口函数配合WHERE过滤就能很好地解决这个问题。

为什么需要窗口函数配合WHERE过滤实现分组分页

普通的SQL分页通常使用LIMIT关键字,比如查询前10条数据就写LIMIT 10,但这种分页方式是对整个查询结果集生效,不会区分分组。如果我们需要先按分类分组,再取每个分类下的前N条数据,直接写GROUP BY加LIMIT,只会返回所有分组聚合后的结果,丢失分组内的明细数据。

比如我们有一个商品表product,结构如下:

字段名类型说明
idint商品ID
category_idint分类ID
product_namevarchar商品名称
create_timedatetime创建时间

现在需要查询每个分类下最新的2条商品,用普通的分组查询是无法实现的,因为GROUP BY会把同一个分类的多条记录合并成一条,这时候就需要窗口函数先给每个分组内的记录生成序号,再通过WHERE过滤序号实现分页。

核心实现步骤

第一步:使用窗口函数生成分组内序号

窗口函数可以在不改变原查询结果集行数的情况下,对数据进行分组排序并生成序号,常用的序号生成函数有ROW_NUMBER()RANK()DENSE_RANK(),其中ROW_NUMBER()会生成连续不重复的序号,最适合分页场景。

语法格式为:

ROW_NUMBER() OVER (PARTITION BY 分组字段 ORDER BY 排序字段 [ASC/DESC]) AS 序号别名

其中PARTITION BY后面跟分组的字段,相当于GROUP BY的分组逻辑,ORDER BY是分组内的排序规则。比如给每个分类的商品按创建时间倒序生成序号:

SELECT 
    id,
    category_id,
    product_name,
    create_time,
    ROW_NUMBER() OVER (PARTITION BY category_id ORDER BY create_time DESC) AS rn
FROM product

第二步:嵌套查询配合WHERE过滤实现分页

窗口函数生成的结果不能直接用在WHERE条件里,因为WHERE的执行顺序早于窗口函数,所以需要把上面的查询结果作为子查询,再在外层查询中用WHERE过滤序号范围,实现分页。

比如要取每个分类下最新的2条商品,也就是序号rn小于等于2的记录:

SELECT 
    id,
    category_id,
    product_name,
    create_time
FROM (
    SELECT 
        id,
        category_id,
        product_name,
        create_time,
        ROW_NUMBER() OVER (PARTITION BY category_id ORDER BY create_time DESC) AS rn
    FROM product
) t
WHERE t.rn <= 2

第三步:实现通用的分页逻辑

如果需要实现类似LIMIT offset, pageSize的分页效果,比如每页取2条,取第2页的数据,也就是每个分组内取第3到第4条记录,只需要调整WHERE条件的范围即可:

-- 假设pageSize=2,pageNum=2,offset=(pageNum-1)*pageSize=2
SELECT 
    id,
    category_id,
    product_name,
    create_time
FROM (
    SELECT 
        id,
        category_id,
        product_name,
        create_time,
        ROW_NUMBER() OVER (PARTITION BY category_id ORDER BY create_time DESC) AS rn
    FROM product
) t
WHERE t.rn > 2 AND t.rn <= 4

注意事项

  • 窗口函数支持大部分主流数据库,包括MySQL 8.0+、PostgreSQL、SQL Server、Oracle等,低版本MySQL不支持窗口函数,需要用变量模拟实现。
  • 如果分组内的排序字段有相同值,ROW_NUMBER()会随机给相同值的记录分配不同的序号,如果需要相同值序号相同,可以换成RANK()或者DENSE_RANK(),但分页逻辑需要对应调整。
  • 子查询的别名是必须的,大部分数据库要求派生表必须有别名,否则会报错。
  • 如果原表数据量很大,建议在分组字段和排序字段上建立联合索引,提升窗口函数的执行效率。

低版本MySQL的替代实现

如果是MySQL 5.7及以下版本,没有窗口函数,可以用用户变量模拟分组内序号的生成:

SELECT 
    id,
    category_id,
    product_name,
    create_time
FROM (
    SELECT 
        id,
        category_id,
        product_name,
        create_time,
        @rn := CASE WHEN @prev_category = category_id THEN @rn + 1 ELSE 1 END AS rn,
        @prev_category := category_id
    FROM product, (SELECT @rn := 0, @prev_category := NULL) vars
    ORDER BY category_id, create_time DESC
) t
WHERE t.rn <= 2

这种方式通过变量记录上一个分组的字段值和当前序号,实现分组内序号的生成,逻辑和窗口函数类似,但可读性和维护性不如窗口函数。

SQL窗口函数分组分页WHERE过滤数据分页修改时间:2026-06-25 11:52:01

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。