Объединение двух столбцов varchar в select into

#sql-server #tsql

#sql-сервер #tsql

Вопрос:

У меня есть insert into tableA select from someTables и в моем select у меня есть два текстовых столбца, которые я объединяю, например colA colB . У них есть тип varchar(n) . Должен ли столбец в TableA просто быть varchar(2n) ? Это плохо для производительности, если, скажем, у меня есть varchar(5*n) ?

Если два столбца объединены из varchar(n) , возможно ли, что результат больше, чем varchar(2n) или, например nvarchar(3n) ?

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

1. На ваш второй вопрос, нет, это невозможно (за исключением некоторых странностей, возможно, из-за разных кодировок). Да, ваш целевой столбец должен быть достаточно большим, чтобы вместить объединенную строку, если вы не возражаете против потери информации.

2. @TimBiegeleisen. Как насчет nvarchar() части, когда входные varchar данные? Я думаю, это тоже пустая трата …?

3. Проверьте ответ @Larnu ниже. Слишком длинный для одного комментария.

Ответ №1:

Когда вы объединяете 2 (n)varchar значения, результирующий тип данных представляет собой 2 свойства длины, добавленные вместе, или 8000 байт (что всегда меньше). Если вы объединяете a varchar и an nvarchar varchar , они будут неявно приведены к nvarchar первому.

Если хотя бы 1 из объединенных значений не имеет MAX длины, возвращаемый тип данных не будет преобразован в a MAX , а все конечные символы будут усечены.

Рассмотрим приведенные ниже примеры, которые возвращают типы данных их псевдонимов:

 SELECT REPLICATE('A',10)   REPLICATE('B',10) AS varchar20,
       REPLICATE(N'A',10)   REPLICATE(N'B',10) AS nvarchar20,
       REPLICATE(N'A',10)   REPLICATE('B',5) AS nvarchar15,
       REPLICATE('A',5000)   REPLICATE('B',5000) AS varchar8000, --Truncation occurs
       REPLICATE(N'A',3000)   REPLICATE('B',3000) AS nvarchar4000, --Truncation occurs
       REPLICATE(CONVERT(nvarchar(MAX),N'A'),3000)   REPLICATE('B',3000) AS nvarcharMAX;
  

И это можно проверить с помощью dm_exec_describe_first_result_set :

 SELECT [name], system_type_name
FROM sys.dm_exec_describe_first_result_set(N'SELECT REPLICATE(''A'',10)   REPLICATE(''B'',10) AS varchar20,
       REPLICATE(N''A'',10)   REPLICATE(N''B'',10) AS nvarchar20,
       REPLICATE(N''A'',10)   REPLICATE(''B'',5) AS nvarchar15,
       REPLICATE(''A'',5000)   REPLICATE(''B'',5000) AS varchar8000, --Truncation occurs
       REPLICATE(N''A'',3000)   REPLICATE(''B'',3000) AS nvarchar4000, --Truncation occurs
       REPLICATE(CONVERT(nvarchar(MAX),N''A''),3000)   REPLICATE(''B'',3000) AS nvarcharMAX;',NULL, NULL);
  

Очевидно, что если вы объедините 3 (n)varchar значения, то результирующая длина будет суммой 3 значений длины и т.д.

Обратите внимание, что я явно указываю длину 8000 байт, а не 8000 или 4000 символов. Многие путают значение длины для varchar и nvarchar означает количество символов, которые оно может содержать, но на самом деле это не так, это количество байтов; для varchar него это 8000 одиночных байт, а для nvarchar него — 4000 двойных байт. Это гораздо важнее сейчас, когда SQL Server поддерживает параметры сортировки UTF-8.

Например, приведенное ниже возвращает значение 2666 , поскольку символ, который я выбрал случайным образом ( ), использует 3 байта на символ.

 SELECT LEN(REPLICATE(CONVERT(varchar(3),N'◘' COLLATE Latin1_General_100_CI_AI_SC_UTF8),8000));
  

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

1. Спасибо. Могут ли два varchar стать navarchar ? Может быть, глупый вопрос, но просто нужно убедиться, прежде чем я его изменю…

2. A varchar не может стать an nvarchar без преобразования, будь то явное или неявное, @David . Никакое значение не может изменить свой тип данных, если не выполняется какое-либо преобразование (которое включает в себя переход от не- MAX к MAX длине и наоборот).

3. Допустим, у меня есть фиксированная длина данных, например, «David», как я могу определить количество байтов в SQL Server и является ли оно ASCII или UNICODE? Я знаю, что ASCII является подмножеством UNICODE, но как проверить, достаточно ли ASCII?

4. Чтобы получить размер строкового типа в SQL Server, @David , вы бы использовали DATALENGTH . Хотя здесь вы начинаете переходить к новому вопросу.

5. @David Смотри SQL_Variant_Property . для способа проверки типов данных, размеров, … .