【问题标题】:Why NVarchar(MAX) cannot execute complete dynamic query using SP_ExecuteSQL?为什么 NVarchar(MAX) 无法使用 SP_ExecuteSQL 执行完整的动态查询?
【发布时间】:2019-02-26 12:55:24
【问题描述】:

我创建了一个存储过程,它将有两个查询,这两个查询将更新两个表中的记录。

所以我会提到它显示的内容

我的程序如下

ALTER PROC UpdateMissingItemONPoe 
    @StoreID INT,
    @Name VARCHAR(20)
AS
BEGIN
    DECLARE @UpdateRec NVARCHAR(MAX) = '';
    DECLARE @StoreIP SYSNAME = ''

    SET @StoreIP = CASE @StoreID 
                      WHEN 1111 THEN '[192.168.1.45].[Store1].[dbo]'
                      WHEN 2222 THEN '[192.168.2.45].[Store2].[dbo]'
                      WHEN 3333 THEN '[192.168.3.45].[Store3].[dbo]'
                   END
    SET @UpdateRec = N' IF((SELECT NameID from '+@StoreIP+'.Details WHERE Name = '''+@Name+''') = 2 )
BEGIN
    INSERT INTO ' + @StoreIP + '.PurchaseOrderEntry(
            /*  InsertField Name  */
        )

        select
            Name,
            Standard,
            Department,
            Category,
            SubDescription,
            Rank
        from
            '+@StoreIP+'.Details 
        where
            Name = '''+@Name+'''

        INSERT INTO '+@StoreIP+'.HeadQuarter(
            /*  InsertField Name  */
        )
        select
            Name,
            Standard,
            Department,
            Category,
            SubDescription,
            Rank
        from
            '+@StoreIP+'.Details 
        where
            Name = '''+@Name+'''
    END'

    print @UpdateRec
    EXEC sp_executesql @UpdateRec
END

当我执行这个存储过程时,它没有显示任何错误消息。但是,当我打印时,该动态查询没有完整的查询。

打印出来的查询是这样的

INSERT INTO '+@StoreIP+'.PurchaseOrderEntry(
    /*  InsertField Name  */
)

select
    Name,
    Standard,
    Department,
    Category,
    SubDescription,
    Rank
from
    '+@StoreIP+'.Details 
where
    Name = '''+@Name+'''

INSERT INTO '+@StoreIP+'.HeadQuarter(
    /*  InsertField Name  */
)

select
    Name,
    Standard,
    Department,
    Category,     

剩下的行不见了

【问题讨论】:

  • @marc_s 你有什么想法吗?
  • @UpdateRec 的长度是多少? print @UpdateRec可能无法打印出@UpdateRec中的所有内容,以SSMS中的设置为准
  • @Squirrel 我提到过。那是NVarchar(MAX)
  • 无法在 SQL Server 2016 上重现 - 打印输出正确显示 (a) @StoreIP 被替换为来自 CASE 的正确预期值,并且输出包含 all 线条.....
  • @Liamneesan,不仅打印的查询被截断,IF 语句丢失并且变量没有正确连接。您发布的代码将无条件包含该代码并按我的预期运行。我怀疑您实际执行的过程与您问题中的过程不同。

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


【解决方案1】:

您的查询肯定超过了 4000 个字符。

将 SET 语句更改为

SET @UpdateRec = CONVERT(NVARCHAR(MAX), '') + N' IF(('

它将强制您的查询字符串N' IF ((... 为 nvarchar(max)。

【讨论】:

  • 我按照你说的做了。现在它显示的长度为4724。但它仍然没有显示完整的查询
  • SSMS 无法打印出全文长度。我记得有一个最大长度,但我不记得了。要打印出完整的查询,您需要执行substring() 并一次打印出4000。但是您的查询会执行吗?
  • 该查询运行良好。现在我创建了两个NVarchar(MAX) variable 并使用sp_executesql 执行这些变量。它成功执行,记录被插入到我的表中。我只是尝试在单个变量上只执行一次。这是k
  • @Liamneesan 那么请接受回复作为答案。这就是 SO 的设计方式;当提问者标记答案以便其他人可以找到答案时,它会有所帮助。
  • @SMor 对不起,没有人告诉我的查询有什么问题,他们只是为我的解决方案提供了替代方法。我的查询出了什么问题?...即使我找到了替代方法,并且像他们发布的那样成功地执行了它。
【解决方案2】:

我会改写为:

ALTER PROC UpdateMissingItemONPoe 
    @StoreID INT,
    @Name VARCHAR(20)
AS
BEGIN
    DECLARE @UpdateRec NVARCHAR(MAX) = N'';
    DECLARE @StoreIP NVARCHAR(128) = N'';

    SET @StoreIP = CASE @StoreID 
                      WHEN 1111 THEN '[192.168.1.45].[Store1].[dbo]'
                      WHEN 2222 THEN '[192.168.2.45].[Store2].[dbo]'
                      WHEN 3333 THEN '[192.168.3.45].[Store3].[dbo]'
                   END;

    SET @UpdateRec = N' IF((SELECT NameID from <@StoreIP>.Details 
                           WHERE Name = @Name) = 2 )
BEGIN
    INSERT INTO <StoreIP>.PurchaseOrderEntry(
            /*  InsertField Name  */
        )

        select
            Name,
            Standard,
            Department,
            Category,
            SubDescription,
            Rank
        from
            <@StoreIP>.Details 
        where
            Name = @Name

        INSERT INTO <@StoreIP>.HeadQuarter(
            /*  InsertField Name  */
        )
        select
            Name,
            Standard,
            Department,
            Category,
            SubDescription,
            Rank
        from
            <@StoreIP>.Details 
        where
            Name = @Name
    END';

   SET @UpdateRec = REPLACE(@UpadteRec, N'<@StoreIP>', @StoreIp);

    print @UpdateRec
    EXEC sp_executesql @UpdateRec, N'@Name NVARCHAR(20)', @Name;
END

使用参数化的动态 SQL 并使用 REPLACE 而不是串联交换表名。

【讨论】:

    【解决方案3】:

    过去,如果这些多部分语句未显式转换为 nvarchar(max) 类型,SQL Server 用于将这些多部分语句转换为 nvarchar(4000)。

    如果你有一个变量

    DECLARE @UpdateRec NVARCHAR(MAX) = '';
    

    然后就用了这种语法

    SET @UpdateRec = N' IF((SELECT NameID from '+@StoreIP+'.Details WHERE
     Name = '''+@Name+''') = 2 ) BEGIN
     INSERT INTO ' + @StoreIP + '.PurchaseOrderEntry( (...)'
    

    结果将被静默转换为 nvarchar(4000),并且会截断任何多余的字符而不发出警告。

    【讨论】:

      猜你喜欢
      • 2015-10-31
      • 2021-01-02
      • 1970-01-01
      • 2011-07-05
      • 2013-02-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多