如何使用每行生成的变量更新 SQL 表?

问题描述 投票:0回答:1

我有一个包含 4 列的表:Project、ScenarioStart、ScenarioEnd 和 TimePeriods。

TimePeriods 一开始总是空白,因为这是我需要填充项目所有适用时间段的字符串(包括开始和结束)。

所有时间段的格式均为 yyyyMm

例如

Project   ScenarioStart    ScenarioEnd   TimePeriods
1         2024M9           2025M3        
2         2024M6           2024M10

我现在需要的是使用包含每行所有适用期间的文本字符串来更新表。 (我正在使用管道分离)

所以第 1 行将是 '2024M9|2024M10|2024M11|2024M12|2025M1|2025M2|2025M3'

第 2 行应为“2024M6|2024M7|2024M8|2024M9|2024M10”

我已经有一个生成字符串的工作代码,但它有两个问题:

  1. 它仅适用于固定的开始和结束值,而不是读取每个数据行并使用现有列的开始和结束值。
  2. 它当前只是生成字符串作为变量,而不是用值更新表。

生成字符串的代码如下。 有人可以帮我将其转换为表中每一行的更新吗?

-- Create the variables to hold Start- and End-Period, and the blank Period List --
-- Currently only works if hard-coded, but should read the table cells)

declare @sScenarioStart nvarchar(10) = '2024M1',
        @sScenarioEnd nvarchar(10) = '2026M3',
        @SplitPeriods nvarchar(max) = ''

----------------------------------------------------------------
-- Create a list of valid time references for this submission --
----------------------------------------------------------------
Declare @sCounterTime nvarchar(10) = @sScenarioStart,
        @sCounterYear nvarchar(4) = substring(@sScenarioStart,1,4),
        @sCounterMonth nvarchar(4) = substring(@sScenarioStart,6,len(@sScenarioStart)-5)

        print 'Counter Time: ' + @sCounterTime + 'Counter Year: ' + @sCounterYear + 'Counter Month: ' + @sCounterMonth

-- Generate the comma-sparated list of time periods --
While @sCounterTime <> @sScenarioEnd
    BEGIN
        -- Add the initial Time Period to the output string
        set @SplitPeriods = @SplitPeriods + @sCounterTime + '|'

        -- If Current month is December then +1 the year and reset the month back to 1
        set @sCounterYear =     case @sCounterMonth
                                    when 12 then @sCounterYear + 1
                                    else @sCounterYear
                                end
        
        set @sCounterMonth =    case @sCounterMonth
                                    when 12 then 1
                                    else @sCounterMonth + 1
                                end

        -- Move the Time Period forward
        set @sCounterTime = @sCounterYear + 'M' + @sCounterMonth

    END     -- End of BEGIN statement

-- Add the final Time Period to the string
set @SplitPeriods = @SplitPeriods + @sCounterTime

-- TESTING: Output the final string
print 'Final Period String: ' + @SplitPeriods
            

该脚本的输出是:

计数器时间:2024M1计数器年份:2024计数器月份:1

最终周期字符串:2024M1|2024M2|2024M3|2024M4|2024M5|2024M6|2024M7|2024M8|2024M9|2024M10|2024M11|2024M12|2025M1|2025M2|2025M3|2025M4 |2025M5|2025M6|2025M7|2025M8|2025M9|2025M10|2025M11 |2025M12|2026M1|2026M2|2026M3

这两个输出都是正确的,但需要在每一行的 TimePeriods 列中更新第二个输出。

谢谢

sql variables sql-update
1个回答
0
投票
CREATE TABLE Example 
(
    Project VARCHAR(512),
    ScenarioStart   VARCHAR(512),
    ScenarioEnd VARCHAR(512),
    TimePeriods VARCHAR(512)
);

INSERT INTO Example (Project, ScenarioStart, ScenarioEnd) VALUES
    ('1', '2024M9', '2025M3'),
    ('2', '2024M6', '2024M10');

SELECT * FROM Example;

-- Recursive CTE to generate a list of months within the date range:
WITH Months AS (
    SELECT Example.Project, Example.ScenarioStart, Example.ScenarioEnd, CONVERT(DATE, DATEADD(D, -(DAY(CONVERT(Date,  Substring(ScenarioStart,1,4) + '-' + Substring(ScenarioStart,6,2) + '-1'))) + 1, CONVERT(Date,  Substring(ScenarioStart,1,4) + '-' + Substring(ScenarioStart,6,2) + '-1'))) [MonthDate]
    FROM Example
    UNION ALL
    SELECT Example.Project, Example.ScenarioStart, Example.ScenarioEnd, DATEADD(M, 1, MonthDate)
    FROM Months   
    INNER JOIN Example on Example.Project=Months.Project
    WHERE MonthDate <= DATEADD(M, -1, CONVERT(Date,Substring(Example.ScenarioEnd,1,4) + '-' + Substring(Example.ScenarioEnd,6,2) + '-1'))
)
UPDATE Example
  SET Example.TimePeriods=t.TimePeriods
FROM Example E
INNER JOIN
(
  SELECT Project, STRING_AGG(CAST(Year(MONTHDATE)  as Varchar(4))+'M'+Cast(Month(Monthdate) as varchar(2)), '|') as TimePeriods 
  FROM Months
  GROUP BY Project 
) t
ON E.Project=t.Project

SELECT * FROM Example;

小提琴

项目 场景开始 场景结束 时间段
1 2024M9 2025M3 2024M9│2024M10│2024M11│2024M12│2025M1│2025M2│2025M3
2 2024M6 2024M10 2024M6│2024M7│2024M8│2024M9│2024M10
© www.soinside.com 2019 - 2024. All rights reserved.