Як побудувати запит SQL (MS SQL Server), де речення "де" не враховує регістр?
SELECT * FROM myTable WHERE myField = 'sOmeVal'
Я хочу, щоб результати повернулись, ігноруючи справу
Як побудувати запит SQL (MS SQL Server), де речення "де" не враховує регістр?
SELECT * FROM myTable WHERE myField = 'sOmeVal'
Я хочу, щоб результати повернулись, ігноруючи справу
Відповіді:
У конфігурації бази даних SQL Server за замовчуванням порівняння рядків не враховує регістр. Якщо ваша база даних замінює цей параметр (за допомогою альтернативного порівняння), вам потрібно буде вказати, який тип порівняння використовувати у вашому запиті.
SELECT * FROM myTable WHERE myField = 'sOmeVal' COLLATE SQL_Latin1_General_CP1_CI_AS
Зауважте, що зіставлення, яке я надав, є лише прикладом (хоча воно, з більшою ймовірністю, для вас буде функціонувати чудово). Більш детальний опис порівнянь SQL Server можна знайти тут .
UPPER
або LOWER
регістр, а потім використовуючи LIKE
для пошуку?
Зазвичай порівняння рядків не враховують регістр. Якщо ваша база даних налаштована на співставлення з урахуванням регістру, вам потрібно змусити використовувати регістр, який не враховує регістр:
SELECT balance FROM people WHERE email = 'billg@microsoft.com'
COLLATE SQL_Latin1_General_CP1_CI_AS
Я знайшов інше рішення в іншому місці; тобто використовувати
upper(@yourString)
але всі тут говорять, що в SQL Server це не має значення, бо це все одно ігнорує регістр? Я майже впевнений, що наша база даних чує регістр.
Найпопулярніші 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 нижче.
Інші чотири відповіді хибні в різному ступені.
Я роз'ясню всі непорозуміння тут, щоб читачі могли сподіватися зробити найбільш прийнятний / ефективний вибір.
Не використовувати UPPER()
. Це абсолютно непотрібна зайва робота. Використовуйте COLLATE
речення. Порівняння рядків потрібно зробити в будь-якому випадку, але використовуючи UPPER()
також потрібно перевірити, символ за символом, щоб перевірити, чи є відображення верхнього регістру, а потім змінити його. І робити це потрібно з обох сторін. Додавання COLLATE
просто спрямовує обробку на створення ключів сортування з використанням іншого набору правил, ніж це було за замовчуванням. Використання COLLATE
, безумовно, є більш ефективним (або "продуктивним", якщо вам подобається це слово :), ніж використання UPPER()
, як доведено у цьому тестовому сценарії (на PasteBin) .
Є також проблема, яку зазначає @Ceisc у відповіді @ Danny:
У деяких мовах перетворення випадків не здійснюється в обидва кінці. тобто LOWER (x)! = LOWER (UPPER (x)).
Поширеним прикладом є турецька літера “İ”.
Ні, сортування не є налаштуванням для всієї бази даних, принаймні не в цьому контексті. Існує порівняння за замовчуванням на рівні бази даних, і воно використовується як за замовчуванням для змінених та новостворених стовпців, які не вказують COLLATE
речення (що, ймовірно, звідки походить ця поширена помилка), але це не впливає безпосередньо на запити, якщо ви не порівнюючи рядкові літерали та змінні з іншими рядковими літералами та змінними, або ви посилаєтесь на метадані на рівні бази даних.
Ні, порівняння не відповідає запиту.
Сортування здійснюється за предикатом (тобто чимось операндом) або виразом, а не за запитом. І це справедливо для всього запиту, а не лише для цього WHERE
пункту. Це охоплює ПРИЄДНАННЯ, ГРУПУВАТИ, ЗАМОВИТИ, РОЗДІЛИТИ, тощо.
Ні, не перетворюйте на VARBINARY
(наприклад convert(varbinary, myField) = convert(varbinary, 'sOmeVal')
) з таких причин:
_BIN2
якщо ви використовуєте SQL Server 2008 або новішу версію, інакше вам не залишається іншого вибору, як використовувати той, який закінчується на _BIN
. Якщо дані є, NVARCHAR
то не має значення, яку локаль ви використовуєте, оскільки в такому випадку вони однакові, отже, Latin1_General_100_BIN2
завжди працює. Якщо дані VARCHAR
, ви повинні використовувати один і той же локаль , що дані в даний час (наприклад Latin1_General
, French
, Japanese_XJIS
і т.д.) , так як локаль визначає кодову сторінку, яка використовується, і зміни коду сторінки можуть змінювати дані (тобто втрати даних).CONVERT()
ним буде використовуватися значення за замовчуванням 30. Небезпека полягає в тому, що якщо рядок може перевищувати 30 байт, він буде мовчки скорочений, і ви, ймовірно, отримаєте неправильні результати від цього предиката.Ні, LIKE
не завжди враховується регістр. Він використовує сортування стовпця, на який посилається, або сортування бази даних, якщо змінна порівнюється з рядковим літералом, або сортування, вказане за допомогою додаткового COLLATE
речення.
LCASE
не є функцією SQL Server. Здається, це або Oracle, або MySQL. Або, можливо, Visual Basic?
Оскільки контекст питання полягає у порівнянні стовпця із рядковим літералом, ні сортування екземпляра (який часто називають "сервером"), ні сортування бази даних тут не мають прямого впливу. Порівняння зберігаються в кожному стовпці, і кожен стовпець може мати різний порядок порівняння, і ці збірки не повинні бути однаковими, як порівняння за замовчуванням бази даних або порівняння екземпляра. Звичайно, збірка примірника є типовим для того, що новостворена база даних використовуватиме як зіставлення за замовчуванням, якщо COLLATE
речення не було вказано під час створення бази даних. І так само, порівняння за замовчуванням бази даних - це те, що буде використовувати змінений або щойно створений стовпець, якщо COLLATE
речення не було вказано.
Ви повинні використовувати нечутливий до регістру сортування, який інакше відповідає сортуванню стовпця. Використовуйте такий запит, щоб знайти порівняння стовпців (змініть ім’я таблиці та ім’я схеми):
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[_]%';
Для отримання додаткової інформації про порівняння, кодування тощо, будь-ласка, відвідайте: Інформація про зіставлення
Ні, лише використання LIKE
не буде працювати. LIKE
здійснює пошук значень, що точно відповідають заданому шаблону. У цьому випадку LIKE
буде знайдено лише текст "sOmeVal", а не "someval".
Практичним рішенням є використання LCASE()
функції. LCASE('sOmeVal')
отримує рядок тексту в нижньому регістрі: 'someval'. Якщо ви використовуєте цю функцію для обох сторін порівняння, вона працює:
SELECT * FROM myTable WHERE LCASE(myField) LIKE LCASE('sOmeVal')
Оператор порівнює два рядки в нижньому регістрі, так що ваш 'sOmeVal' збігатиметься з усіма іншими позначеннями 'someval' (наприклад, 'Someval', 'sOMEVAl' тощо).
LCASE()
у SQL Server (принаймні не те, що я бачу). Я думаю, що ця відповідь стосується зовсім іншої СУБД. Будь ласка, перегляньте мою відповідь для роз’яснень щодо порівняння рядків.
Ви можете примусити чутливий регістр, перекинувши на такий варіант:
SELECT * FROM myTable
WHERE convert(varbinary, myField) = convert(varbinary, 'sOmeVal')
У якій базі даних ви знаходитесь? У MS SQL Server це налаштування для всієї бази даних, або ви можете перевиконати його за запитом за допомогою ключового слова COLLATE.
WHERE
заяви, і це вплине на всіWHERE
пункти, правильно?