用于构建SQL Server 2008R2动态查询的NVARCHAR(MAX)变量仅接受4000个字符

时间:2014-08-20 18:25:29

标签: sql-server tsql nvarchar

你能帮我理解这个奇怪的NVARCHAR变量行为吗?

我正在构建一个dSQL查询,其范围为LEN(),大约为6,700到6,900个字符,并将其存储在变量中:

DECLARE 
   @SQL           NVARCHAR(MAX),
   @WhereClause   NVARCHAR(MAX) = 'WHERE 1 = 1 
',
   @OrderByClaose NVARCHAR(MAX)
SET @SQL = 
'SELECT
    <column list>
FROM
    <very complicated FROM clause>
 '

不幸的是,我不允许发布实际代码。

最初,dSQL是一个长常量SELECTFROM字符串,大约有6,600个字符。确定了可变长度dSQL WHEREORDER BY子句

IF <condition p>
   SET @WhereClause = @WhereClause + 'AND <condition p clause>
'

IF <condition q>
   SET @WhereClause = @WhereClause + 'AND <condition q clause>
'
etc.    

然后添加到@SQL的末尾。

整个@SQLPRINT很好地执行,然后sp_executesql顺便执行。

因此,客户自然需要进行一些更改,从而将好的常量字符串分成几部分。这需要将动态列部分添加到SELECT列列表中间的IF语句。

SET @SQL = '
SELECT <code through first few columns>
...
'  

IF <condition>
   SET @SQL = @SQL + 
'    <new dynamic column spec stuff A> 
'
ELSE
    SET @SQL = @SQL + 
'    <new dynamic column spec stuff B> 
'

SET @SQL = @SQL + ' <next block of constant chars>'
...

当我添加新的IF/ELSE块时,由于某种原因@SQL停止接受前4,000个字符后的数据,大约是FROM子句的一半。

删除IF/ELSE块并将SELECTFROM返回到常量字符串(只是为测试添加一个新的需求案例),然后再次愉快@SQL接受了所有6,700个左右的字符。

作为解决方法,我将@SQL的声明更改为VARCHAR(MAX)

DECLARE @SQL varchar(max)
SET @SQL = <The built-up query string with the new IF/ELSE blocks>

DECLARE @NSQL nvarchar(max) = cast(@SQL as nvarchar(max))
exec sp_executesql @NSQL

一切都很好。

虽然我还没有测试过,但我想知道这个解决方法是否适用于这个特定任务的唯一原因是因为我最大的dSQL语句中的字符数小于8,000个字符。

我看过几篇文章,包括

但我发现的任何东西似乎都没有解释我在这个特殊的dSQL构造中观察到的行为。

知道这里有什么用吗?

1 个答案:

答案 0 :(得分:2)

首先,由于您有NVARCHAR数据类型,因此应始终使用N'...'格式(带有前导N前缀)来清楚地表示Unicode字符串文字。

DECLARE @WhereClause NVARCHAR(MAX) = N'WHERE 1 = 1'

其次,如果仅此一点没有帮助,请尝试在连接之前将字符串文字强制转换为NVARCHAR(MAX)

IF <condition>
   SET @SQL = @SQL + CAST(...... AS NVARCHAR(MAX))