SQL-сервер игнорирует регистр в выражении where

Как создать SQL-запрос (MS SQL Server), в котором в предложении «where» не учитывается регистр?

SELECT * FROM myTable WHERE myField = 'sOmeVal'

Я хочу, чтобы результаты возвращались, игнорируя дело


person Raul Agrait    schedule 03.08.2009    source источник


Ответы (7)


В конфигурации базы данных SQL Server по умолчанию сравнение строк выполняется без учета регистра. Если ваша база данных переопределяет этот параметр (за счет использования альтернативного сопоставления), вам необходимо указать, какой тип сопоставления использовать в вашем запросе.

SELECT * FROM myTable WHERE myField = 'sOmeVal' COLLATE SQL_Latin1_General_CP1_CI_AS

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

person Adam Robinson    schedule 03.08.2009
comment
Просто для подтверждения, это нужно добавить только один раз, в конце оператора WHERE, и это повлияет на все предложения WHERE, верно? - person ashleedawg; 03.05.2018
comment
Хотелось бы узнать, есть ли у вашего ответа какие-либо проблемы с производительностью, если преобразовать значение столбца в регистр UPPER или LOWER, а затем использовать LIKE для поиска? - person Shaiju T; 29.08.2018
comment
@ashleedawg - хороший вопрос .. похоже, это настройка для каждой строки. - person Leo Gurdian; 09.10.2018

Обычно сравнение строк не зависит от регистра. Если ваша база данных настроена на сортировку с учетом регистра, вам необходимо принудительно использовать ее без учета регистра:

SELECT balance FROM people WHERE email = '[email protected]'
  COLLATE SQL_Latin1_General_CP1_CI_AS 
person Andrejs Cainikovs    schedule 03.08.2009
comment
@АскеБ. и Андрейс: Технически это не проблема конфигурации базы данных. См. мой ответ для получения пояснений по сравнению строк. - person Solomon Rutzky; 01.02.2019

Я нашел другое решение в другом месте; то есть использовать

upper(@yourString)

но все здесь говорят, что в SQL Server это не имеет значения, потому что он все равно игнорирует регистр? Я почти уверен, что наша база данных чувствительна к регистру.

person Danny    schedule 16.07.2010
comment
Вы правы в том, что базу данных можно сделать чувствительной к регистру, но это довольно неэффективно, даже если это необходимо. COLLATE — ключевое слово для использования. - person mjaggard; 28.06.2012
comment
Спасибо, что подняли эту тему, @mjaggard. Я надеюсь, что вы или кто-либо, кто, кажется, отрицает мой ответ, уточните на благо тех, кто, как я, ищет и находит такие ответы, как мои. - person Danny; 08.12.2012
comment
Проголосовал за это, поскольку это совершенно рациональное объяснение. Сортировка отдает слишком большими накладными расходами, и что, если в вашей строке есть символы, которые не понимает сопоставление? Latin 1 - паршивая схема кодирования. Удачи в получении значимых результатов, если в вашей строке есть апостроф (например: O'Brien). - person eggmatters; 16.02.2013
comment
Также проголосовал. Я могу вспомнить множество случаев, когда это было бы полезно. Кроме того, часто существует более одного хорошего способа сделать что-либо. - person Inversus; 13.04.2013
comment
У нас то же самое. Я использую верхний, например, в некоторых полях ввода пользователя для сравнения с записями БД, где пользователь может не писать заглавными буквами. (если я не могу использовать LIKE) В противном случае я могу порекомендовать также взглянуть на myField LIKE 'someValue'. Однако для LIKE БД должна быть настроена на нечувствительность к регистру (как и большинство из них). - person skofgar; 10.02.2014
comment
Я использую это решение в функции SQL для сравнения строки, переданной пользователем, со строкой, которую я определил как заглавную. Простое решение! - person Mike Richards; 06.11.2014
comment
Изменение регистра строки для целей сравнения, как правило, плохо. В некоторых языках преобразование регистра не выполняется в оба конца. т. е. НИЖНИЙ (x)! = НИЖНИЙ (ВЕРХНИЙ (x)). - person Ceisc; 10.11.2016
comment
@Danny По моему опыту, ваше решение обязательно сработает; однако он будет работать во много раз медленнее. - person Stephen G Tuggy; 28.02.2017
comment
@eggmatters Нет, это не совсем рационально, поскольку доказуемо хуже, чем использование COLLATE. Я понятия не имею, почему вы говорите, что добавление COLLATE {collation_name} к предикату является чрезмерным. Это безосновательное заявление. Идея состоит в том, чтобы использовать нечувствительную к регистру версию сопоставления, которую столбец уже использует, и в этом случае невозможна потеря данных (поскольку нет преобразования кодовой страницы). См. мой ответ для получения пояснений по сравнению строк, особенно в пункте № 1. - person Solomon Rutzky; 01.02.2019
comment
@Ceisc Да, за это, а также потому, что он медленнее. См. мой ответ для получения разъяснений по сравнению строк в SQL Server, особенно в пункте № 1. - person Solomon Rutzky; 01.02.2019

Лучшие 2 ответа (от Адама Робинсона и Андрей Кайников) вроде как правильны в том смысле, что они технически работают, но их объяснения неверны и поэтому во многих случаях могут вводить в заблуждение. Например, хотя сортировка SQL_Latin1_General_CP1_CI_AS будет работать во многих случаях, ее не следует считать подходящей сортировкой без учета регистра. На самом деле, учитывая, что OP работает в базе данных с учетом регистра (или, возможно, двоичного) сопоставления, мы знаем, что OP не использует сопоставление, которое используется по умолчанию для многих установок (особенно для тех, которые установлены в ОС). используя американский английский язык): SQL_Latin1_General_CP1_CI_AS. Конечно, OP может использовать SQL_Latin1_General_CP1_CS_AS, но при работе с данными VARCHAR важно не менять кодовую страницу, так как это может привести к потере данных, и это контролируется языком/культурой сопоставление (т.е. Latin1_General против французского против иврита и т.д.). См. пункт № 9 ниже.

Остальные четыре ответа неверны в той или иной степени.

Я разъясню здесь все недоразумения, чтобы читатели, надеюсь, могли сделать наиболее подходящий/эффективный выбор.

  1. #P4# #P5#
    #P6#
    #P7#
  2. Нет, сопоставление не является настройкой всей базы данных, по крайней мере, не в этом контексте. Существует сопоставление по умолчанию на уровне базы данных, и оно используется по умолчанию для измененных и вновь созданных столбцов, в которых не указано предложение COLLATE (вероятно, отсюда и происходит это распространенное заблуждение), но оно не влияет на запросы напрямую, если вы не сравниваете строковые литералы и переменные с другими строковыми литералами и переменными или ссылаетесь на метаданные уровня базы данных.

  3. Нет, сопоставление не для каждого запроса.

  4. Сопоставления выполняются по предикату (т. е. по операнду что-то) или по выражению, а не по запросу. И это верно для всего запроса, а не только для предложения WHERE. Это касается JOIN, GROUP BY, ORDER BY, PARTITION BY и т. д.

  5. Нет, не конвертируйте в VARBINARY (например, convert(varbinary, myField) = convert(varbinary, 'sOmeVal')) по следующим причинам:

    1. that is a binary comparison, which is not case-insensitive (which is what this question is asking for)
    2. если вам нужно двоичное сравнение, используйте двоичное сопоставление. Используйте тот, который заканчивается на _BIN2, если вы используете SQL Server 2008 или новее, иначе у вас нет другого выбора, кроме как использовать тот, который заканчивается на _BIN. Если данные NVARCHAR, то не имеет значения, какую локаль вы используете, поскольку в этом случае они все одинаковы, поэтому Latin1_General_100_BIN2 работает всегда. Если данные VARCHAR, вы должны использовать ту же локаль, в которой находятся данные в данный момент (например, Latin1_General, French, Japanese_XJIS и т. д.), поскольку локаль определяет используемую кодовую страницу, а изменение кодовых страниц может изменить данные (т. е. потеря).
    3. использование типа данных переменной длины без указания размера будет зависеть от размера по умолчанию, и есть два разных значения по умолчанию в зависимости от контекста, в котором используется тип данных. Это либо 1, либо 30 для строковых типов. При использовании с CONVERT() будет использоваться значение по умолчанию 30. Опасность заключается в том, что если длина строки может превышать 30 байт, она будет автоматически усечена, и вы, скорее всего, получите неверные результаты от этого предиката.
    4. Даже если вам нужно сравнение с учетом регистра, бинарные сопоставления не чувствительны к регистру (еще одно очень распространенное заблуждение).
  6. Нет, LIKE не всегда чувствителен к регистру. Он использует сопоставление столбца, на который ссылаются, или сопоставление базы данных, если переменная сравнивается со строковым литералом, или сопоставление, указанное в необязательном предложении COLLATE.

  7. LCASE не является функцией SQL Server. Похоже, это Oracle или MySQL. Или, возможно, Visual Basic?

  8. Поскольку контекст вопроса сравнивает столбец со строковым литералом, ни сопоставление экземпляра (часто называемого «сервером»), ни сопоставление базы данных не имеют здесь никакого прямого влияния. Параметры сортировки хранятся для каждого столбца, и каждый столбец может иметь разные параметры сортировки, и эти параметры сортировки не обязательно должны быть такими же, как параметры сортировки по умолчанию в базе данных или параметры сортировки экземпляра. Конечно, параметры сортировки экземпляра используются по умолчанию для вновь созданной базы данных в качестве параметров сортировки по умолчанию, если предложение COLLATE не было указано при создании базы данных. Точно так же сопоставление базы данных по умолчанию — это то, что будет использовать измененный или вновь созданный столбец, если не указано условие COLLATE.

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

    SELECT col.*
    FROM   sys.columns col
    WHERE  col.[object_id] = OBJECT_ID(N'dbo.TableName')
    AND    col.[collation_name] IS NOT NULL;
    

    Затем просто измените _CS на _CI. Таким образом, Latin1_General_100_CS_AS станет Latin1_General_100_CI_AS.

    Если в столбце используется двоичная сортировка (оканчивающаяся на _BIN или _BIN2), найдите аналогичную сортировку, используя следующий запрос:

    SELECT *
    FROM   sys.fn_helpcollations() col
    WHERE  col.[name] LIKE N'{CurrentCollationMinus"_BIN"}[_]CI[_]%';
    

    Например, предположив, что столбец использует Japanese_XJIS_100_BIN2, сделайте следующее:

    SELECT *
    FROM   sys.fn_helpcollations() col
    WHERE  col.[name] LIKE N'Japanese_XJIS_100[_]CI[_]%';
    

Дополнительную информацию о сопоставлениях, кодировках и т. д. см. на странице Информация о сопоставлениях.

person Solomon Rutzky    schedule 29.01.2019

Нет, только с помощью LIKE не получится. LIKE ищет значения, точно соответствующие заданному шаблону. В этом случае LIKE найдет только текст "sOmeVal", а не "someval".

Практическим решением является использование функции LCASE(). LCASE('sOmeVal') получает строку вашего текста в нижнем регистре: 'someval'. Если вы используете эту функцию для обеих сторон вашего сравнения, она работает:

SELECT * FROM myTable WHERE LCASE(myField) LIKE LCASE('sOmeVal')

Оператор сравнивает две строки в нижнем регистре, так что ваш «sOmeVal» будет соответствовать любому другому обозначению «someval» (например, «Someval», «sOMEVAl» и т. д.).

person David Hermanns    schedule 02.10.2012
comment
В 99,9% установок SQL Server, которые сопоставлены с _CI, LIKE нечувствителен к регистру. - person RichardTheKiwi; 02.10.2012
comment
В настоящее время функция называется LOWER - person David Brossard; 02.01.2019
comment
@DavidBrossard и Дэвид Херманнс, я не думаю, что это когда-либо было LCASE() в SQL Server (по крайней мере, я не вижу). Я думаю, что этот ответ для совершенно другой СУБД. См. мой ответ для получения пояснений по сравнению строк. - person Solomon Rutzky; 01.02.2019

Вы можете принудительно учитывать регистр, приводя к такому varbinary:

SELECT * FROM myTable 
WHERE convert(varbinary, myField) = convert(varbinary, 'sOmeVal')
person Community    schedule 03.08.2009
comment
Хотя это функционально, это не рекомендуемый подход. Сопоставления предназначены для управления сортировкой и сравнением строк. - person Adam Robinson; 04.08.2009
comment
@AdamRobinson, разве это не сравнение строк? - person Fandango68; 05.12.2016
comment
@ Fandango68 Да, это так, и Адам говорит, что сопоставления лучше при сравнении строк. - person JLRishe; 22.05.2018

Вы в какой базе? В MS SQL Server это параметр для всей базы данных, или вы можете переопределить его для каждого запроса с помощью ключевого слова COLLATE.

person Chase Seibert    schedule 03.08.2009
comment
Всем привет. Для SQL Server, с точки зрения того, о чем этот вопрос, это не параметр для всей базы данных и не для каждого запроса. Подробнее см. мой ответ. - person Solomon Rutzky; 01.02.2019