如何在 sql 服务器中执行动态创建的查询
How to execute Dynamically created query in sql server
我编写了一个存储过程,其中我编写了一个查询以获取 userid
。每个 userid
都有一个单独的数据库。因此,我正在尝试 运行 一个 select 查询,该查询基于循环中从我之前的 select 查询中获得的此用户 ID。
我正在尝试将此 select 查询中的列分配给声明的变量并进一步使用它们。但是我不明白如何将这些分配给变量,因为我收到错误
USE DATABASE1
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [User].[update_client_details]
AS
DECLARE
@clientdata CURSOR,
@clientid INT,
@SQL VARCHAR(2000),
@uid INT
@isactive INT,
@createdDate Date
BEGIN
SET @clientdata = CURSOR FOR
SELECT clientuserid FROM User.queen_client
OPEN @clientdata
FETCH NEXT
FROM @clientdata INTO @clientid
WHILE @@FETCH_STATUS = 0
BEGIN
SET @SQL = N'SELECT @uid=userid, @isactive=isactive, @createdDate=createddate FROM ['+CAST(@clientid AS NVARCHAR(20))+'].User.queen_user';
EXEC (@SQL)
IF(@isactive = 1)
BEGIN
//do someting//
END
END
CLOSE @clientdata
DEALLOCATE @clientdata
END
如果执行存储过程,它正在执行并且不会停止。如果我强行停止执行,则会收到错误 "must declare the scalar variable "uid
"""
我试过的查询
EXEC sys.sp_executesql N'SELECT @uid=userid, @isactive=isactive, @createdDate=createddate FROM ' +QUOTENAME(@clientid)+'.QueenBase.queen_user', N'@clienid int, @uid int OUTPUT, @createDate date OUTPUT';
变量仅在声明的范围内持久存在。因此,以下两个批次都将失败:
DECLARE @I int = 1;
EXEC (N'SELECT @i;');
GO
EXEC (N'DECLARE @I int = 1;');
SELECT @i;
使用动态SQL时,不要使用EXEC(@SQL);
,使用sp_executesql
。然后你可以参数化语句。例如:
DECLARE @I int = 1;
EXEC sys.sp_executesql N'SELECT @i;', N'@i int', @i;
这个returns 1
。如果需要return一个值给外SQL作为参数,则需要使用OUTPUT
参数:
DECLARE @I int = 10;
DECLARE @O int;
EXEC sys.sp_executesql N'SELECT @O = @I / 2;', N'@I int, @O int OUTPUT', @I, @O OUTPUT;
SELECT @O;
这会将值 5
赋给变量 @O
(然后选中)。
此外,不要使用 N'...[' + @SomeVariable + N'] ...'
来注入动态值,这不是注入安全的。使用 QUOTENAME
: N'...' + QUOTENAME(@SomeVariable) + N'...'
补充说明。事实上,您需要做类似 N'FROM ['+CAST(@clientid AS NVARCHAR(20))+'].User.queen_user'
的事情表明存在严重的设计缺陷,但那是另一个话题。
如果您喜欢额外阅读,我在我的文章 Dos and Don'ts of Dynamic SQL 中介绍了很多您需要考虑的注意事项。
对于您的尝试,它不起作用,因为您对第一个参数(不是文字或变量)使用表达式,然后不传递您定义的任何参数:
DECLARE @SQL nvarchar(MAX) = N'SELECT @uid=userid, @isactive=isactive, @createdDate=createddate FROM ' +QUOTENAME(@clientid)+'.QueenBase.queen_user;';
EXEC sys.sp_executesql @SQL, N'@isactive int OUTPUT, @uid int OUTPUT, @createDate date OUTPUT', @isactive OUTPUT, @uid OUTPUT, @createDate OUTPUT;
我编写了一个存储过程,其中我编写了一个查询以获取 userid
。每个 userid
都有一个单独的数据库。因此,我正在尝试 运行 一个 select 查询,该查询基于循环中从我之前的 select 查询中获得的此用户 ID。
我正在尝试将此 select 查询中的列分配给声明的变量并进一步使用它们。但是我不明白如何将这些分配给变量,因为我收到错误
USE DATABASE1
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [User].[update_client_details]
AS
DECLARE
@clientdata CURSOR,
@clientid INT,
@SQL VARCHAR(2000),
@uid INT
@isactive INT,
@createdDate Date
BEGIN
SET @clientdata = CURSOR FOR
SELECT clientuserid FROM User.queen_client
OPEN @clientdata
FETCH NEXT
FROM @clientdata INTO @clientid
WHILE @@FETCH_STATUS = 0
BEGIN
SET @SQL = N'SELECT @uid=userid, @isactive=isactive, @createdDate=createddate FROM ['+CAST(@clientid AS NVARCHAR(20))+'].User.queen_user';
EXEC (@SQL)
IF(@isactive = 1)
BEGIN
//do someting//
END
END
CLOSE @clientdata
DEALLOCATE @clientdata
END
如果执行存储过程,它正在执行并且不会停止。如果我强行停止执行,则会收到错误 "must declare the scalar variable "uid
"""
我试过的查询
EXEC sys.sp_executesql N'SELECT @uid=userid, @isactive=isactive, @createdDate=createddate FROM ' +QUOTENAME(@clientid)+'.QueenBase.queen_user', N'@clienid int, @uid int OUTPUT, @createDate date OUTPUT';
变量仅在声明的范围内持久存在。因此,以下两个批次都将失败:
DECLARE @I int = 1;
EXEC (N'SELECT @i;');
GO
EXEC (N'DECLARE @I int = 1;');
SELECT @i;
使用动态SQL时,不要使用EXEC(@SQL);
,使用sp_executesql
。然后你可以参数化语句。例如:
DECLARE @I int = 1;
EXEC sys.sp_executesql N'SELECT @i;', N'@i int', @i;
这个returns 1
。如果需要return一个值给外SQL作为参数,则需要使用OUTPUT
参数:
DECLARE @I int = 10;
DECLARE @O int;
EXEC sys.sp_executesql N'SELECT @O = @I / 2;', N'@I int, @O int OUTPUT', @I, @O OUTPUT;
SELECT @O;
这会将值 5
赋给变量 @O
(然后选中)。
此外,不要使用 N'...[' + @SomeVariable + N'] ...'
来注入动态值,这不是注入安全的。使用 QUOTENAME
: N'...' + QUOTENAME(@SomeVariable) + N'...'
补充说明。事实上,您需要做类似 N'FROM ['+CAST(@clientid AS NVARCHAR(20))+'].User.queen_user'
的事情表明存在严重的设计缺陷,但那是另一个话题。
如果您喜欢额外阅读,我在我的文章 Dos and Don'ts of Dynamic SQL 中介绍了很多您需要考虑的注意事项。
对于您的尝试,它不起作用,因为您对第一个参数(不是文字或变量)使用表达式,然后不传递您定义的任何参数:
DECLARE @SQL nvarchar(MAX) = N'SELECT @uid=userid, @isactive=isactive, @createdDate=createddate FROM ' +QUOTENAME(@clientid)+'.QueenBase.queen_user;';
EXEC sys.sp_executesql @SQL, N'@isactive int OUTPUT, @uid int OUTPUT, @createDate date OUTPUT', @isactive OUTPUT, @uid OUTPUT, @createDate OUTPUT;