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

如何在TSQL中使用窗口函数实现On Balance Volume(OBV)计算

TSQL 计算On Balance Volume(能量潮指标)实现方案

你需要的迭代累计逻辑在TSQL中可以实现,以下是两种常用方案:

方案1:窗口函数累加实现(推荐,SQL Server 2012+支持,性能最优)

核心思路是先给每行计算Volume的加减系数,再通过开窗累加得到最终的c值,无需递归,适合大数据量场景:

-- 测试数据,实际使用替换为你的业务表
WITH SourceData AS (
    SELECT a = 1, b = '2020-01', Volume = 10 UNION ALL
    SELECT a = 2, b = '2020-02', Volume = 20 UNION ALL
    SELECT a = 5, b = '2020-03', Volume = 40 UNION ALL
    SELECT a = 3, b = '2020-04', Volume = 30 UNION ALL
    SELECT a = 1, b = '2020-05', Volume = 10
),
-- 计算每行的加减系数
VolumeCoeff AS (
    SELECT *,
        CASE
            -- 首行系数为0,对应初始值0
            WHEN LAG(a,1) OVER(ORDER BY b ASC) IS NULL THEN 0
            -- 当期a大于上期,系数为+1
            WHEN LAG(a,1) OVER(ORDER BY b ASC) < a THEN 1
            -- 当期a小于上期,系数为-1
            WHEN LAG(a,1) OVER(ORDER BY b ASC) > a THEN -1
            -- 若a相等可自行调整规则,默认系数为0(不累加)
            ELSE 0
        END AS coeff
    FROM SourceData
)
SELECT a, b, Volume,
    -- 按时间顺序累加系数*Volume得到c值
    SUM(coeff * Volume) OVER(ORDER BY b ASC ROWS UNBOUNDED PRECEDING) AS c
FROM VolumeCoeff
ORDER BY b ASC

运行结果和你给出的预期完全一致。

方案2:递归CTE实现(兼容所有TSQL版本)

如果你的SQL Server版本低于2012,可以用递归CTE模拟逐行迭代的逻辑,和你提到的其他语言用变量存储上一行值的逻辑一致:

-- 测试数据,实际使用替换为你的业务表
WITH SourceData AS (
    SELECT a = 1, b = '2020-01', Volume = 10 UNION ALL
    SELECT a = 2, b = '2020-02', Volume = 20 UNION ALL
    SELECT a = 5, b = '2020-03', Volume = 40 UNION ALL
    SELECT a = 3, b = '2020-04', Volume = 30 UNION ALL
    SELECT a = 1, b = '2020-05', Volume = 10
),
-- 按时间排序生成行号,方便定位上一行
OrderedData AS (
    SELECT *, ROW_NUMBER() OVER(ORDER BY b ASC) AS rn
    FROM SourceData
),
-- 递归计算c值
OBV_Calc AS (
    -- 锚点:首行c初始值为0
    SELECT a, b, Volume, rn, c = 0
    FROM OrderedData
    WHERE rn = 1
    UNION ALL
    -- 递归逐行计算
    SELECT curr.a, curr.b, curr.Volume, curr.rn,
        CASE
            WHEN prev.a < curr.a THEN prev.c + curr.Volume
            WHEN prev.a > curr.a THEN prev.c - curr.Volume
            ELSE prev.c
        END AS c
    FROM OBV_Calc prev
    INNER JOIN OrderedData curr ON curr.rn = prev.rn + 1
)
SELECT a, b, Volume, c
FROM OBV_Calc
ORDER BY rn
-- 数据量超过100行时需打开递归深度限制,0为不限制
-- OPTION (MAXRECURSION 0)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 04:06:02