将动态 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
撇开使用动态 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