nvarchar(max)仍然被截断

And*_*old 52 sql dynamic-sql sql-server-2008

所以我在MS SQL Server 2008中编写了一个存储过程.这是一个非常长的查询,我必须动态编写它,所以我创建一个名为的变量@Query并使其成为类型NVARCHAR(MAX).现在,我被告知在现代版本的SQL Server中,NVARCHAR(MAX)可以容纳一大堆数据,比最初的4000个字符最多.但是,@Query当我尝试将其打印出来时,仍会被截断为4000个字符.

DECLARE @Query NVARCHAR(max);
SET @Query = 'SELECT...' -- some of the query gets set here
SET @Query = @Query + '...' -- more query gets added on, etc.

-- later on...
PRINT LEN(@Query) -- Prints out 4273, which is correct as far as I can tell
PRINT @Query      -- Truncates value to 4000 characters
EXEC sp_executesql @Query -- totally crashes due to malformed (truncated) query
Run Code Online (Sandbox Code Playgroud)

我做错了什么,或者我完全错误的做法是什么NVARCHAR(MAX)

小智 63

问题似乎与SET语句有关.我认为表达式的大小不能超过4,000个字节.如果你要做的就是分配一个超过4,000个字符的动态生成语句,则无需对任何设置进行任何更改.你需要做的是分割你的作业.如果您的语句长度为6,000个字符,请找到逻辑断点,然后将后半部分连接到同一个变量.例如:

SET @Query = 'SELECT ....' [Up To 4,000 characters, then rest of statement as below]

SET @Query = @Query + [rest of statement]
Run Code Online (Sandbox Code Playgroud)

现在正常运行您的查询即 EXEC ( @Query )

  • 这确实解决了我长期以来一直遇到的问题。非常感谢。 (3认同)
  • 这应该是答案,似乎海报在他的“SET”语句中连接了超过 4000 个字符,NVARCHAR(MAX) 确实存储了超过 4000 个字符 (2认同)
  • 顺便说一句,如果您使用`DECLARE`创建查询,也是如此,例如`DECLARE @my_query NVARCHAR(MAX)='...一些非常长的查询...'`也会截断4000个字符.在SQL Server 2008上进入这个. (2认同)

Mik*_*Vee 60

问题在于隐式转换.

如果您正在连接Unicode/nChar/nVarChar值,那么SQL Server将隐式地将您的字符串转换为nVarChar(4000),遗憾的是它太愚蠢了,以至于它不会截断您的字符串,甚至会给您一个警告数据已被删除截断了那件事!

当连接长字符串(或者你感觉可能很长的字符串)时,总是将字符串构建与CAST(''作为nVarChar(MAX))预连接,如下所示:

SET @Query = CAST('' as nVarChar(MAX))--Force implicit conversion to nVarChar(MAX)
           + 'SELECT...'-- some of the query gets set here
           + '...'-- more query gets added on, etc.
Run Code Online (Sandbox Code Playgroud)

想到这就是SQL Server的工作方式真是太痛苦和可怕了. :(

我知道网上的其他解决方法是说使用多个变量将你的代码分解成多个SET/SELECT赋值,但是根据上面的解决方案,这是不必要的.

对于那些最多达到8000个字符的人来说,可能是因为你没有Unicode因此被隐式转换为VarChar(8000).

说明:
幕后发生的事情是,即使您指定的变量使用(MAX),SQL Server也会评估您首先分配的值的右侧并且默认为nVarChar(4000)或VarChar(8000)(取决于你连接的内容).完成后计算出值(并在为你截断之后),然后在分配给它时将其转换为(MAX)你的变量,但到那时为时已晚.

  • 这个答案是关于确切的问题. (4认同)
  • 有关此处隐式转换问题的详细说明,请参阅关于同一主题的另一个 SO 问题中的 [this answer](/sf/answers/884798071/)。 (2认同)

Ric*_*iwi 12

要查看生成的动态SQL,请更改为文本模式(快捷键: Ctrl-T),然后使用SELECT

PRINT LEN(@Query) -- Prints out 4273, which is correct as far as I can tell
--SET NOCOUNT ON
SELECT @Query
Run Code Online (Sandbox Code Playgroud)

至于sp_executesql尝试这个(在文本模式下),它应该显示三个aaaaa...中间的一个是最长的'SELECT ..'添加.观察Ln... Col..右下方状态栏中的 指示器,显示第二个输出结束时的4510.

declare @n nvarchar(max)
set @n = REPLICATE(convert(nvarchar(max), 'a'), 4500)
SET @N = 'SELECT ''' + @n + ''''
print @n   -- up to 4000
select @n  -- up to max
exec sp_Executesql @n
Run Code Online (Sandbox Code Playgroud)

  • MS SQL Server中有一个默认值,它限制文本结果中每列的最大字符数.要更改它,请转到"查询"菜单>"查询选项">"结果">"文本",然后将"最大值"更改为类似于8192. (10认同)

Mar*_*tos 6

你的第一个问题是声明的局限性PRINT。我不确定为什么sp_executesql会失败。它应该支持几乎任何长度的输入。

也许查询格式错误的原因不是截断。


boy*_*bas 6

打印将 varchar(MAX) 截断为 8000,将 nvarchar(MAX) 截断为 4000 个字符。

但;

PRINT CAST(@query AS NTEXT)
Run Code Online (Sandbox Code Playgroud)

将打印整个查询。


Mar*_*ith 5

文本结果最多只允许8192个字符.

截图

我用这种方法

DECLARE @Query NVARCHAR(max);

set @Query = REPLICATE('A',4000)
set @Query = @Query + REPLICATE('B',4000)
set @Query = @Query + REPLICATE('C',4000)
set @Query = @Query + REPLICATE('D',4000)

select LEN(@Query)

SELECT @Query /*Won't contain any "D"s*/
SELECT @Query as [processing-instruction(x)] FOR XML PATH /*Not truncated*/
Run Code Online (Sandbox Code Playgroud)

  • @cyberkiwi - 使用PI停止SQL Server替换XML实体(即`<`with`&lt;`等) (2认同)