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

如何在SQL中计算每个唯一evt_type最新与次新记录的value差值?

问题描述

现有数据表events结构及数据如下:

evt_type | value      | time
  ------------+------------+--------------------
   2          | 5          | 2015-05-09 12:42:00
   4          | -42        | 2015-05-09 13:19:57
   2          | 2          | 2015-05-09 14:48:30
   2          | 7          | 2015-05-09 12:54:39
   3          | 16         | 2015-05-09 13:19:57
   3          | 20         | 2015-05-09 15:01:09

需求:计算每个拥有至少2条记录的evt_type,其最新与次新记录的value列差值。

目前已写出筛选并排序的查询:

SELECT *
FROM events
WHERE evt_type IN (
    SELECT evt_type
    FROM events
    GROUP BY evt_type
    HAVING COUNT(*) >= 2
)
ORDER BY evt_type ASC, time DESC

返回结果:

evt_type   value   time
+----------+------+---------------------+
| 2        |  2   | 2015-05-09 14:48:30 |
| 2        |  7   | 2015-05-09 12:54:39 |
| 2        |  5   | 2015-05-09 12:42:00 |
| 3        | 20   | 2015-05-09 15:01:09 |
| 3        | 16   | 2015-05-09 13:19:57 |
+----------+------+---------------------+

提问:如何获取每个唯一evt_type前两条记录的value差值?能否基于现有查询作为子查询实现,还是需要其他方法?


解决方案

方法一:使用窗口函数(推荐)

利用ROW_NUMBER()给每个evt_type下的记录按时间倒序编号,筛选前两条后计算差值,这是现代数据库最高效简洁的方式:

WITH ranked_events AS (
    SELECT 
        evt_type,
        value,
        ROW_NUMBER() OVER (PARTITION BY evt_type ORDER BY time DESC) AS rn
    FROM events
    WHERE evt_type IN (
        SELECT evt_type FROM events GROUP BY evt_type HAVING COUNT(*) >= 2
    )
)
SELECT 
    evt_type,
    MAX(CASE WHEN rn = 1 THEN value END) - MAX(CASE WHEN rn = 2 THEN value END) AS value_diff
FROM ranked_events
WHERE rn <= 2
GROUP BY evt_type;

执行结果:

evt_type | value_diff
----------+------------
        2 |         -5
        3 |          4

方法二:基于现有查询作为子查询实现

可以把你写的排序查询作为子查询,通过自关联获取最新和次新值:

SELECT 
    t1.evt_type,
    t1.value - t2.value AS value_diff
FROM (
    SELECT 
        evt_type, 
        value, 
        ROW_NUMBER() OVER (PARTITION BY evt_type ORDER BY time DESC) AS rn
    FROM events
    WHERE evt_type IN (SELECT evt_type FROM events GROUP BY evt_type HAVING COUNT(*) >= 2)
) t1
JOIN (
    SELECT 
        evt_type, 
        value, 
        ROW_NUMBER() OVER (PARTITION BY evt_type ORDER BY time DESC) AS rn
    FROM events
    WHERE evt_type IN (SELECT evt_type FROM events GROUP BY evt_type HAVING COUNT(*) >= 2)
) t2 
ON t1.evt_type = t2.evt_type 
AND t1.rn = 1 
AND t2.rn = 2;

更简化的写法可以用LAG()窗口函数,直接获取上一条(次新)的value:

WITH ranked_events AS (
    SELECT 
        evt_type,
        value,
        LAG(value) OVER (PARTITION BY evt_type ORDER BY time DESC) AS prev_value,
        ROW_NUMBER() OVER (PARTITION BY evt_type ORDER BY time DESC) AS rn
    FROM events
    WHERE evt_type IN (SELECT evt_type FROM events GROUP BY evt_type HAVING COUNT(*) >= 2)
)
SELECT evt_type, value - prev_value AS value_diff
FROM ranked_events
WHERE rn = 1;

方法三:兼容旧版本数据库(无窗口函数支持)

如果你的数据库不支持窗口函数(如MySQL 5.x),可以用关联子查询:

SELECT 
    e1.evt_type,
    e1.value - e2.value AS value_diff
FROM events e1
JOIN events e2 ON e1.evt_type = e2.evt_type
WHERE 
    -- 获取当前evt_type的最新时间记录
    e1.time = (SELECT MAX(time) FROM events WHERE evt_type = e1.evt_type)
    -- 获取当前evt_type的次新时间记录
    AND e2.time = (SELECT MAX(time) FROM events WHERE evt_type = e1.evt_type AND time < e1.time)
    -- 过滤出至少2条记录的evt_type
    AND (SELECT COUNT(*) FROM events WHERE evt_type = e1.evt_type) >= 2;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 06:10:01