Функция LEN без учета пробелов в SQL Server - PullRequest
101 голосов
/ 08 января 2010

У меня есть следующая тестовая таблица в SQL Server 2005:

CREATE TABLE [dbo].[TestTable]
(
 [ID] [int] NOT NULL,
 [TestField] [varchar](100) NOT NULL
) 

Заполнено:

INSERT INTO TestTable (ID, TestField) VALUES (1, 'A value');   -- Len = 7
INSERT INTO TestTable (ID, TestField) VALUES (2, 'Another value      '); -- Len = 13 + 6 spaces

Когда я пытаюсь определить длину TestField с помощью функции SQL Server LEN (), он не считает конечные пробелы - например,

-- Note: Also results the grid view of TestField do not show trailing spaces (SQL Server 2005).
SELECT 
 ID, 
 TestField, 
 LEN(TestField) As LenOfTestField, -- Does not include trailing spaces
FROM 
 TestTable

Как включить конечные пробелы в результат длины?

Ответы [ 10 ]

117 голосов
/ 08 января 2010

Это четко задокументировано Microsoft в MSDN на http://msdn.microsoft.com/en-us/library/ms190329(SQL.90).aspx,, в котором говорится, что LEN «возвращает количество символов указанного строкового выражения, исключая конечные пробелы». Это, однако, очень легко пропустить, если вы не насторожены.

Вместо этого вам нужно использовать функцию DATALENGTH - см. http://msdn.microsoft.com/en-us/library/ms173486(SQL.90).aspx - которая "возвращает количество байтов, использованных для представления любого выражения".

Пример:

SELECT 
    ID, 
    TestField, 
    LEN(TestField) As LenOfTestField,           -- Does not include trailing spaces
    DATALENGTH(TestField) As DataLengthOfTestField      -- Shows the true length of data, including trailing spaces.
FROM 
    TestTable
76 голосов
/ 18 июня 2012

Вы можете использовать этот трюк:

LEN (Str + 'x') - 1

12 голосов
/ 17 ноября 2016

Я использую этот метод:

LEN(REPLACE(TestField, ' ', '.'))

Я предпочитаю это, а не DATALENGTH, потому что это работает с разными типами данных, и я предпочитаю это добавлять символ в конец, потому что вам не нужно беспокоиться о крайнем случае, когда ваша строка уже имеет максимальную длину. 1004 *

Примечание: я бы проверил производительность перед ее использованием на очень большом наборе данных; хотя я только что проверил его на 2М рядах, и он не был медленнее, чем ЛЕН без ЗАМЕНЫ ...

12 голосов
/ 18 сентября 2013

«Как включить конечные пробелы в результат длины?»

Вы можете попросить кого-нибудь подать запрос / отчет об улучшении SQL Server, поскольку почти все перечисленные обходные пути к этой удивительно простой проблеме здесь имеют некоторые недостатки или неэффективны. Это все еще кажется верным в SQL Server 2012. Функция автоматической обрезки может быть основана на ANSI / ISO SQL-92, но, похоже, есть некоторые дыры (или их отсутствие).

Пожалуйста, проголосуйте "Добавить настройку, чтобы LEN считал конечные пробелы" здесь:

https://feedback.azure.com/forums/908035-sql-server/suggestions/34673914-add-setting-so-len-counts-trailing-whitespace

Пенсионер Соединить ссылку: https://connect.microsoft.com/SQLServer/feedback/details/801381

8 голосов
/ 01 января 2015

Есть проблемы с двумя наиболее популярными ответами. Ответ с рекомендацией DATALENGTH подвержен ошибкам программиста. Результат DATALENGTH должен быть разделен на 2 для NVARCHAR типов, но не для VARCHAR типов. Это требует знания типа, длина которого вы получаете, и если этот тип меняется, вы должны старательно менять места, которые вы использовали DATALENGTH.

Существует также проблема с ответом, получившим наибольшее количество голосов (который, я признаю, был моим предпочтительным способом сделать это, пока эта проблема не укусила меня). Если значение, которое вы получаете, имеет тип NVARCHAR(4000) и фактически содержит строку из 4000 символов, SQL будет игнорировать добавленный символ, а не неявно приводить результат к NVARCHAR(MAX). Конечный результат - неправильная длина. То же самое произойдет с VARCHAR (8000).

То, что я нашел, работает почти так же быстро, как обычный LEN, быстрее, чем LEN(@s + 'x') - 1 для больших строк, и не предполагает, что нижележащая ширина символа следующая:

DATALENGTH(@s) / DATALENGTH(LEFT(LEFT(@s, 1) + 'x', 1))

Получается длина данных, а затем делится на длину данных одного символа из строки. Добавление 'x' охватывает случай, когда строка пуста (что в этом случае даст деление на ноль). Это работает независимо от того, является ли @s VARCHAR или NVARCHAR. Выполнение LEFT из 1 символа перед добавлением бреет некоторое время, когда строка большая. Однако проблема в том, что он некорректно работает со строками, содержащими суррогатные пары.

В комментарии к принятому ответу упоминается другой способ, использующий REPLACE(@s,' ','x'). Этот метод дает правильный ответ, но на пару порядков медленнее, чем другие методы при большой длине строки.

Учитывая проблемы, создаваемые суррогатными парами для любой техники, использующей DATALENGTH, я думаю, что самый безопасный метод, который дает правильные ответы, о которых я знаю, заключается в следующем:

LEN(CONVERT(NVARCHAR(MAX), @s) + 'x') - 1

Это быстрее, чем REPLACE техника, и намного быстрее с более длинными строками. По сути, это техника LEN(@s + 'x') - 1, но с защитой для краевого случая, когда строка имеет длину 4000 (для nvarchar) или 8000 (для varchar), так что правильный ответ дается даже для этого. Он также должен правильно обрабатывать строки с суррогатными парами.

5 голосов
/ 08 января 2010

Вы также должны убедиться, что ваши данные действительно сохраняются с конечными пробелами. Когда ANSI PADDING выключено (не по умолчанию):

Конечные пробелы в символьных значениях вставлены в столбец varchar являются обрезается.

4 голосов
/ 07 января 2013

LEN обрезает конечные пробелы по умолчанию, поэтому я обнаружил, что это работает, когда вы перемещаете их вперед

(LEN (REVERSE (TestField))

Так что, если бы вы хотели, вы могли бы сказать

SELECT
t.TestField,
LEN(REVERSE(t.TestField)) AS [Reverse],
LEN(t.TestField) AS [Count]
FROM TestTable t
WHERE LEN(REVERSE(t.TestField)) <> LEN(t.TestField)

Конечно, не используйте это для начальных пробелов.

1 голос
/ 21 октября 2014

Вы должны определить функцию CLR, которая возвращает поле длины строки, если вам не нравится конкатенация строк.Я использую LEN('x' + @string + 'x') - 2 в своих производственных случаях.

0 голосов
/ 22 января 2017

использовать SELECT DATALENGTH ('строка')

0 голосов
/ 05 января 2017

Если вам не нравится DATALENGTH из-за проблем с n / varchar, как насчет:

select DATALENGTH(@var)/isnull(nullif(DATALENGTH(left(@var,1)),0),1)

что просто

select DATALENGTH(@var)/DATALENGTH(left(@var,1))

с защитой от деления на ноль.

Путем деления на DATALENGTH одного символа мы получаем нормированную длину.

(Конечно, проблемы с суррогатными парами все еще возникают, если это не проблема.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...