如何在 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;