SQL Server中WHILE循环实现变量名递减的问题
解决SQL Server WHILE循环中动态获取递减变量值的问题
问题分析
你当前通过CONCAT('@chk', @task_total)生成的是字符串(比如'@chk3'),而非变量@chk3的实际值,因此需要一种方式根据@task_total的数值匹配到对应变量的内容。
解决方案
方法1:使用CASE表达式(推荐,适合变量数量固定的场景)
由于你的变量仅包含@chk1、@chk2、@chk3三个,直接用CASE表达式根据@task_total的数值返回对应变量的值即可,无需动态拼接变量名,简单高效。
修改后的代码如下:
DECLARE @chk1 VARCHAR(3), @chk2 VARCHAR(3), @chk3 VARCHAR(3) DECLARE @task_total INT, @tasknum INT, @next_evtcode VARCHAR(10), @ot_desc VARCHAR(100) DECLARE @ot_dates VARCHAR(10), @ot_object VARCHAR(50), @ot_createdby VARCHAR(50), @tasklist VARCHAR(50) SET @chk1 = 'YES' SET @chk2 = 'YES' SET @chk3 = 'NO' SELECT @task_total = COUNT(*) FROM R5TASKCHECKLISTS WHERE TCH_TASK = @tasknum -- 循环从@task_total开始,直到1(无@chk0变量,避免无效循环) WHILE @task_total >= 1 BEGIN DECLARE @chk_current VARCHAR(3) -- 通过CASE匹配对应变量的值 SET @chk_current = CASE @task_total WHEN 3 THEN @chk3 WHEN 2 THEN @chk2 WHEN 1 THEN @chk1 END INSERT INTO R5TRACKINGDATA (TKD_TRANS, TKD_TRACKDATE, TKD_PROMPTDATA1, TKD_PROMPTDATA2, TKD_PROMPTDATA3, TKD_PROMPTDATA4, TKD_PROMPTDATA5, TKD_PROMPTDATA6, TKD_PROMPTDATA7, TKD_PROMPTDATA8, TKD_PROMPTDATA9, TKD_PROMPTDATA10, TKD_PROMPTDATA11, TKD_PROMPTDATA12, TKD_PROMPTDATA13, TKD_PROMPTDATA14, TKD_PROMPTDATA15) VALUES ('AO01', --TKD_TRANS GETDATE(), @next_evtcode, -- EVT_CODE @ot_desc, -- EVT_DESC @ot_dates, -- EVT_DATE (dd/mm/yyyy) '100', -- EVT_MRC '282', -- EVT_ORG 'PMM', -- EVT_JOBTYPE @ot_dates, -- EVT_REPORTED (dd/mm/yyyy) @ot_object, -- EVT_OBJECT '282', -- EVT_OBJECT_ORG @ot_dates, -- EVT_TARGET (dd/mm/yyyy) @ot_dates, -- EVT_COMPLETED (dd/mm/yyyy) @ot_createdby, -- EVT_ENTEREDBY @tasklist, -- TSK_CODE @task_total, -- ACK_SEQUENCE @chk_current -- ACK_NO_YES (NO or YES) ) SET @task_total = @task_total - 1; END
方法2:使用动态SQL(适合变量数量不固定的场景)
如果后续可能新增更多@chkN类型的变量,可以用动态SQL拼接执行语句,注意变量传递的处理:
DECLARE @chk1 VARCHAR(3), @chk2 VARCHAR(3), @chk3 VARCHAR(3) DECLARE @task_total INT, @tasknum INT, @next_evtcode VARCHAR(10), @ot_desc VARCHAR(100) DECLARE @ot_dates VARCHAR(10), @ot_object VARCHAR(50), @ot_createdby VARCHAR(50), @tasklist VARCHAR(50) DECLARE @sql NVARCHAR(MAX) SET @chk1 = 'YES' SET @chk2 = 'YES' SET @chk3 = 'NO' SELECT @task_total = COUNT(*) FROM R5TASKCHECKLISTS WHERE TCH_TASK = @tasknum WHILE @task_total >= 1 BEGIN -- 拼接动态SQL语句,代入对应变量值 SET @sql = N' INSERT INTO R5TRACKINGDATA (TKD_TRANS, TKD_TRACKDATE, TKD_PROMPTDATA1, TKD_PROMPTDATA2, TKD_PROMPTDATA3, TKD_PROMPTDATA4, TKD_PROMPTDATA5, TKD_PROMPTDATA6, TKD_PROMPTDATA7, TKD_PROMPTDATA8, TKD_PROMPTDATA9, TKD_PROMPTDATA10, TKD_PROMPTDATA11, TKD_PROMPTDATA12, TKD_PROMPTDATA13, TKD_PROMPTDATA14, TKD_PROMPTDATA15) VALUES (''AO01'', --TKD_TRANS GETDATE(), @next_evtcode, -- EVT_CODE @ot_desc, -- EVT_DESC @ot_dates, -- EVT_DATE (dd/mm/yyyy) ''100'', -- EVT_MRC ''282'', -- EVT_ORG ''PMM'', -- EVT_JOBTYPE @ot_dates, -- EVT_REPORTED (dd/mm/yyyy) @ot_object, -- EVT_OBJECT ''282'', -- EVT_OBJECT_ORG @ot_dates, -- EVT_TARGET (dd/mm/yyyy) @ot_dates, -- EVT_COMPLETED (dd/mm/yyyy) @ot_createdby, -- EVT_ENTEREDBY @tasklist, -- TSK_CODE ' + CAST(@task_total AS NVARCHAR) + ', -- ACK_SEQUENCE ' + CASE @task_total WHEN 3 THEN '''NO''' WHEN 2 THEN '''YES''' WHEN 1 THEN '''YES''' END + ' -- ACK_NO_YES (NO or YES) )' -- 执行动态SQL,传递外部变量 EXEC sp_executesql @sql, N'@next_evtcode VARCHAR(10), @ot_desc VARCHAR(100), @ot_dates VARCHAR(10), @ot_object VARCHAR(50), @ot_createdby VARCHAR(50), @tasklist VARCHAR(50)', @next_evtcode = @next_evtcode, @ot_desc = @ot_desc, @ot_dates = @ot_dates, @ot_object = @ot_object, @ot_createdby = @ot_createdby, @tasklist = @tasklist SET @task_total = @task_total - 1; END
注意事项
- 方法1更简洁,性能更优,无需动态编译SQL,完全适配你当前的固定变量场景。
- 原代码循环条件
@task_total >=0会触发无对应变量的无效循环,已调整为@task_total >=1。
内容的提问来源于stack exchange,提问作者Pau
相关产品推荐
相关产品推荐

