Ответ 1
Я понимаю, что для
существует 4000 максимальных значений,NVARCHAR(MAX)
Ваше понимание неверно. NVARCHAR(MAX)
может хранить до (и за пределами иногда) 2 ГБ данных (1 млрд. двухбайтовых символов).
Из nchar и nvarchar в онлайн-книгах грамматика
nvarchar [ ( n | max ) ]
Символ |
означает, что это альтернативы. то есть вы указываете либо n
, либо литерал max
.
Если вы решите указать конкретный n
, то это должно быть от 1 до 4000, но с использованием max
определяет его как большой тип данных объекта (замена ntext
, который устарел).
Фактически в SQL Server 2008 кажется, что для переменной ограничение 2 ГБ может быть неограниченно превышено на достаточное пространство в tempdb
(показано здесь)
Что касается других частей вашего вопроса
Усечение при конкатенации зависит от типа данных.
-
varchar(n) + varchar(n)
будет усекаться с 8000 символами. -
nvarchar(n) + nvarchar(n)
будет усекаться с 4000 символов. -
varchar(n) + nvarchar(n)
будет обрезаться с 4000 символов.nvarchar
имеет более высокий приоритет, поэтому результатnvarchar(4,000)
-
[n]varchar(max)
+[n]varchar(max)
не будет усекать (для < 2GB). -
varchar(max)
+varchar(n)
не будет усекать (для < 2GB), и результат будет напечатан какvarchar(max)
. -
varchar(max)
+nvarchar(n)
не будет усекать (для < 2GB), и результат будет напечатан какNVARCHAR(MAX)
. -
NVARCHAR(MAX)
+varchar(n)
сначала преобразует входvarchar(n)
вnvarchar(n)
, а затем выполнит конкатенацию. Если длина строкиvarchar(n)
больше 4000 символов, то приведение будетnvarchar(4000)
и произойдет усечение.
Типы данных строковых литералов
Если вы используете префикс n
, а строка - <= 4000 символов, он будет набираться как nvarchar(n)
, где n
- длина строки. Таким образом, N'Foo'
будет рассматриваться как nvarchar(3)
, например. Если строка длиннее 4000 символов, она будет обрабатываться как NVARCHAR(MAX)
Если вы не используете префикс n
, а строка - <= 8000 символов, он будет набираться как varchar(n)
, где n
- длина строки. Если дольше varchar(max)
Для обоих указанных выше, если длина строки равна нулю, тогда n
устанавливается в 1.
Новые элементы синтаксиса.
1. Функция CONCAT
здесь не помогает
DECLARE @A5000 VARCHAR(5000) = REPLICATE('A',5000);
SELECT DATALENGTH(@A5000 + @A5000),
DATALENGTH(CONCAT(@A5000,@A5000));
Приведенное выше возвращает 8000 для обоих методов конкатенации.
2. Будьте осторожны с +=
DECLARE @A VARCHAR(MAX) = '';
SET @A+= REPLICATE('A',5000) + REPLICATE('A',5000)
DECLARE @B VARCHAR(MAX) = '';
SET @B = @B + REPLICATE('A',5000) + REPLICATE('A',5000)
SELECT DATALENGTH(@A),
DATALENGTH(@B);`
Возвращает
-------------------- --------------------
8000 10000
Обратите внимание, что @A
встретил усечение.
Как решить проблему, с которой вы столкнулись.
Вы получаете усечение либо из-за того, что вы объединяете два типа данных типа max
, либо из-за того, что вы объединяете строку varchar(4001 - 8000)
с введенной строкой nvarchar
(даже NVARCHAR(MAX)
).
Чтобы избежать второй проблемы, просто убедитесь, что все строковые литералы (или, по крайней мере, те, которые имеют длину в диапазоне 4001-8000) имеют префикс n
.
Чтобы избежать первой проблемы, измените назначение из
DECLARE @SQL NVARCHAR(MAX);
SET @SQL = 'Foo' + 'Bar' + ...;
Для
DECLARE @SQL NVARCHAR(MAX) = '';
SET @SQL = @SQL + N'Foo' + N'Bar'
так что a NVARCHAR(MAX)
участвует в конкатенации с самого начала (так как результат каждой конкатенации будет также NVARCHAR(MAX)
, это будет распространяться)
Избегание усечения при просмотре
Убедитесь, что выбран режим "результаты в сетку", и вы можете использовать
select @SQL as [processing-instruction(x)] FOR XML PATH
Параметры SSMS позволяют устанавливать неограниченную длину для результатов XML
. Бит processing-instruction
позволяет избежать проблем с такими символами, как <
, отображаемый как <
.