导读:本期聚焦于小伙伴创作的《如何用SQL在报表中标记变动项_使用LAG对比新旧值》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《如何用SQL在报表中标记变动项_使用LAG对比新旧值》有用,将其分享出去将是对创作者最好的鼓励。

在报表开发场景中,识别数据项的变动情况是常见需求,比如统计用户状态变更、订单金额波动、库存数量变化等。传统方式需要自关联表获取上一周期数据,逻辑复杂且性能较差,而使用SQL的LAG窗口函数可以直接获取同一分组内前序行的数据,通过简单对比就能完成变动标记。

如何用SQL在报表中标记变动项_使用LAG对比新旧值

LAG函数基础语法

LAG函数属于窗口函数的一种,作用是返回当前行之前指定偏移量的行的数据,基础语法如下:

LAG(expression [, offset [, default_value]]) 
OVER (
    [PARTITION BY partition_expression]
    ORDER BY sort_expression [ASC|DESC]
)

参数说明:

  • expression:要获取的列或表达式,即需要对比的旧值来源
  • offset:偏移量,默认值为1,表示获取前1行的数据,也可以设置为2获取前2行的数据
  • default_value:当没有前序行时返回的默认值,不设置的话默认返回NULL
  • PARTITION BY:分组条件,可选,用于在不同分组内独立计算LAG值,比如按用户分组、按部门分组
  • ORDER BY:排序条件,必选,用于确定行的先后顺序,通常按时间、序号等排序

基础变动标记示例

假设我们有一张用户状态变更记录表user_status_log,结构如下:

字段名类型说明
user_idINT用户ID
statusVARCHAR用户状态 正常/冻结/注销
change_timeDATETIME状态变更时间

现在需要查询每个用户的状态变更记录,并标记当前状态相比上一次是否发生了变动,SQL实现如下:

SELECT
    user_id,
    status AS current_status,
    change_time,
    -- 获取上一次的状态,没有上一次记录则返回空字符串
    LAG(status, 1, '') OVER (
        PARTITION BY user_id 
        ORDER BY change_time ASC
    ) AS previous_status,
    -- 标记是否变动,状态不同则为变动
    CASE 
        WHEN LAG(status, 1, '') OVER (
            PARTITION BY user_id 
            ORDER BY change_time ASC
        ) != status THEN '是'
        ELSE '否'
    END AS is_changed
FROM user_status_log
ORDER BY user_id, change_time ASC;

上述查询中,首先按user_id分组,保证每个用户的状态记录独立排序,再按change_time升序排列,拿到每个用户上一次的状态值,最后通过对比当前状态和上一次状态,完成变动标记。

多维度数值对比场景

如果是数值类数据的变动标记,比如每日销售额对比,我们可以同时计算变动值和变动比例。假设有销售日报表daily_sales,包含sale_date(销售日期)、product_id(商品ID)、sale_amount(销售额)三个字段,需求是标记每日销售额相比前一日的变动情况:

SELECT
    product_id,
    sale_date,
    sale_amount AS current_amount,
    -- 获取前一日的销售额
    LAG(sale_amount, 1, 0) OVER (
        PARTITION BY product_id 
        ORDER BY sale_date ASC
    ) AS previous_amount,
    -- 计算变动金额
    sale_amount - LAG(sale_amount, 1, 0) OVER (
        PARTITION BY product_id 
        ORDER BY sale_date ASC
    ) AS change_amount,
    -- 计算变动比例,避免除零错误
    CASE 
        WHEN LAG(sale_amount, 1, 0) OVER (
            PARTITION BY product_id 
            ORDER BY sale_date ASC
        ) = 0 THEN NULL
        ELSE ROUND(
            (sale_amount - LAG(sale_amount, 1, 0) OVER (
                PARTITION BY product_id 
                ORDER BY sale_date ASC
            )) / LAG(sale_amount, 1, 0) OVER (
                PARTITION BY product_id 
                ORDER BY sale_date ASC
            ) * 100, 2
        )
    END AS change_rate_percent,
    -- 标记是否增长
    CASE 
        WHEN sale_amount > LAG(sale_amount, 1, 0) OVER (
            PARTITION BY product_id 
            ORDER BY sale_date ASC
        ) THEN '增长'
        WHEN sale_amount < LAG(sale_amount, 1, 0) OVER (
            PARTITION BY product_id 
            ORDER BY sale_date ASC
        ) THEN '下降'
        ELSE '持平'
    END AS change_trend
FROM daily_sales
ORDER BY product_id, sale_date ASC;

边界情况处理

使用LAG函数时需要注意几个常见的边界情况:

  • 首行数据没有前序行,此时如果不设置default_value,LAG会返回NULL,对比时需要根据业务需求设置合理的默认值,比如数值类默认0,状态类默认空字符串
  • 分组内排序必须明确,否则LAG获取的前序行可能不符合预期,比如按时间排序时一定要明确升序还是降序,避免拿到错误的前序数据
  • 如果数据存在重复的时间或排序值,LAG会按照数据库的实际执行顺序取值,必要时可以增加次要排序字段保证顺序稳定

性能注意事项

LAG函数作为窗口函数,执行时会对分组和排序的数据做内存计算,当数据量较大时,建议给PARTITION BYORDER BY涉及的字段建立联合索引,比如上述用户状态表的(user_id, change_time)索引,可以大幅提升查询性能。另外尽量避免在窗口函数内做复杂的表达式计算,提前处理好字段可以减少运行时的计算开销。

SQLLAG函数数据对比报表标记新旧值修改时间:2026-06-19 22:09:21

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