SQL Server уменьшает длину строки до 8000 символов

#sql #sql-server #ntext

#sql #sql-сервер #ntext

Вопрос:

Я пытаюсь вставить данные в таблицу с типом данных столбца as NTEXT . В идеале он должен хранить более 8000 символов, но в моем случае он сокращает его до 8000 символов.

Я выполняю запрос Insert во время выполнения в процедуре. Ниже приведен пример запроса, который выполняет процедура.

 INSERT INTO TMPRESULTS SELECT ('A'   ','   'B'   ','   'C')
  

A, B, C и т. Д. Являются образцами данных, А фактические данные будут идентифицированы во время выполнения с фактическим содержимым, превышающим 8000 символов. Также переменная, используемая для хранения значения, определяется как « NVARCHAR(MAX)

Однако, когда я пытаюсь выполнить следующий запрос, он вставляет в таблицу более 8000 символов

 INSERT INTO TMPRESULTS SELECT ('ABCdddd................')
  

Я предполагаю, что пока я пытаюсь объединить данные со знаком » «, sql server уменьшает длину до 8000. Я не могу использовать CONCAT , поскольку данные будут содержать более 256 столбцов / аргументов.

Есть идеи, почему он это делает? Кроме того, если кто-то может помочь с каким-либо альтернативным решением, поскольку мне придется выполнить запрос insert во время выполнения.

Комментарии:

1. Тип выражения задается его членами, а не столбцом / переменной, в которой вы будете хранить результат. Если ни один член выражения не имеет типа nvarchar(max) , все выражение не будет повышено до nvarchar(max) при вычислении, даже если результирующая длина будет больше 4000/8000. Приведите хотя бы один из членов выражения к nvarchar(max) .

2. ПРИВЕТ @GSerg, я сохранил данные в NVARCHAR (MAX), который составляет experssion. Не знаю, должен ли я делать что-нибудь еще

3. ntext более десяти лет не рекомендуется. Прошло слишком много времени для ее обновления / замены.

Ответ №1:

Это задокументировано в (Конкатенация строк) (Transact-SQL) — Примечания:

Если результат конкатенации строк превышает ограничение в 8000 байт, результат усекается. Однако, если хотя бы одна из объединенных строк имеет тип большого значения, усечение не происходит.

Для varchar 8000 байт будет 8000 символов, а для nvarchar 4000.

Все ваши литеральные строки в запросе INSERT INTO TMPRESULTS SELECT ('A' ',' 'B' ',' 'C') представляют собой небольшие типы значений (фактически, все они являются a varchar(1) ). Если вы CONVERT / CAST один из них в a varchar(MAX) , это решит проблему:

 INSERT INTO TMPRESULTS
SELECT (CONVERT(varchar(MAX),'A')   ','   'B'   ','   'C');
  

если вам нужен an nvarchar , убедитесь, что вы также объявляете свои литеральные строки как a nvarchar :

 INSERT INTO TMPRESULTS
SELECT (CONVERT(nvarchar(MAX),N'A')   N','   N'B'   N','   N'C');
  

Ответ №2:

В SQL Server 2017 года и далее есть функция CONCAT_WS для простого выполнения конкатенации. Вы также можете прочитать о CONCAT

Итак, вместо этого:

 INSERT INTO TMPRESULTS SELECT ('A'   ','   'B'   ','   'C')
  

Мы можем иметь ниже:

 INSERT INTO TMPRESULTS SELECT CONCAT_WS(CAST(N',' AS NVARCHAR(MAX)),'A','B','C'))
  

Ниже я привел пример из SQL Server 2017 для справки:

 CREATE TABLE #tempValue(BigValue NVARCHAR(MAX))

INSERT INTO #tempValue
SELECT CONCAT_WS(CAST(N',' AS NVARCHAR(MAX)),REPLICATE('A',4000),REPLICATE('B',4000),REPLICATE('C',4000))

SELECT LEN(BigValue) FROM #tempValue -- 12002
  

Кроме того, CONCAT_WS лучше по следующим причинам:

Если CONCAT_WS получает аргументы со всеми нулевыми значениями, он вернет пустую строку типа varchar(1).

CONCAT_WS игнорирует нулевые значения во время конкатенации и не добавляет разделитель между нулевыми значениями.

Комментарии:

1. Хотя использование concat_ws может выглядеть более чистым, это не имеет ничего общего с проблемой усечения. select cast(CONCAT_WS(',', replicate('A', 4000), replicate('B', 4000), replicate('C', 4000)) as nvarchar(max)) результат все равно будет усечен до 8000 символов.

2. @GSerg, спасибо. Я обновил свой ответ. Если один из параметров равен NVARCHAR(MAX), CONCAT_WS автоматически преобразует возвращаемый тип как NVARCHAR(MAX)