[英]Concatenating SQL Server VARCHAR(N), results with unexpected and inconsistent truncated results when converted to NVARCHAR(MAX)
In the following code we see that concatenation of varchar(n) where n>4000, results with unexpected and inconsistent truncated results when converted to nvarchar(max):在下面的代码中,我们看到 varchar(n) 的串联(其中 n>4000)在转换为 nvarchar(max) 时会产生意外且不一致的截断结果:
I guess that the implicit cast is done in order of concatenation, but then I would say that (1) behave as expected, (2) should be truncated to 8000 and (3) should not be truncated at all.我想隐式转换是按连接顺序完成的,但我会说 (1) 的行为符合预期,(2) 应该被截断为 8000,而 (3) 根本不应该被截断。
It seems like there is some kind of a (wrong) length cast to 4000 that is done out of the concatenation order which is somehow related to the resulting type NVARCHAR.似乎有某种(错误的)长度转换为 4000,这是在连接顺序之外完成的,这在某种程度上与结果类型 NVARCHAR 相关。 But then if the intention was to cast all the concatenations according to the resulting type, then, since it is MAXed, no truncates would have been expected (which would give the best result).
但是如果意图是根据结果类型转换所有连接,那么,因为它是 MAXed,所以不会有任何截断(这会给出最好的结果)。
Where am I wrong?我哪里错了?
DECLARE @x AS NVARCHAR(MAX)
DECLARE @y AS NVARCHAR(MAX) = '_10 chars_'
DECLARE @z AS VARCHAR(4200) = replicate('_', 4200)
SET @x = @z
print CAST(len(@x) AS NVARCHAR(MAX)) + ' Expected 4200'
SET @x = @z + @z
print CAST(len(@x) AS NVARCHAR(MAX)) + ' Expected 8400 = 4200 * 2'
SET @x = @z + @z + @z
print CAST(len(@x) AS NVARCHAR(MAX)) + ' Expected 12600 = 4200 * 3'
SET @x = @z + @y
print CAST(len(@x) AS NVARCHAR(MAX)) + ' Expected 4210 = 4200 + 10'
SET @x = @z + @z + @y
print CAST(len(@x) AS NVARCHAR(MAX)) + ' Expected 8410 = 4200 * 2 + 10'
SET @x = @z + @z + @z + @y
print CAST(len(@x) AS NVARCHAR(MAX)) + ' Expected 12610 = 4200 * 3 + 10'
SET @x = @y + @z
print CAST(len(@x) AS NVARCHAR(MAX)) + ' Expected 4210 = 10 + 4200'
SET @x = @y + @z + @z
print CAST(len(@x) AS NVARCHAR(MAX)) + ' Expected 8410 = 10 + 4200 * 2'
SET @x = @y + @z + @z + @z
print CAST(len(@x) AS NVARCHAR(MAX)) + ' Expected 12610 = 10 + 4200 * 3'
SET @x = @z + @z + @z + @y + @z + @z + @z
print CAST(len(@x) AS NVARCHAR(MAX)) + ' Expected 25210 = 4200 * 3 + 10 + 4200 * 3'
When you concatenate two varchar
values together, the resulting length of the data type is the sum of the two, up to a maximum of 8000 , any longer will be truncated.当您将两个
varchar
值连接在一起时,数据类型的结果长度是两者的总和,最大为 8000 ,超过的长度将被截断。
When you concatenate two nvarchar
values together, the resulting length of the data type is the sum of the two, up to a maximum of 4000 , any longer will be truncated.当您将两个
nvarchar
值连接在一起时,数据类型的结果长度是两者的总和,最大为 4000 ,超过的长度将被截断。
Only when you store it in a max
variable does the value become max
, the truncation will happen before then只有当您将它存储在
max
变量中时,该值才会变为max
,截断会在此之前发生
Furthermore, you have a second implicit conversion going on here, from varchar
to nvarchar
, which itself causes truncation because nvarchar
can only be up to 4000.此外,您在这里进行了第二次隐式转换,从
varchar
到nvarchar
,这本身会导致截断,因为nvarchar
最多只能是 4000。
If you concatenate a nvarchar
and a varchar
, the varchar
is converted to match, but capped at 4000. The final result will not become max
until it is stored in the variable.如果您连接一个
nvarchar
和一个varchar
,则varchar
将转换为匹配,但上限为 4000。最终结果在存储到变量中之前不会变为max
。 So the implicit conversion will be done after that truncation.所以隐式转换将在截断之后完成。
Your results now make perfect sense:您的结果现在非常有意义:
max
.max
。SET @x = @z
print CAST(len(@x) AS NVARCHAR(MAX)) + ' Expected 4200'
max
max
SET @x = @z + @z
print CAST(len(@x) AS NVARCHAR(MAX)) + ' Expected 8400 = 4200 * 2'
SET @x = @z + @z + @z
print CAST(len(@x) AS NVARCHAR(MAX)) + ' Expected 12600 = 4200 * 3'
nvarchar
is done first, then concatenated with a max
afterwards , so the original @z
value was truncated first.nvarchar
的隐式转换,然后再与max
连接,因此首先截断原始@z
值。SET @x = @z + @y
print CAST(len(@x) AS NVARCHAR(MAX)) + ' Expected 4210 = 4200 + 10'
SET @x = @z + @z + @y
print CAST(len(@x) AS NVARCHAR(MAX)) + ' Expected 8410 = 4200 * 2 + 10'
SET @x = @z + @z + @z + @y
print CAST(len(@x) AS NVARCHAR(MAX)) + ' Expected 12610 = 4200 * 3 + 10'
SET @x = @y + @z
print CAST(len(@x) AS NVARCHAR(MAX)) + ' Expected 4210 = 10 + 4200'
SET @x = @y + @z + @z
print CAST(len(@x) AS NVARCHAR(MAX)) + ' Expected 8410 = 10 + 4200 * 2'
SET @x = @y + @z + @z + @z
print CAST(len(@x) AS NVARCHAR(MAX)) + ' Expected 12610 = 10 + 4200 * 3'
SET @x = @z + @z + @z + @y + @z + @z + @z
print CAST(len(@x) AS NVARCHAR(MAX)) + ' Expected 25210 = 4200 * 3 + 10 + 4200 * 3'
The only way to guarantee the right results is to cast your values to nvarchar(max)
first保证正确结果的唯一方法是首先将您的值转换为
nvarchar(max)
SET @x = CAST(@z AS nvarchar(max)) + CAST(@z AS nvarchar(max)) + CAST(@z AS nvarchar(max)) + @y + CAST(@z AS nvarchar(max)) + CAST(@z AS nvarchar(max)) + CAST(@z AS nvarchar(max))
print CAST(len(@x) AS NVARCHAR(MAX)) + ' Expected 25210 = 4200 * 3 + 10 + 4200 * 3'
Alternatively, just use CONCAT
, which deals with all of this correctly anyway或者,只需使用
CONCAT
,它无论如何都能正确处理所有这些
SET @x = CONCAT(@z, @z, @z, @y, @z, @z, @z);
print CAST(len(@x) AS NVARCHAR(MAX)) + ' Expected 25210 = 4200 * 3 + 10 + 4200 * 3'
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.