簡體   English   中英

串聯 SQL 服務器 VARCHAR(N),轉換為 NVARCHAR(MAX) 時會出現意外且不一致的截斷結果

[英]Concatenating SQL Server VARCHAR(N), results with unexpected and inconsistent truncated results when converted to NVARCHAR(MAX)

在下面的代碼中,我們看到 varchar(n) 的串聯(其中 n>4000)在轉換為 nvarchar(max) 時會產生意外且不一致的截斷結果:

  1. 當連接中僅涉及 varchar(n) 值時,結果將被截斷為 8000 個字符。
  2. 在連接到 nvarchar(max) 之前完成的一系列 varchar(n) 連接在連接到 nvarchar(max) 之前被截斷為 4000 個字符。
  3. 一系列 varchar(n) 連接,在連接到 nvarchar(max) 之后完成,每個 varchar(n) 在連接之前被截斷為 4000 個字符

我想隱式轉換是按連接順序完成的,但我會說 (1) 的行為符合預期,(2) 應該被截斷為 8000,而 (3) 根本不應該被截斷。

似乎有某種(錯誤的)長度轉換為 4000,這是在連接順序之外完成的,這在某種程度上與結果類型 NVARCHAR 相關。 但是如果意圖是根據結果類型轉換所有連接,那么,因為它是 MAXed,所以不會有任何截斷(這會給出最好的結果)。

我哪里錯了?

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'

當您將兩個varchar值連接在一起時,數據類型的結果長度是兩者的總和,最大為 8000 ,超過的長度將被截斷。

當您將兩個nvarchar值連接在一起時,數據類型的結果長度是兩者的總和,最大為 4000 ,超過的長度將被截斷。

只有當您將它存儲在max變量中時,該值才會變為max ,截斷會在此之前發生

此外,您在這里進行了第二次隱式轉換,從varcharnvarchar ,這本身會導致截斷,因為nvarchar最多只能是 4000。

如果您連接一個nvarchar和一個varchar ,則varchar將轉換為匹配,但上限為 4000。最終結果在存儲到變量中之前不會變為max 所以隱式轉換將在截斷之后完成。

您的結果現在非常有意義:

  • 長度已經是 4200,並擴展到max
SET @x = @z
print CAST(len(@x) AS NVARCHAR(MAX)) + '    Expected 4200'

  • 在這些情況下,中間值上限為 8000,然后才轉換為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的隱式轉換,然后再與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'

保證正確結果的唯一方法是首先將您的值轉換為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'

或者,只需使用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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM