将动态 SQL 输出变量分配给局部变量

Assigning Dynamic SQL Output Variables to Local Variables

撇开使用动态 SQL 的注意事项不谈,我想知道我是否可以动态地声明我想从动态 SQL 语句中为给定输出变量分配值的局部变量。

希望我说得足够好。这是一些代码以及我遇到问题的地方。我有一个带有多个 OUTPUT 参数的存储过程,如下所示:

ALTER PROCEDURE [dbo].[mngi_psi_paginate]

 @image_desc_1          VARCHAR(50) OUTPUT
,@image_desc_2          VARCHAR(50) OUTPUT
,@image_desc_3          VARCHAR(50) OUTPUT
,@image_desc_4          VARCHAR(50) OUTPUT
,@image_desc_5          VARCHAR(50) OUTPUT
,@image_desc_6          VARCHAR(50) OUTPUT
,@image_desc_7          VARCHAR(50) OUTPUT
,@image_desc_8          VARCHAR(50) OUTPUT
,@image_desc_9          VARCHAR(50) OUTPUT
,@image_desc_10         VARCHAR(50) OUTPUT

...

共有40个OUTPUT参数。我将允许用户翻阅未知数量的图像,一次翻阅 10 张图像。对于每张图像,我需要 4 个数据字段,但一次可能有 10 条记录,我宁愿不对所有 40 个变量赋值进行硬编码。

我意识到应该有更好的方法来做到这一点,但接收应用程序不是网络浏览器,所以不幸的是,这就是我必须使用的。

我还做了一些其他事情:确定图片总数、页数以及将在页面上显示的图片数量。

一旦我弄清楚哪组图像属于给定页面,我就会将它们放入临时 table。

CREATE TABLE #images_page   
    (primary_key INT IDENTITY(1,1) NOT NULL
    ,image_id VARCHAR(36)
    ,image_path VARCHAR(400)
    ,image_type VARCHAR(5)
    ,image_desc VARCHAR(MAX)
    )

INSERT INTO     #images_page
SELECT           image_id
                ,image_path
                ,image_type
                ,image_desc
FROM            @images_set
WHERE           primary_key >= @image_start 
AND             primary_key <= @image_end

然后我构建一个字符串来执行一个动态的SQL语句,它全部包裹在一个WHILE循环中,希望能够只分配有相应记录的变量(例如@ image_desc_1 从第 #1 行获取数据,@image_desc_2 从第 # 行获取数据,等等

SELECT  @image_page_total = COUNT(*)
FROM    #images_page

DECLARE      @row_counter INT
            ,@loop_counter INT

SET @loop_counter = @image_page_total
SET @row_counter = 1

WHILE
    @loop_counter > 0
AND @row_counter <= @loop_counter
BEGIN

-- Dynamically assign variables
DECLARE @sql        NVARCHAR(MAX)
DECLARE @params     NVARCHAR(MAX)
DECLARE @assign     NVARCHAR(MAX)
SELECT  @sql =      'SELECT  @image_desc = image_desc ' + 
                    '@image_path = image_path,' +
                    '@image_type = image_type,' +
                    '@image_comments = image_comments' +
                    'FROM #images_page ' + 
                    'WHERE primary_key = ' + CAST(@row_counter AS VARCHAR)

SELECT  @params =   '@image_desc varchar(50) OUTPUT'
SELECT  @assign =   '@image_desc = @image_desc_' + CAST(@row_counter AS VARCHAR) + ' OUTPUT'

--This line works because I've simply typed out the variable name
EXEC sp_executesql @sql, @params, @image_desc = @image_desc_1 OUTPUT
--This line does not work because I am trying to append the '_1' to   @image_desc
EXEC sp_executesql @sql, @params, @assign

SET @row_counter = @row_counter + 1

END

第一行 EXEC sp_executesql 有效,因为这是它应该的工作方式,也是您在所有文档和示例中看到的方式。第二个 EXEC sp_executesql 是我真正希望能够做到的,但我似乎看不到实现它的方法。

有没有办法按照我尝试的方式完成此操作?

我愿意接受不需要我对变量赋值进行硬编码的替代方法。

提前感谢您的帮助!

我不认为你需要的是完全可能的,但也许这会引导你朝着正确的方向前进。它并没有完全删除引用所有 40 个变量的行为是代码,但您不必对变量赋值进行硬编码。

我用了我自己的例子。我已经根据@I 的值设置了@T1 或@T2 的值。所以如果@I = 1,那么@T1 将被设置为 'SET AT RUNTIME'。如果@I = 2,那么@T2 将被设置为 'SET AT RUNTIME'。您需要将所有 40 个变量传递给动态查询。

DECLARE @T1     INT,
        @T2     INT,
        @I      VARCHAR(10) = '2',
        @SQL    NVARCHAR(MAX);

SET @SQL = 'SET @T' + @I + ' = ''SET AT RUNTIME'''
EXEC sp_executesql @SQL, N'@T1 INT OUT, @T2 INT OUT', @T1 OUT, @T2 OUT

SELECT @T1, @T2

希望对您有所帮助

似乎 Spock 是正确的,我无法动态计算我想从动态 SQL 传递出去的变量。如有不妥请大家指正

因为我只有 10 组变量要处理,所以我接受了它并为每组写了一个 IF 语句。同样,如果有人有更好的选择,我愿意接受任何事情。

郑重声明,这是我所做的并且有效:

SET @loop_counter = @image_page_total
SET @row_counter = 1

WHILE
    @loop_counter > 0
AND @row_counter <= @loop_counter
BEGIN

-- Dynamically assign variables
DECLARE @sql        NVARCHAR(MAX)
DECLARE @params     NVARCHAR(MAX)
DECLARE @assign     NVARCHAR(MAX)
SELECT  @sql =      'SELECT @image_path = image_path, ' +
                    '@image_type = image_type, ' +
                    '@image_desc = image_desc, ' +
                    '@image_comments = image_comments ' +
                    'FROM #images_page ' + 
                    'WHERE primary_key = ' + CAST(@row_counter AS VARCHAR)

SELECT  @params =   '@image_path VARCHAR(400) OUTPUT, @image_type VARCHAR(5) OUTPUT, @image_desc VARCHAR(50) OUTPUT, @image_comments VARCHAR(MAX) OUTPUT'

IF @row_counter = 1 EXEC sp_executesql @sql, @params, @image_type_1 OUTPUT, @image_type_1 OUTPUT, @image_desc_1 OUTPUT, @image_comments_1 OUTPUT
IF @row_counter = 2 EXEC sp_executesql @sql, @params, @image_type_2 OUTPUT, @image_type_2 OUTPUT, @image_desc_2 OUTPUT, @image_comments_2 OUTPUT
IF @row_counter = 3 EXEC sp_executesql @sql, @params, @image_type_3 OUTPUT, @image_type_3 OUTPUT, @image_desc_3 OUTPUT, @image_comments_3 OUTPUT
IF @row_counter = 4 EXEC sp_executesql @sql, @params, @image_type_4 OUTPUT, @image_type_4 OUTPUT, @image_desc_4 OUTPUT, @image_comments_4 OUTPUT
IF @row_counter = 5 EXEC sp_executesql @sql, @params, @image_type_5 OUTPUT, @image_type_5 OUTPUT, @image_desc_5 OUTPUT, @image_comments_5 OUTPUT
IF @row_counter = 6 EXEC sp_executesql @sql, @params, @image_type_6 OUTPUT, @image_type_6 OUTPUT, @image_desc_6 OUTPUT, @image_comments_6 OUTPUT
IF @row_counter = 7 EXEC sp_executesql @sql, @params, @image_type_7 OUTPUT, @image_type_7 OUTPUT, @image_desc_7 OUTPUT, @image_comments_7 OUTPUT
IF @row_counter = 8 EXEC sp_executesql @sql, @params, @image_type_8 OUTPUT, @image_type_8 OUTPUT, @image_desc_8 OUTPUT, @image_comments_8 OUTPUT
IF @row_counter = 9 EXEC sp_executesql @sql, @params, @image_type_9 OUTPUT, @image_type_9 OUTPUT, @image_desc_9 OUTPUT, @image_comments_9 OUTPUT
IF @row_counter = 10 EXEC sp_executesql @sql, @params, @image_type_10 OUTPUT, @image_type_10 OUTPUT, @image_desc_10 OUTPUT, @image_comments_10 OUTPUT

SET @row_counter = @row_counter + 1

END