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

如何在T-SQL中循环遍历变量列表传入存储过程参数

月度变动值计算的两种实现方案

一、遍历已有日期表的逐行处理方案

如果已经有存储月度数据的表(比如名为date_list,包含year_month INT列),可以通过游标逐行读取连续月份对,调用你的存储过程:

-- 声明变量
DECLARE @current_month INT, @prev_month INT
DECLARE @date_cursor CURSOR

-- 初始化游标,按月份升序读取
SET @date_cursor = CURSOR FOR
SELECT year_month
FROM date_list
ORDER BY year_month

-- 读取第一个月份作为初始值
OPEN @date_cursor
FETCH NEXT FROM @date_cursor INTO @prev_month

-- 循环遍历后续月份,生成连续月份对并调用存储过程
WHILE @@FETCH_STATUS = 0
BEGIN
    FETCH NEXT FROM @date_cursor INTO @current_month
    IF @@FETCH_STATUS = 0
    BEGIN
        -- 替换为你的存储过程名称
        EXEC dbo.CalculateMonthChange 
            @start_month = @prev_month,
            @end_month = @current_month
        
        SET @prev_month = @current_month
    END
END

-- 清理游标
CLOSE @date_cursor
DEALLOCATE @date_cursor

二、无需依赖日期表:用DATEADD自动生成连续月份对

如果没有现成的日期表,可以通过递归CTE自动生成指定范围内的连续月份,再配对成前后月组合,批量处理(推荐这种方式,避免逐行遍历的性能损耗):

1. 自动生成月份对并调用存储过程

-- 定义需要处理的月份范围
DECLARE @start_year_month INT = 202301, @end_year_month INT = 202312

-- 递归CTE生成连续月份列表
;WITH MonthSeries AS (
    SELECT @start_year_month AS year_month
    UNION ALL
    SELECT 
        -- 将YYYYMM格式的INT转换为日期,加1个月后再转回INT格式
        CAST(FORMAT(DATEADD(MONTH, 1, CAST(CAST(year_month AS VARCHAR(6)) + '01' AS DATE)), 'yyyyMM') AS INT)
    FROM MonthSeries
    WHERE year_month < @end_year_month
)
-- 生成前后月配对并存储到临时表
SELECT 
    ms.year_month AS start_month,
    ms_next.year_month AS end_month
INTO #TempMonthPairs
FROM MonthSeries ms
JOIN MonthSeries ms_next 
    ON ms_next.year_month = CAST(FORMAT(DATEADD(MONTH, 1, CAST(CAST(ms.year_month AS VARCHAR(6)) + '01' AS DATE)), 'yyyyMM') AS INT)

-- 遍历临时表调用存储过程
DECLARE @start_month INT, @end_month INT
DECLARE @pair_cursor CURSOR

SET @pair_cursor = CURSOR FOR
SELECT start_month, end_month
FROM #TempMonthPairs
ORDER BY start_month

OPEN @pair_cursor
FETCH NEXT FROM @pair_cursor INTO @start_month, @end_month

WHILE @@FETCH_STATUS = 0
BEGIN
    EXEC dbo.CalculateMonthChange 
        @start_month = @start_month,
        @end_month = @end_month
    
    FETCH NEXT FROM @pair_cursor INTO @start_month, @end_month
END

-- 清理资源
CLOSE @pair_cursor
DEALLOCATE @pair_cursor
DROP TABLE #TempMonthPairs

2. 更高效的批量计算(替代存储过程调用)

如果可以将存储过程的计算逻辑整合到SQL语句中,建议直接批量计算并插入结果,避免循环调用存储过程的性能开销:

DECLARE @start_year_month INT = 202301, @end_year_month INT = 202312

;WITH MonthSeries AS (
    SELECT @start_year_month AS year_month
    UNION ALL
    SELECT 
        CAST(FORMAT(DATEADD(MONTH, 1, CAST(CAST(year_month AS VARCHAR(6)) + '01' AS DATE)), 'yyyyMM') AS INT)
    FROM MonthSeries
    WHERE year_month < @end_year_month
),
MonthPairs AS (
    SELECT 
        ms.year_month AS start_month,
        ms_next.year_month AS end_month
    FROM MonthSeries ms
    JOIN MonthSeries ms_next 
        ON ms_next.year_month = CAST(FORMAT(DATEADD(MONTH, 1, CAST(CAST(ms.year_month AS VARCHAR(6)) + '01' AS DATE)), 'yyyyMM') AS INT)
),
-- 假设底层数据是amount_table,包含year_month和amount列
AmountData AS (
    SELECT year_month, amount
    FROM amount_table
    WHERE year_month BETWEEN @start_year_month AND @end_year_month
)
-- 直接计算变动值并插入预创建的目标表
INSERT INTO target_change_table (start_month, end_month, amount_change)
SELECT 
    mp.start_month,
    mp.end_month,
    ad_end.amount - ad_start.amount AS amount_change
FROM MonthPairs mp
JOIN AmountData ad_start ON ad_start.year_month = mp.start_month
JOIN AmountData ad_end ON ad_end.year_month = mp.end_month

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 08:52:50