nvarchar(max)仍然被截断

时间:2011-01-28 22:08:44

标签: sql sql-server-2008 dynamic-sql

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

@Query

我做错了什么,或者我对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 的工作原理完全错了?

10 个答案:

答案 0 :(得分:57)

问题似乎与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]

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

答案 1 :(得分:55)

问题在于隐式转换。

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

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

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的工作方式真是太痛苦和可怕了。的:(

我知道网上的其他解决方法是说使用多个变量将代码分解为多个SET / SELECT分配,但鉴于上述解决方案,这是不必要的。

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

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

答案 2 :(得分: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

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

答案 3 :(得分:5)

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

Screenshot

我使用这种方法

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*/

答案 4 :(得分:4)

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

查询格式错误的原因可能不是截断。

答案 5 :(得分:1)

我今天遇到了同样的问题,发现超过4000个字符限制,我不得不将动态查询拆分为两个字符串,并在执行查询时将它们连接起来。

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)

答案 6 :(得分:1)

使用此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

答案 7 :(得分:1)

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

但;

PRINT CAST(@query AS NTEXT)

将打印整个查询。

答案 8 :(得分:1)

使用字符串表达式创建动态SQL的问题是SQL确实将字符串表达式的计算限制为4,000个字符。您可以将更长的字符串分配给nvarchar(max)变量,但只要在表达式中包含+(例如+ CASE ... END +),表达式结果就会限制为4,000个字符。

解决此问题的一种方法是使用CONCAT而不是+。例如:

SET @sql = CONCAT(@sql, N'
     ... dynamic SQL statements ...
    ', CASE ... END, N'
     ... dynamic SQL statements ...
    ')

其中@sql被声明为nvarchar(max)。

答案 9 :(得分:0)

我正在创建一个JSON-LD来创建站点审查脚本。 **DECLARE @json VARCHAR(MAX);**的实际JSON约为94K。

我通过使用CAST(''AS VARCHAR(MAX))+ @json使它起作用,如其他贡献者所述: 所以**SET @json = CAST('' AS VARCHAR(MAX)) + (SELECT .....**

2 /我还必须更改查询选项:- 查询选项->“结果”->“网格”->“接收的最大字符”->“非XML数据”设置为2000000。 (我将“ 结果”->“文本”->“每列中显示的最大字符数”保留为默认值