You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SQL如何基于0和1切换的ping_result状态列分组取每组首条记录

需求说明

现有数据表包含date_time、id、name、ip、ping_result字段,其中ping_result取值为0或1,会随时间发生状态切换。
需求:针对指定id(示例为id=1的Mario),每次ping_result发生状态变更时,获取该状态序列的第一条记录。

原有代码问题

原有实现直接按ping_result分区生成行号,只会将所有ping_result=0和ping_result=1的记录各自分为一组,无法实现状态切换时重置分区计数的效果,因此只能拿到全局最新的0和1状态记录,无法匹配每次状态切换的需求。
原有代码如下:

WITH cte AS
(
    SELECT *, ROW_NUMBER() OVER (PARTITION BY ping_result ORDER BY [date_time] DESC) AS row_num
    FROM [table] where id = 1 
)
select * from cte WHERE row_num = 1
正确实现方案

通过相邻行状态对比+分组累加标记的方法即可实现需求,兼容所有支持窗口函数的数据库(MySQL 8.0+、PostgreSQL、SQL Server等),实现代码如下:

WITH step1 AS (
    -- 第一步:获取上一行的ping_result,用于对比状态是否变化
    SELECT *,
           LAG(ping_result) OVER (ORDER BY date_time ASC) AS prev_ping
    FROM [table]
    WHERE id = 1
),
step2 AS (
    -- 第二步:状态变化时打标记1,初始第一条记录也标记为1
    SELECT *,
           CASE WHEN ping_result != prev_ping OR prev_ping IS NULL THEN 1 ELSE 0 END AS is_change
    FROM step1
),
step3 AS (
    -- 第三步:累加标记生成连续状态分组ID,同一连续状态的group_id相同
    SELECT *,
           SUM(is_change) OVER (ORDER BY date_time ASC) AS group_id
    FROM step2
),
step4 AS (
    -- 第四步:每个分组内按时间排序,取第一条即为状态切换后的首条记录
    SELECT *,
           ROW_NUMBER() OVER (PARTITION BY group_id ORDER BY date_time ASC) AS row_num
    FROM step3
)
SELECT date_time, id, name, ip, ping_result
FROM step4
WHERE row_num = 1
ORDER BY date_time ASC;
输出示例

和需求预期一致,返回每次状态切换后的第一条记录:

date_timeidnameipping_result
2021-08-26 14:001Mario1.1.1.11
2021-08-26 14:101Mario1.1.1.10
2021-08-26 14:201Mario1.1.1.11

内容的提问来源于stack exchange,提问作者Ocean Airdrop

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 04:00:05