Регистронезависимый поиск в Oracle

по умолчанию LIKE и другие операторы сравнения:= etc чувствителен к регистру.

возможно ли сделать их нечувствительными к регистру?

6 ответов


начиная с 10gR2, Oracle позволяет точно настроить поведение сравнения строк, установив NLS_COMP и NLS_SORT параметры сессии:

SQL> SET HEADING OFF
SQL> SELECT *
  2  FROM NLS_SESSION_PARAMETERS
  3  WHERE PARAMETER IN ('NLS_COMP', 'NLS_SORT');

NLS_SORT
BINARY

NLS_COMP
BINARY


SQL>
SQL> SELECT CASE WHEN 'abc'='ABC' THEN 1 ELSE 0 END AS GOT_MATCH
  2  FROM DUAL;

         0

SQL>
SQL> ALTER SESSION SET NLS_COMP=LINGUISTIC;

Session altered.

SQL> ALTER SESSION SET NLS_SORT=BINARY_CI;

Session altered.

SQL>
SQL> SELECT *
  2  FROM NLS_SESSION_PARAMETERS
  3  WHERE PARAMETER IN ('NLS_COMP', 'NLS_SORT');

NLS_SORT
BINARY_CI

NLS_COMP
LINGUISTIC


SQL>
SQL> SELECT CASE WHEN 'abc'='ABC' THEN 1 ELSE 0 END AS GOT_MATCH
  2  FROM DUAL;

         1

вы также можете создавать индексы без учета регистра:

create index
   nlsci1_gen_person
on
   MY_PERSON
   (NLSSORT
      (PERSON_LAST_NAME, 'NLS_SORT=BINARY_CI')
   )
;

эта информация была взята из Oracle case нечувствительные поиски. В статье упоминается REGEXP_LIKE но это, кажется, работает со старым добрым = как хорошо.


в версиях старше 10gR2 это не может быть сделано, и обычный подход, если вам не нужен учитывает диакритические знаки поиск, это просто UPPER() и столбец, и выражение поиска.


существует 3 основных способа выполнения поиска без учета регистра в Oracle без использования полнотекстовых индексов.

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

1. Case ваш столбец и ваша строка одинаково.

вы можете заставить все ваши данные быть одним и тем же случаем, используя UPPER() или LOWER():

select * from my_table where upper(column_1) = upper('my_string');

или

select * from my_table where lower(column_1) = lower('my_string');

если column_1 не индексируется на upper(column_1) или lower(column_1), при необходимости, это может привести к полному сканированию таблицы. Чтобы избежать этого, вы можете создать ; цитата:

точные операторы и предложения запроса, которые подчиняются параметру NLS_SORT зависит от значения параметра NLS_COMP. Если оператор или предложение не подчиняется значению NLS_SORT, как определено NLS_COMP, используемые параметры сортировки являются двоичными.

значение по умолчанию NLS_COMP является двоичным; но, LINGUISTIC указывает, что Oracle должен обратите внимание на значение NLS_SORT:

сравнения для всех операций SQL в предложении WHERE и в PL / SQL блоки должны использовать лингвистическую сортировку, указанную в NLS_SORT параметр. Для повышения производительности можно также определить лингвистический индекс столбца, для которого требуется лингвистический индекс сравнения.

Итак, еще раз, вам нужно изменить сеанс

alter session set nls_comp=LINGUISTIC

как отмечено в документации, вы можете создать лингвистические индекс для повышения производительности

create index my_linguistc_index on my_table 
   (NLSSORT(column_1, 'NLS_SORT = BINARY_CI'));

может быть, вы можете попробовать использовать

SELECT user_name
FROM user_master
WHERE upper(user_name) LIKE '%ME%'

из Oracle 12c R2 вы можете использовать COLLATE operator:

оператор COLLATE определяет параметры сортировки для выражения. Этот оператор позволяет переопределить параметры сортировки, которые база данных производила бы для выражения, используя стандартные правила вывода параметров сортировки.

оператор сортировки принимает один аргумент, collation_name, для которого можно указать именованную сортировку или псевдо-сортировку. Если имя сортировки содержит пробелы, вы должны заключить имя в двойные кавычки.

демо:

CREATE TABLE tab1(i INT PRIMARY KEY, name VARCHAR2(100));

INSERT INTO tab1(i, name) VALUES (1, 'John');
INSERT INTO tab1(i, name) VALUES (2, 'Joe');
INSERT INTO tab1(i, name) VALUES (3, 'Billy'); 
--========================================================================--
SELECT /*csv*/ *
FROM tab1
WHERE name = 'jOHN' ;
-- no rows selected

SELECT /*csv*/ *
FROM tab1
WHERE name COLLATE BINARY_CI = 'jOHN' ;
/*
"I","NAME"
1,"John"
*/

SELECT /*csv*/ *
FROM tab1 
WHERE name LIKE 'j%';
-- no rows selected

SELECT /*csv*/ *
FROM tab1 
WHERE name COLLATE BINARY_CI LIKE 'j%';
/*
"I","NAME"
1,"John"
2,"Joe"
*/

select user_name
from my_table
where nlssort(user_name, 'NLS_SORT = Latin_CI') = nlssort('%AbC%', 'NLS_SORT = Latin_CI')

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

where regexp_like(name, 'string$', 'i');