SQL NVARCHAR和VARCHAR限制

所有,我有一个大的(不可避免的)dynamicSQL查询。 由于select标准中的字段数量,包含dynamicSQL的string正在增长超过4000个字符。 现在我明白NVARCHAR(MAX)有一个最大值为4000的设置,但是在Server Profiler中查看执行的SQL

 DELARE @SQL NVARCHAR(MAX); SET @SQL = 'SomeMassiveString > 4000 chars...'; EXEC(@SQL); GO 

似乎工作(!?),另一个查询也很大,它会抛出一个错误,这是4000的限制(!?),它基本上修剪所有的SQL后4000限制,留下一个语法错误。 尽pipe在剖析器中,它完全显示了这个dynamicSQL查询(!?)。

到底发生了什么,我应该只是将这个@SQLvariables转换为VARCHAR并继续使用它?

谢谢你的时间。

PS。 能够打印超过4000个字符来查看这些大问题也是很好的。 以下限制为4000

 SELECT CONVERT(XML, @SQL); PRINT(@SQL); 

还有没有其他酷的方式?

我知道有一个4000最大设置为NVARCHAR(MAX)

你的理解是错误的。 nvarchar(max)可以存储(甚至超出)2GB数据(10亿个双字节字符)。

从书中的nchar和nvarchar在线语法是

 nvarchar [ ( n | max ) ] 

| 字符意味着这些是替代品。 即你指定n或文字max

如果你select指定一个特定的n那么这个值必须介于1到4,000之间,但是使用max将它定义为一个大的对象数据types(replace为不被使用的ntext )。

实际上,在SQL Server 2008中,似乎对于一个variables来说 ,2GB的限制可以无限制地超过tempdb空间( 这里显示 )

关于你问题的其他部分

连接时的截断取决于数据types。

  1. varchar(n) + varchar(n)将截断8,000个字符。
  2. nvarchar(n) + nvarchar(n)将以4,000个字符截断。
  3. varchar(n) + nvarchar(n)将以4,000个字符截断。 nvarchar有更高的优先级,所以结果是nvarchar(4,000)
  4. [n]varchar(max) + [n]varchar(max)不会截断(<2GB)。
  5. varchar(max) + varchar(n)不会截断(对于<2GB),结果将被input为varchar(max)
  6. varchar(max) + nvarchar(n)不会截断(对于<2GB),结果将被input为nvarchar(max)
  7. nvarchar(max) + varchar(n)将首先将varchar(n)input转换为nvarchar(n) ,然后进行连接。 如果varchar(n)string的长度大于4,000个字符,则转换为nvarchar(4000) ,将发生截断

string文字的数据types

如果使用N前缀,并且string<= 4,000个字符,则它将被键入为nvarchar(n) ,其中n是string的长度。 所以N'Foo'将被视为nvarchar(3) 。 如果string长度超过4,000个字符,则将被视为nvarchar(max)

如果不使用N前缀,并且string长度小于8,000个字符,则将键入为varchar(n) ,其中n是string的长度。 如果更长时间varchar(max)

对于上述两者,如果string的长度为零,则n被设置为1。

较新的语法元素。

1. CONCATfunction在这里没有帮助

 DECLARE @A5000 VARCHAR(5000) = REPLICATE('A',5000); SELECT DATALENGTH(@A5000 + @A5000), DATALENGTH(CONCAT(@A5000,@A5000)); 

上面的两个方法的连接返回8000。

2.小心+=

 DECLARE @A VARCHAR(MAX) = ''; SET @A+= REPLICATE('A',5000) + REPLICATE('A',5000) DECLARE @B VARCHAR(MAX) = ''; SET @B = @B + REPLICATE('A',5000) + REPLICATE('A',5000) SELECT DATALENGTH(@A), DATALENGTH(@B);` 

返回

 -------------------- -------------------- 8000 10000 

请注意@A遇到截断。

如何解决您遇到的问题。

由于将两个非max数据types连接在一起,或者因为将一个varchar(4001 - 8000)string连接到一个nvarchartypes的string(甚至是nvarchar(max) ),所以正在截断。

为了避免第二个问题,只要确保所有string文字(或者至less那些长度在4001-8000范围内的文字)以N开头。

为了避免第一个问题从改变分配

 DECLARE @SQL NVARCHAR(MAX); SET @SQL = 'Foo' + 'Bar' + ...; 

 DECLARE @SQL NVARCHAR(MAX) = ''; SET @SQL = @SQL + N'Foo' + N'Bar' 

所以一个NVARCHAR(MAX)参与了从一开始的串联(因为每个串联的结果也将是NVARCHAR(MAX)这将传播)

查看时避免截断

确保你有“结果到网格”模式select,那么你可以使用

 select @SQL as [processing-instruction(x)] FOR XML PATH 

SSMS选项允许您为XML结果设置无限长度。 processing-instruction位避免了诸如<显示为&lt;

好的,所以如果后面的问题是你有一个大于允许的大小的查询(这可能发生,如果它继续增长),你将不得不把它分成块和执行string值。 所以,假设您有如下的存储过程:

 CREATE PROCEDURE ExecuteMyHugeQuery @SQL VARCHAR(MAX) -- 2GB size limit as stated by Martin Smith AS BEGIN -- Now, if the length is greater than some arbitrary value -- Let's say 2000 for this example -- Let's chunk it -- Let's also assume we won't allow anything larger than 8000 total DECLARE @len INT SELECT @len = LEN(@SQL) IF (@len > 8000) BEGIN RAISERROR ('The query cannot be larger than 8000 characters total.', 16, 1); END -- Let's declare our possible chunks DECLARE @Chunk1 VARCHAR(2000), @Chunk2 VARCHAR(2000), @Chunk3 VARCHAR(2000), @Chunk4 VARCHAR(2000) SELECT @Chunk1 = '', @Chunk2 = '', @Chunk3 = '', @Chunk4 = '' IF (@len > 2000) BEGIN -- Let's set the right chunks -- We already know we need two chunks so let's set the first SELECT @Chunk1 = SUBSTRING(@SQL, 1, 2000) -- Let's see if we need three chunks IF (@len > 4000) BEGIN SELECT @Chunk2 = SUBSTRING(@SQL, 2001, 2000) -- Let's see if we need four chunks IF (@len > 6000) BEGIN SELECT @Chunk3 = SUBSTRING(@SQL, 4001, 2000) SELECT @Chunk4 = SUBSTRING(@SQL, 6001, (@len - 6001)) END ELSE BEGIN SELECT @Chunk3 = SUBSTRING(@SQL, 4001, (@len - 4001)) END END ELSE BEGIN SELECT @Chunk2 = SUBSTRING(@SQL, 2001, (@len - 2001)) END END -- Alright, now that we've broken it down, let's execute it EXEC (@Chunk1 + @Chunk2 + @Chunk3 + @Chunk4) END 

你也使用nvarchar文本。 这意味着你必须在你的巨大的string之前有一个“N”,就是这样! 没有限制了

 DELARE @SQL NVARCHAR(MAX); SET @SQL = N'SomeMassiveString > 4000 chars...'; EXEC(@SQL); GO 
 declare @p varbinary(max) set @p = 0x declare @local table (col text) SELECT @p = @p + 0x3B + CONVERT(varbinary(100), Email) FROM tbCarsList where email <> '' group by email order by email set @p = substring(@p, 2, 100000) insert @local values(cast(@p as varchar(max))) select DATALENGTH(col) as collen, col from @local result collen > 8000, length col value is more than 8000 chars