【问题标题】:Using VARCHAR(MAX) with string concatenation in SQL Server 2005在 SQL Server 2005 中使用带有字符串连接的 VARCHAR(MAX)
【发布时间】:2010-12-28 17:11:08
【问题描述】:

我们其中一个数据库的用户正尝试向 SQL Server 2005 数据库提交 UPDATE 查询,但文本被意外截断。

被截断的字段是 VARBINARY(MAX),用于存储 HTML 文本。

查询大致是:

UPDATE Story 
SET mainText = CONVERT (VARBINARY (MAX), '[...5000 chars of text...]' 
    + char(47) + char(47)
    + '[...3000 chars of text...]'
    + char(47) + char(47)
    + '[...5000 chars of text...]') 
WHERE storyId = 123456

经过一些实验,我发现当我删除字符串连接时,查询按预期工作,并且字段不会被截断。

我能够解决限制并通过将 CAST 中的每个单独字符串包装到 VARCHAR(MAX) 来保持连接,因此如果用户认为需要使用 char(),则可以选择。

认为正在发生的事情是,每当使用连接运算符时,VARCHAR 都会发生隐式转换,并且隐式转换似乎仅限于 VARCHAR(8000) 而不是 VARCHAR(MAX )。因此,在字符串被发送到 CONVERT 函数之前,它已经被截断为 8000 个字符。

如果我是正确的,有没有办法改变这种行为?

如果没有办法改变行为,除了CAST还有其他方法可以解决这个问题吗?

【问题讨论】:

  • 你为什么用VARBINARY(MAX)来存储HTML?? VARCHAR(MAX) 将是更明显和合乎逻辑的选择...
  • 旧版数据库。不知道为什么会做出这样的选择。正在雷达上研究正在发生的事情。

标签: sql-server-2005 tsql


【解决方案1】:

你需要 CAST 第一个字符串first

CONVERT (VARBINARY (MAX), '[...5000 chars of text...]')
    + char(47) + char(47)
    + '[...3000 chars of text...]'
    + char(47) + char(47)
    + '[...5000 chars of text...]'

以前,内部文本永远不会超过 8000 字节。然后你正在铸造。太晚了。

'[...5000 chars of text...]') 
    + char(47) + char(47)
    + '[...3000 chars of text...]'
    + char(47) + char(47)
    + '[...5000 chars of text...]' 

有关“为什么”的更完整演练,请在此处查看我的答案"For Nvarchar(Max) I am only getting 4000 characters in TSQL?"

【讨论】:

    【解决方案2】:

    我的经验是 1) 你只需要将最左边的项转换为 varchar(max):

    UPDATE Story 
    SET mainText = CONVERT (VARBINARY (MAX), '[...5000 chars of text...]') 
        + char(47) + char(47)
        + '[...3000 chars of text...]'
        + char(47) + char(47)
        + '[...5000 chars of text...]' 
    WHERE storyId = 123456
    

    2) 您可以将整个文本作为一个字符串文字提供,不要被查询结果每列 8192 个字符或 PRINT 语句 8000 个字符的限制所迷惑。您不需要将“/”字符转义为 char(...)。您唯一需要做的就是复制嵌入的撇号。

    【讨论】:

      【解决方案3】:

      解决方案

      创建 多个 SET 语句,每个语句相加小于 8000 字节。 SQL 将在连接过程中自动扩展字符串大小。

      示例

      declare @SQLStatement nvarchar(Max)
      SET @SQLStatement = '[...first block of text...]'
      SET @SQLStatement = @SQLStatement + '[...next block of text...]'
      ...
      

      背景

      我遇到了同样的问题,只是上述方法都不起作用。就我而言,代码使用的是 nvarchar(max)。我尝试将第一个字符串显式转换为 nvarchar(max) 但它没有帮助。就我而言,附加了很多行,因此很容易将它们分开。请注意,nchar 需要 2x char。在我们的案例中,开发人员从 char 更改为 nchar,这导致了我们的 bug,并将我们推到了 8000 字节的边缘。我们刚刚超过 4000 个字符(我并不是说这是一个好习惯 :) 切换到 nchar 使其翻倍,然后我们超过了 8000 个字符的限制。

      为什么

      为什么会这样?我确信一些 SQL 负责人可以告诉我们,但我相信这与 SQL 如何根据需要动态为 nvarchar(max) 分配空间有关。出于某种原因,它无法在单个 SET 语句中执行此操作。但是,如果您将它们分解,则在检测到您超过 8000 限制时,它会在每个新的串联中重新评估并分配所需的空间。

      【讨论】:

        【解决方案4】:

        您应该尝试对要连接的每个字符串执行CONVERT。或者,您可以将查询分隔为多个 UPDATE(假设列主文本为 VARBINARY(MAX))。

        UPDATE Story 
        SET mainText = CONVERT (VARBINARY (MAX), '[...5000 chars of text...]' )
                       + char(47) + char(47)
                       + CONVERT (VARBINARY (MAX),'[...3000 chars of text...]')
                       + char(47) + char(47)
                       + CONVERT (VARBINARY (MAX),'[...5000 chars of text...]') 
        WHERE storyId = 123456
        

        或者

        UPDATE Story 
        SET mainText = '[...5000 chars of text...]'
        WHERE storyId = 123456
        
        UPDATE Story 
        SET mainText = maintext + char(47) + char(47) + '[...3000 chars of text...]'
        WHERE storyId = 123456
        
        UPDATE Story 
        SET mainText = maintext + char(47) + char(47) + '[...5000 chars of text...]'
        WHERE storyId = 123456
        

        【讨论】:

          【解决方案5】:

          您的截断正在发生,因为您首先进行字符串连接 [...5000 chars of text...]' + char(47) + char(47) + '[...3000 chars of text...]' + char(47) + char(47) + '[...5000 chars of text...]') 然后转换为 VARBINARY (MAX)。

          您应该先将每个字符串转换为VARBINARY (MAX),然后再进行连接

          UPDATE Story 
          SET mainText = 
                CONVERT (VARBINARY (MAX), '[...5000 chars of text...]' )
              + CONVERT (VARBINARY (MAX), char(47) + char(47))
              + CONVERT (VARBINARY (MAX), '[...3000 chars of text...]')
              + CONVERT (VARBINARY (MAX), char(47) + char(47)
              + CONVERT (VARBINARY (MAX), '[...5000 chars of text...]') )
          WHERE storyId = 123456
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-08-27
            • 2010-12-09
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-04-23
            相关资源
            最近更新 更多