#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
не может стать annvarchar
без преобразования, будь то явное или неявное, @David . Никакое значение не может изменить свой тип данных, если не выполняется какое-либо преобразование (которое включает в себя переход от не-MAX
кMAX
длине и наоборот).3. Допустим, у меня есть фиксированная длина данных, например, «David», как я могу определить количество байтов в SQL Server и является ли оно ASCII или UNICODE? Я знаю, что ASCII является подмножеством UNICODE, но как проверить, достаточно ли ASCII?
4. Чтобы получить размер строкового типа в SQL Server, @David , вы бы использовали
DATALENGTH
. Хотя здесь вы начинаете переходить к новому вопросу.5. @David Смотри
SQL_Variant_Property
. для способа проверки типов данных, размеров, … .