nvarchar(max)仍然被截断

所以我在MS SQL Server 2008中编写了一个存储过程。这是一个非常长的查询,我必须dynamic编写它,所以我创build了一个名为@Query的variables,并将其设置为NVARCHAR(MAX)types。 现在有人告诉我,在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 

我做错了什么,或者我完全错误如何NVARCHAR(MAX)工作?

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

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

至于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 

问题似乎与SET语句相关联。 我认为expression式的大小不能超过4000字节。 如果您所要做的只是分配一个超过4,000个字符的dynamic生成的语句,则不需要对任何设置进行任何更改。 你需要做的是分裂你的任务。 如果您的语句长度为6000个字符,则find一个逻辑中断点,然后将后半部分连接到同一个variables。 例如:

SET @Query ='SELECT ….'[最多4,000个字符,其余部分如下所示]

SET @Query = @Query + [语句的其余部分]

现在运行你的查询作为正常即EXEC(@Query)

问题是隐式转换。

如果你有连接的Unicode / nChar / nVarChar值,那么SQL Server会隐式地将你的string转换为nVarChar(4000),不幸的是,它会截断你的string,甚至给你一个警告,数据已经截断的事情!

当连接长string(或者你觉得可能很长的string)时, 总是CAST(''as nVarChar(MAX))预先连接你的string,像这样:

 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. 

多么痛苦和可怕的想法是SQL Server的工作原理。 🙁

我知道networking上的其他解决方法是使用多个variables将代码分解为多个SET / SELECT赋值,但是考虑到上面的解决scheme,这是不必要的。

对于那些最多打8000个字符的人,可能是因为你没有Unicode,所以它被隐式转换为VarChar(8000)。

说明:
在幕后发生的事情是,即使你正在分配的variables使用(MAX),SQL Server将评估你首先分配的值的右侧,默认为nVarChar(4000)或VarChar(8000)(取决于关于你的连接)。 在完成计算之后(并在为你截断之后),在将其分配给variables时将其转换为(MAX),但是到时候为时已晚。

结果到文本只允许最多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*/ 

你的第一个问题是PRINT语句的限制。 我不知道为什么sp_executesql失败。 它应该支持几乎任何长度的input。

也许查询格式不正确的原因是截断以外的东西。

我今天遇到同样的问题,发现超过4000个字符的限制,我不得不将dynamic查询拆分成两个string,并在执行查询时连接它们。

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

使用这个PRINT BIG函数来输出一切:

 IF OBJECT_ID('tempdb..#printBig') IS NOT NULL DROP PROCEDURE #printBig GO CREATE PROCEDURE #printBig ( @text NVARCHAR(MAX) ) AS --DECLARE @text NVARCHAR(MAX) = 'YourTextHere' DECLARE @lineSep NVARCHAR(2) = CHAR(13) + CHAR(10) -- Windows \r\n DECLARE @off INT = 1 DECLARE @maxLen INT = 4000 DECLARE @len INT WHILE @off < LEN(@text) BEGIN SELECT @len = CASE WHEN LEN(@text) - @off - 1 <= @maxLen THEN LEN(@text) ELSE @maxLen - CHARINDEX(REVERSE(@lineSep), REVERSE(SUBSTRING(@text, @off, @maxLen))) - LEN(@lineSep) + 1 END PRINT SUBSTRING(@text, @off, @len) --PRINT '@off=' + CAST(@off AS VARCHAR) + ' @len=' + CAST(@len AS VARCHAR) SET @off += @len + LEN(@lineSep) END 

资源:

https://www.richardswinbank.net/doku.php?id=tsql:print_big