Как я могу заставить SQL Server возвращать FALSE для сравнения вариантов с конечными пробелами и без них? - PullRequest
11 голосов
/ 15 октября 2010

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

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

Я пытался:

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

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

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

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

Ответы [ 6 ]

6 голосов

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

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

Также со страницы поддержки на Как SQL Server сравниваетСтроки с конечными пробелами :

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

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

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

2 голосов
/ 15 октября 2010

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

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

select @a, @b, DATALENGTH(@a), DATALENGTH(@b)
1 голос
/ 14 ноября 2016

Подход, который я планирую использовать, состоит в том, чтобы использовать нормальное сравнение, которое должно быть индексируемым («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)

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

1 голос
/ 17 марта 2015

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

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

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

Также работает для 'WHERE IN'

SELECT <columnA>
FROM <tableA>
WHERE <columnA> + 'BOGUS_TXT' in ( SELECT <columnB> + 'BOGUS_TXT' FROM <tableB> )
1 голос
/ 15 октября 2010

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

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

0 голосов
/ 07 марта 2019

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

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

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

...