目录
一、核心概念
二、典型应用场景
三、实现步骤与SQL示例
场景
目标
步骤
分析
结果
四、核心原理解释
1. 核心原理:相邻比较
2. 去重的本质
3. 与传统方法的对比
4 类别理解
五、如何应对复杂场景?
1. 多字段断点检测
2. 时间窗口断点
四、小结
一、核心概念
断点去重 是一种处理 连续重复数据 的技术,常用于时间序列或状态日志中。其核心目标是:
- 检测变化点(Gaps):标记值发生变化的边界点。
-
保留断点记录:将连续相同值的记录合并,只保留断点处的记录。
-
连续重复数据(如设备状态日志)的特点是:相邻记录的值可能长时间保持不变,仅在特定时间点发生突变。例如,设备状态从“正常”变为“故障”,再恢复为“正常”。
-
传统分组去重(如
ROW_NUMBER()
)的局限在于:它们基于固定分组字段(如user_id
),但无法捕捉到连续重复区间内的动态变化。
二、典型应用场景
-
在物联网、日志分析等场景中,用户往往只关心状态变化的时刻(如设备何时故障、用户何时点击按钮),而非所有重复记录。
-
例如:设备连续上报多次“正常”状态,只有第一次“正常”和第一次“故障”的记录是真正有价值的信息。
设备状态监控
- 合并设备连续相同的运行状态记录。
用户行为分析
- 合并用户连续访问同一页面的时间段。
传感器数据清洗
- 合并温度/湿度等连续相同的采样值。
三、实现步骤与SQL示例
场景
传感器采集的温度数据中,存在连续重复的值,需仅在数值变化时保留记录(例如:温度从 25°C 变为 26°C 时记录一次)。
原始数据表 sensor_data
:
timestamp | temperature | |
---|---|---|
2023-01-01 08:00:00 | 25 | |
2023-01-01 08:05:00 | 25 | ← 连续重复 |
2023-01-01 08:10:00 | 26 | ← 断点(值变化) |
2023-01-01 08:15:00 | 26 | ← 连续重复 |
目标
保留断点处的记录(即温度变化时的第一条)。
步骤
WITH marked_data AS (
SELECT *,
LAG(temperature) OVER (ORDER BY timestamp) AS prev_temp
FROM sensor_data
)
SELECT timestamp, temperature
FROM marked_data
WHERE temperature != prev_temp OR prev_temp IS NULL; -- 第一条记录无条件保留
分析
-
LAG(temperature)
获取前一行的温度值。 -
若当前温度与前一行的温度不同(或为第一条记录),则保留该行。
-
最终仅保留值变化的断点记录。
结果
timestamp | temperature |
---|---|
2023-01-01 08:00:00 | 25 |
2023-01-01 08:10:00 | 26 |
四、核心原理解释
1. 核心原理:相邻比较
-
LAG(status)
:获取当前行的前一条记录的status
值。 -
status <> prev_status
:如果当前行的状态与前一行不同,说明此处发生了状态变化,即断点。 -
prev_status IS NULL
:保留第一条记录(因为它没有前一行,是初始状态)。
2. 去重的本质
-
通过筛选出所有断点记录(即状态变化的记录),隐式合并了连续的重复数据。
例如:
原始数据:OK → OK → Error → Error → OK
断点记录:OK(初始) → Error(变化) → OK(变化)
-
最终结果仅保留每个连续区间的起点,从而实现了去重。
3. 与传统方法的对比
方法 | 去重逻辑 | 适用场景 |
---|---|---|
DISTINCT | 完全相同的行去重 | 静态重复数据(如全表去重) |
ROW_NUMBER() | 按固定分组保留首条/末条 | 分组内重复(如用户最新操作) |
LAG() +比较 | 动态检测相邻记录的变化点 | 连续重复数据(如状态日志) |
4 类别理解
想象你在阅读一篇长篇小说,书中连续多页描述同一个场景(例如“主角在森林中行走”)。如果你只想标记场景变化的页码(例如“主角进入城堡”),你会:
-
逐页比较当前页和前一页的内容。
-
当发现内容变化时,记录当前页码。
这正是 LAG()
函数的思维逻辑:通过局部比较,找到全局变化点。
五、如何应对复杂场景?
1. 多字段断点检测
-
如果断点由多个字段共同决定(如同时检测
status
和temperature
),只需扩展比较条件:WHERE status <> prev_status OR temperature <> prev_temperature
2. 时间窗口断点
-
如果需忽略短暂的状态抖动(如状态持续不足5分钟不视为断点),可结合时间差过滤:
LAG(timestamp) OVER (...) AS prev_timestamp, WHERE timestamp - prev_timestamp > INTERVAL '5 minutes'
四、小结
通过本文的解析,读者可以深入理解断点去重的核心逻辑,掌握其SQL实现方法
其核心思想是:通过局部差异检测全局变化。通过 LAG()获取上一字段状态值与当前行值进行比较,判断是否相等进行去重判断,核心思路如下:
-
检测变化:利用
LAG()
比较相邻行差异。 -
保留断点记录:判断逻辑,current_value != lag_value