Функція LEN, що не включає пробіли в SQL Server


109

У мене є така тестова таблиця в 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 за допомогою функції LQL () SQL Server, він не рахує пробіли, наприклад:

-- 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

Як я включаю проміжки проміжків у результат довжини?


1
Я думаю, що справжнє рішення тут може полягати в тому, щоб Microsoft виправити їхнє зламане програмне забезпечення. Проголосуйте тут: feedback.azure.com/forums/908035-sql-server/suggestions/…
QA Collective

Відповіді:


125

Це чітко задокументовано 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

52
ПРИМІТКА. Тому DATALENGTHщо вам також потрібно буде розділити результат на 2, якщо випробуваний вираз має широкий тип символів (Unicode; nchar, nvarchar або ntext), оскільки результат знаходиться в байтах , а не символах .
devstuff

7
Крім того, і varcharт. Д. Це може бути залежно від співставлення і навіть надійний поділ на 2 не є надійним. Дивіться приклад тут
Мартін Сміт

18
Я б користувався LEN(REPLACE(expr, ' ', '_')). Це має працювати з varcharі nvarcharрядками, що містять спеціальні символи управління unicode.
Олів'є Якот-Дескомбс

6
-1, DATALENGTH()не слід вважати альтернативним способом підрахунку символів, оскільки він рахує байти замість символів, і це має значення при поданні тієї ж строки в VARCHAR/ NVARCHAR.
binki

5
Починаючи з SQL сервера 2012, стовпці unicode із зібранням версії 100 тепер підтримують сурогатні пари. Це означає, що один символ може використовувати до 4 байтів, що призводить до невдачі поділу на два трюки. Див. Msdn .
Фредерік

85

Ви можете використовувати цей трюк:

LEN (Str + 'x') - 1


15
Не могли б ви просвітити нас кращими альтернативами, будь ласка? Немає даних про довжину даних.
Серж

15
Я абсолютно не погоджуюся з тим, що використання непослідовного методу (у деяких випадках ви ділите його результат на 2, а іноді і ні) - кращий варіант. Можливо, є моєму методу майже ефективна ефективність.
Серж

5
Метод @usr Serge є найкращим, IMHO. Простий і елегантний. DATALENGTH є складним: залежно від типу одного / подвійного байту, залежності від мови та мови тощо
Mr. TA

10
Це найкраще, елегантне рішення досі. Мені дуже не байдуже, чи це ВІДПОВІДЬ, як хак чи ні (кодування не стосується почуттів), мені дуже цікаво, що це рішення не має побічних ефектів. Я можу змінити тип даних varchar / nvarchar, і він все ще працює. Хороша робота.
Майк Кескінов

5
Існує застереження через цей побічний ефект. Якщо ви працюєте зі змінною типу nvarchar (4000), а ваша змінна містить рядок 4000 символів, доданий символ буде проігноровано, і ви отримаєте невірний результат (SQL-лена, яка ігнорує пробіли, за винятком 1 ви віднімаєте).
капелюх - зроблено з SOverflow

17

Я використовую цей метод:

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

Я віддаю перевагу цьому над DATALENGTH, тому що це працює з різними типами даних, і я віддаю перевагу над додаванням символу до кінця, тому що вам не потрібно турбуватися про крайній випадок, коли ваша рядок вже на максимальній довжині.

Примітка: я б протестував продуктивність, перш ніж використовувати його на дуже великому наборі даних; хоча я щойно тестував його на 2М рядках, і це було не повільніше, ніж LEN без ЗАМІНИ ...


14

"Як я включаю проміжки проміжків у результат довжини?"

Ви можете когось подати на запит про покращення 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

Посилання на відставку Connect: https://connect.microsoft.com/SQLServer/feedback/details/801381


2
datalengthРішення ще гірше , починаючи з SQL Server 2012, так як він тепер підтримує сурогатні пари в UTF-16, тобто персонаж може використовувати до 4 байт. Дійсно, вони фіксують lenфункцію для дотримання ANSI або принаймні надають виділену функцію для підрахунку знаків, включаючи пробіли.
Фредерік

1
Для цього потрібно використовувати більше посилання для зворотного зв’язку. Неприємно, що цю проблему можна шукати лише через Інтернет. Я витратив майже 2 години, намагаючись зрозуміти, де я помилився у власному коді, перш ніж навіть вважав, що функція LEN () стала причиною мого відключення.
Такофіліак

Я погоджуюся з цим, але повинен дозволити параметру обрізати пробіли .. оскільки це робить порівняння рядків із EF набагато простішим, не потрібно перевіряти, чи є пробіл, включений під час побудови виразного виразу.
ganjeii

9

Існують проблеми з двома голосовими відповідями. Відповідь, яка рекомендує 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), так що правильна відповідь дана навіть для цього. Він також повинен правильно обробляти струни із сурогатними парами.


1
На жаль, ця відповідь більше не працює для рядків, що містять сурогатні пари в SQL Server 2012. Запуск вашої операції на N'x𤭢x' COLLATE Latin1_General_100_CI_AS_SCдає 4, в той час як LENдає 3.
Дуглас

9
@Douglas - Це корисна інформація. Якби тільки Microsoft лише дав нам версію LEN, яка не ігнорує пробіли.
хетч - зроблено з SOverflow

5

Потрібно також переконатися, що ваші дані фактично зберігаються з проміжними пробілами. Коли ANSI PADDING вимкнено (не за замовчуванням):

Останні пробіли у знакових значеннях, вставлених у колонку varchar, обрізані.


3
Я думаю, ви не повинні вимикати ANSI PADDING, оскільки ця настройка застаріла. Наявність його у нестандартному значенні викликає багато невеликих проблем.
usr

4

LEN скорочує пробіли за замовчуванням, тому я виявив, що це спрацьовує, коли ви переміщуєте їх на передню частину

(LEN (ПОВЕРНЕННЯ (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)

Звичайно, не використовуйте це для провідних просторів.


9
Тепер він обрізає провідні простори замість пробілів. Цього ж дня, інша проблема :)
Інженер з

@DaveBoltman Моя пропозиція, ймовірно, все-таки більш суперечлива, але ви можете додатково порівняти довжину TRIM'ed.
Brian J

Це повертає помилку, коли провідні пробіли не враховуються замість пробілів. Дивіться наступний код: declare @TestField varchar(10); SET @TestField = ' abc '; -- Length with spaces is 5. select LEN(REVERSE(@TestField)) -- Returns 4 select LEN(@TestField) -- Returns 4
Metalogic

1

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


0

Якщо ви не любите DATALENGTHчерез проблеми n / varchar, як щодо:

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

яка справедлива

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

обернутий захистом від поділу до нуля.

Розділивши ДАТАЛЕНТНІСТЬ одного знаку, ми отримаємо нормалізовану довжину.

(Звичайно, все-таки проблеми із сурогатними парами, якщо це хвилює.)


-4

використовувати SELECT DATALENGTH ('рядок')


2
Ви просто переробили відповіді інших людей на 7 років раніше і не запропонували нічого нового або навіть пояснили, що ви відповідаєте, або як вони відповідають на це питання.
Jpsh
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.