Странная длина varchar и nvarchar в T-SQL - PullRequest
1 голос
/ 14 ноября 2011

У меня был вопрос о Transcat SQL, ниже приведен код SQL;

DECLARE @main nVARCHAR(max);

--there are over 4000 characters to @main 
set @main = '01234567890123456789...';
Print len(@main)

длина @main правильная, например 4007 однако, если я изменю код ниже:

DECLARE @main nVARCHAR(max);

--there are over 4000 characters to @main 
set @main = N'01234567890123456789...';
Print len(@main)

длина @main всегда будет 4000, это странно, я не понимаю. Другое дело, если я поменяю код ниже:

DECLARE @main nVARCHAR(max), @split nVARCHAR(500);

--there are 500 characters to @split 
set @split = '01234567890123456789...';
set @main = @split + @split + @split + @split + @split + @split + @split + @split + @split + @split;
Print len(@main)

Длина @main 4000, почему? Независимо от того, я добавляю букву N перед '01234567890123456789 ...'? если я изменю @split на varchar (500) ОБЪЯВИТЬ @ основной nVARCHAR (макс.), @Split VARCHAR (500);

--there are 500 characters to @split 
set @split = '01234567890123456789...';
-- 10 @split
set @main = @split + @split + @split + @split + @split + @split + @split + @split + @split + @split;
Print len(@main)

Длина @main правильная, независимо от того, добавляю ли я букву N перед '' 01234567890123456789 ... 'или нет, длина @main всегда равна 5000

1 Ответ

1 голос
/ 14 ноября 2011

У вас проблемы с неявными типами строковых выражений. За исключением длины MAX, тип VARCHAR может содержать 8000 символов (ограничено размером страницы в SQL SERVER) и, поскольку NVARCHAR хранит двухбайтовые символы, он может содержать половину числа символов (4000). По умолчанию строковые выражения (литералы, объединенные строки и т. Д.) Оцениваются с использованием максимальной длины 8000 для varchar или максимальной длины 4000 для nvarchar. Вы должны явно привести выражение к типу MAX, чтобы получить ожидаемое поведение.

В первом примере ваше строковое выражение '01234567890123456789...' неявно оценивается как VARCHAR(8000), которое затем неявно преобразуется в NVARCHAR(MAX), поэтому оно правильно сохраняет количество символов, поскольку в вашем выражении только 4007 символов.

Когда вы преобразуете строковое выражение в юникод (то есть N'01234567890123456789...', оно оценивает строку как NVARCHAR(4000), прежде чем присваивать значение переменной NVARCHAR(MAX).

Измените ваш второй пример на это:

DECLARE @main nVARCHAR(max);

--there are over 4000 characters to @main 
set @main = CAST(N'01234567890123456789...' AS NVARCHAR(MAX));
Print len(@main)

И он будет вести себя так, как вы ожидаете.

Аналогично, когда вы объединяете переменные @split, SQL Server оценивает выражение как NVARCHAR(4000), вам нужно привести самое левое значение как NVARCHAR(MAX), чтобы выражение оценивалось как NVARCHAR(MAX)

DECLARE @main nVARCHAR(max), @split nVARCHAR(500);

--there are 500 characters to @split 
set @split = '01234567890123456789...';
set @main = CAST(@split as NVARCHAR(MAX)) + @split + @split + @split + @split + @split + @split + @split + @split + @split;
Print len(@main)

Это будет работать.

...