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

时间:2015-01-17 08:02:07

标签: sql-server sql-server-2008

抛开使用动态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个变量赋值进行硬编码。

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

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

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

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是我真正希望能够做到的,但我似乎无法看到它的方法。

有没有办法以我尝试的方式实现这一目标?

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

提前感谢您的任何帮助!

2 个答案:

答案 0 :(得分:2)

我认为你的需要完全不可能,但也许这会引导你朝着正确的方向前进。它没有完全删除契约来引用所有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

希望有所帮助

答案 1 :(得分:0)

似乎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