Как заставить SQL Server возвращать FALSE для сравнения varchars с конечными пробелами и без них?

Если я преднамеренно сохраняю конечные пробелы в столбце VARCHAR, как я могу заставить SQL Server рассматривать данные как несоответствующие?

SELECT 'foo' WHERE 'bar' = 'bar    '

Я пытался:

SELECT 'foo' WHERE LEN('bar') = LEN('bar    ')

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

Есть ли метод, который я упустил из виду?

Я заметил, что это не относится к ведущим пробелам, поэтому, возможно, я запускаю функцию, которая инвертирует порядок символов перед сравнением.... проблема в том, что это делает запрос невозможным для поиска....


person Matthew    schedule 15.10.2010    source источник


Ответы (6)


Из документов на LEN (Transact -SQL):

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

Кроме того, на странице поддержки Как SQL Server сравнивает строки с пробелами в конце:

SQL Server следует спецификации ANSI/ISO SQL-92 о том, как сравнивать строки с пробелами. Стандарт ANSI требует заполнения строк символов, используемых при сравнении, чтобы их длины совпадали перед их сравнением.

Обновление: Я удалил свой код, используя LIKE (который не дополняет пробелы во время сравнения) и DATALENGTH(), так как они ненадежны для сравнения строк

Это также было задано во многих других местах, а также для других решений:

person Gennady Vanin Геннадий Вани&    schedule 15.10.2010
comment
Я думаю, что DATALENGTH мне здесь хорошо подойдет, или сохранение вычисленного DATALENGTH в столбце, чтобы сделать его быстрее за счет байта. - person Matthew; 15.10.2010
comment
Это не отвечает на вопрос, как написано. И он ошибочно утверждает, что это дубликат вопросов о поведении, которого этот вопрос явно просит избегать. - person Kenny Evitt; 29.06.2018

вы можете попробовать что-то вроде этого:

declare @a varchar(10), @b varchar(10)
set @a='foo'
set @b='foo   '

select @a, @b, DATALENGTH(@a), DATALENGTH(@b)
person DForck42    schedule 15.10.2010
comment
Ага. SELECT * FROM YourTable WHERE col = @searchterm and DATALENGTH(col) = DATALENGTH(@searchterm) должен по-прежнему быть доступным для анализа. - person Martin Smith; 15.10.2010
comment
это потрясающе Мартин, я пытался придумать способ сделать это. - person DForck42; 15.10.2010

После некоторого поиска самое простое решение, которое я нашел, было у Энтони Блоша WebLog.

Просто добавьте текст (достаточно символа) в конец данных (добавьте)

SELECT 'foo' WHERE 'bar' + 'BOGUS_TXT' = 'bar    ' + 'BOGUS_TXT'

Также работает для «ГДЕ В»

SELECT <columnA>
FROM <tableA>
WHERE <columnA> + 'BOGUS_TXT' in ( SELECT <columnB> + 'BOGUS_TXT' FROM <tableB> )
person Bruno Silva    schedule 17.03.2015
comment
Спасибо за ссылку! В статье также объясняется, почему вы можете предпочесть это DATALENGTH (правильность при наличии меток объединения Unicode). - person Nickolay; 21.01.2021

У меня есть только два предложения. Одним из них было бы пересмотреть дизайн, который требует, чтобы вы сохраняли конечные пробелы - с ними всегда сложно иметь дело в SQL.

Второй (учитывая ваши комментарии с возможностью SARG) будет состоять в том, чтобы добавить вычисляемый столбец в таблицу, в которой хранится длина, и добавить этот столбец в соответствующие индексы. Таким образом, по крайней мере, сравнение длин должно иметь возможность SARG.

person Damien_The_Unbeliever    schedule 15.10.2010
comment
Этот вопрос должен был быть закрыт как обман. Ранее в SO был исчерпывающий и неоднократный ответ, включая дизайн (усечение конечных пробелов), который я дал в своем обновлении, stackoverflow.com/questions/1146280/ - person Gennady Vanin Геннадий Вани&; 15.10.2010
comment
@ vgv8 - я думаю, что это немного отличается тем, что ОП, кажется, говорит, что они должны хранить завершающие пробелы, и что это важно. - person Damien_The_Unbeliever; 15.10.2010

Подход, который я планирую использовать, состоит в том, чтобы использовать обычное сравнение, которое должно быть доступно для индексации («sargable»), дополненное DATALENGTH (поскольку LEN игнорирует пробелы). Это будет выглядеть так:

DECLARE @testValue VARCHAR(MAX) = 'x';

SELECT t.Id, t.Value
FROM dbo.MyTable t
WHERE t.Value = @testValue AND DATALENGTH(t.Value) = DATALENGTH(@testValue)

Оптимизатор запросов должен определить порядок фильтров, но он должен выбрать использование индекса для поиска данных, если это имеет смысл для тестируемой таблицы, а затем дополнительно отфильтровать оставшийся результат по длине с помощью более дорогого скаляра. операции. Однако, как указано в другом ответе, было бы лучше вообще избегать этих скалярных операций, используя индексированный вычисляемый столбец. Представленный здесь метод может иметь смысл, если у вас нет контроля над схемой, или если вы хотите избежать создания вычисляемых столбцов, или если создание и обслуживание вычисляемых столбцов считается более дорогостоящим, чем снижение производительности запросов.

person binki    schedule 13.11.2016

Иногда самое глупое решение — лучшее:

SELECT 'foo' WHERE 'bar' + 'x' = 'bar     ' + 'x'

Таким образом, перед сравнением добавьте любой символ к обеим строкам.

person Extragorey    schedule 06.03.2019
comment
может это так просто? ммм интересное предложение - person Seabizkit; 13.03.2019