【问题标题】:Dynamic sql query with stored procedure and table variable带有存储过程和表变量的动态 sql 查询
【发布时间】:2015-12-25 16:06:13
【问题描述】:

我想动态调用存储过程,因为我的过程名称存储在某个地方,我还需要将该过程的结果存储到表变量中。因此我不得不编写以下sql代码,

在下面的代码中 @tblEmailIds 是我要存储 SP 的结果的表变量 @tempEmailSource 是过程的名称 @tempRecipientsIdsCSV 是我的 SP 接受的第一个参数 @ObjectMasterId 是 SP 接受的第二个参数(可选)

DECLARE @tempTypeName NVARCHAR(100), 
            @tempTypeId INT,
            @tempEmailSource NVARCHAR(100),
            @tempRecipientsIdsCSV NVARCHAR(MAX),
            @tempIsObjectSpecific BIT,
            @sqlQuery NVARCHAR(MAX) = 'INSERT INTO @tblEmailIds '
SELECT TOP 1 @tempTypeName = NAME, 
@tempTypeId = Id,         
@tempEmailSource = EmailListSourceName 
FROM @tbleRecipientsTypes WHERE IsEmailIdsFetched = 0

    SELECT @tempRecipientsIdsCSV = SUBSTRING(
    (SELECT ',' + CAST(RT.EmailRecipientId AS NVARCHAR(50))
    FROM @tbleRecipientsTypes RT WHERE RT.Id = @tempTypeId
    ORDER BY RT.EmailRecipientId
    FOR XML PATH('')),2,200000)

    SELECT @tempRecipientsIdsCSV


    SET @sqlQuery = @sqlQuery + 'EXEC ' + @tempEmailSource +' ' +''''  +    @tempRecipientsIdsCSV +''''
    IF (@tempIsObjectSpecific = 1)
    BEGIN
        SET @sqlQuery = @sqlQuery + ' ' + @ObjectMasterId
    END

    PRINT @SQLQUERY

    EXECUTE SP_EXECUTESQL 
    @SqlQuery,'@IdsCSV NVARCHAR(MAX) OUTPUT,  
    @ObjectMasterId INT = NULL OUTPUT', @tblEmailIds

我收到以下错误

消息 214,级别 16,状态 3,过程 sp_executesql,第 6 行过程 需要类型为“ntext/nchar/nvarchar”的参数“@params”。

【问题讨论】:

    标签: sql-server stored-procedures dynamic-sql


    【解决方案1】:

    这里有很多问题。

      1234563 >
    1. 表变量的工作方式与您尝试使用它们的方式不同。首先,您永远不会声明@tblEmailIds,但即使您声明了,表变量的范围也是本地的,它们不能用作OUTPUT 参数。相反,您需要创建一个本地临时表(即#tblEmailIds)并执行INSERT INTO #tblEmailIds

    2. 您引用了另一个尚未声明或填充的表变量@tbleRecipientsTypes

    3. 您确实声明了@tempIsObjectSpecific,但从未设置它,因此它始终为NULL

    4. 为什么@IdsCSV(在sp_executesql 调用参数列表中)声明为OUTPUT?您不仅没有传入@tempRecipientsIdsCSV(在动态SQL 中成为@IdsCSV),甚至不需要作为参数,因为您直接将@tempRecipientsIdsCSV 的值连接到动态SQL 中,并且有开始时动态 SQL 中没有 @tempRecipientsIdsCSV 变量。所以从参数列表中删除@IdsCSV NVARCHAR(MAX) OUTPUT,

    5. 您说“@tempRecipientsIdsCSV 是我的 SP 接受的第一个参数”,但是您在代码中声明了它,这应该会导致错误。

    6. @ObjectMasterId 是什么数据类型?你说它被传递到 proc 中,我看到它被连接到动态 SQL 中,所以它需要是字符串类型(即不是 INTsp_executesql 参数列表中显示的那样)或者它需要加入CONVERT(NVARCHAR(10), @ObjectMasterId

    7. 如果传入@ObjectMasterId,那么为什么在sp_executesql参数列表中声明为OUTPUT?但更好的问题可能是:既然您直接将它连接到动态 SQL 中,为什么还要将它传递给 sp_executesql?动态 SQL 中没有使用 @ObjectMasterId 变量。

    【讨论】:

    • 谢谢,总结一下这些是我所做的更改,输入 N'',删除 OUTPUT,并将 @tblEmailIds 设为 #tblEmailIds ...它成功了
    • @RoshanBirwatkar 不客气。我很高兴它奏效了。但是,正如我所说,您可以完全摆脱参数列表和参数,因为您甚至不使用它们。你可以只用EXECUTE SP_EXECUTESQL @SqlQuery; 就可以了,应该没问题。
    【解决方案2】:

    SP_EXECUTESQL@params 加上前缀N

    还需要存储OUTPUT参数的结果

    Declare  @IdsCSV NVARCHAR(MAX),@ObjectMasterId INT = NULL
    
    EXECUTE SP_EXECUTESQL 
        @SqlQuery,
        N'@IdsCSV NVARCHAR(MAX) OUTPUT,@ObjectMasterId INT = NULL OUTPUT',
        @IdsCSV = @IdsCSV OUTPUT,
        @ObjectMasterId = @ObjectMasterId OUTPUT
    

    【讨论】:

    • 您是正确的,参数列表需要以 N 为前缀,但存储 OUTPUT 参数的结果并没有帮助,因为它不仅看起来不是 OUTPUT参数,它首先不是参数,因为它没有被使用。事实上,这些参数中的任何一个都被使用了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-04
    • 1970-01-01
    • 1970-01-01
    • 2010-10-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多