Oracle에서 대소 문자를 구분하지 않는 검색


228

기본 동작 LIKE및 기타 비교 연산자 =등은 대소 문자를 구분합니다.

대소 문자를 구분하지 않습니까?


user_name에 인덱스가 있어도 일부 예제 검색으로 인해 전체 테이블 스캔이 발생 함을 알립니다.
JonSG

8
REGEXP_LIKE(username,'me','i')LIKE 대신 사용을 고려 했습니까 ?
kubanczyk

5
아니, LIKE는 나를 위해 잘 작동
sergionni

답변:


82

10gR2부터 Oracle은 NLS_COMPNLS_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 검색 에서 가져온 것입니다 . 이 기사는 언급 REGEXP_LIKE하지만 좋은 오래된 =것으로도 작동하는 것 같습니다 .


10gR2 이전의 버전에서는 실제로 수행 할 수 없으며 악센트에 구애받지 않는 검색이 필요하지 않은 경우 일반적인 접근 방식 UPPER()은 열과 검색 표현식 모두입니다.


1
이것은 잘 작동하지만 LIKE / = 연산자를 사용하여 업데이트를 매우 느리게 만듭니다 ... :(
Saqib Ali

1
@SaqibAli 임의의 LIKE표현 (예 :) WHERE foo LIKE '%abc%'은 색인을 생성 할 수 없다면 이미 충분히 느립니다. 특히 대소 문자 구분과 관련이 있다고 생각하지 않습니다.
Álvaro González

1
쉘 환경에서와 같이 SQLPLUS 외부에서이를 설정할 수도 있습니다. 예를 들어 Perl 스크립트에서 `DBI-> connect`를 호출하기 전에 DBD::Oracle작성할 수 있습니다 $ENV{NLS_SORT} = 'BINARY_CI'; $ENV{NLS_COMP} = 'LINGUISTIC';.
mivk

ALTER SESSION수정의 로컬 인스턴스 만 변경하고 현재 세션과 같은 의미입니다. 즉, 닫았다가 다시 열면 재설정되었을 것입니다. 현재의 값이 무엇인지 알 수있는 방법이 있습니까? 어디에서나 지속되는 경우 원래 설정으로 다시 변경할 수 있습니다.
Seabizkit

305

전체 텍스트 인덱스를 사용하지 않고 Oracle에서 대소 문자를 구분하지 않는 검색을 수행하는 3 가지 주요 방법이 있습니다.

궁극적으로 어떤 방법을 선택 하느냐는 개인의 상황에 따라 다릅니다. 기억해야 할 것은 성능을 향상 시키려면 대소 문자를 구분하지 않는 검색을 위해 올바르게 색인을 작성해야한다는 것입니다.

1. 열과 문자열을 동일하게 입력하십시오.

당신은 사용하여 동일한 경우로 모든 데이터를 강제로 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)

create index my_index on my_table ( lower(column_1) );

LIKE를 사용하는 경우 %검색하려는 문자열 주위 를 연결해야합니다 .

select * from my_table where lower(column_1) LIKE lower('my_string') || '%';

이 SQL Fiddle 은 이러한 모든 쿼리에서 발생하는 상황을 보여줍니다. 설명 계획은 인덱스가 사용되는시기와 사용되지 않는시기를 나타냅니다.

2. 정규식을 사용하십시오.

Oracle 10g부터 REGEXP_LIKE()사용할 수 있습니다. 'i'대소 문자를 구분하지 않는 검색을 수행하기 위해 _match_parameter_를 지정할 수 있습니다 .

이것을 항등 연산자로 사용하려면 문자열의 시작과 끝을 지정해야하며 캐럿과 달러 기호로 표시됩니다.

select * from my_table where regexp_like(column_1, '^my_string$', 'i');

LIKE와 동등한 기능을 수행하기 위해 LIKE를 제거 할 수 있습니다.

select * from my_table where regexp_like(column_1, 'my_string', 'i');

문자열에 정규식 엔진에서 다르게 해석되는 문자가 포함될 수 있으므로주의하십시오.

이 SQL Fiddle 은 REGEXP_LIKE ()를 사용하는 것을 제외하고 동일한 출력 예를 보여줍니다.

3. 세션 레벨에서 변경하십시오.

NLS_SORT의 매개 변수는 주문 및 다양한 비교 연산자를 포함에 대한 정렬 순서 지배 =와 LIKE를. 세션을 변경하여 대소 문자를 구분하지 않는 이진 정렬을 지정할 수 있습니다. 이는 해당 세션에서 수행 된 모든 쿼리가 대소 문자를 구분하지 않는 매개 변수를 수행함을 의미합니다.

alter session set nls_sort=BINARY_CI

다른 언어를 지정하거나 BINARY_AI를 사용하여 악센트에 구애받지 않는 검색을 수행하려는 경우 언어 정렬 및 문자열 검색에 대한 추가 정보가 많이 있습니다 .

NLS_COMP 매개 변수도 변경해야합니다 . 인용 :

NLS_SORT 매개 변수를 따르는 정확한 연산자 및 쿼리 절은 NLS_COMP 매개 변수의 값에 따라 다릅니다. 연산자 또는 절이 NLS_COMP에 의해 결정된 NLS_SORT 값을 준수하지 않으면 사용 된 데이터 정렬은 BINARY입니다.

NLS_COMP의 기본값은 BINARY입니다. 그러나 LINGUISTIC은 Oracle이 NLS_SORT의 가치에주의를 기울여야한다고 지정합니다.

WHERE 절과 PL / SQL 블록의 모든 SQL 연산을 비교하려면 NLS_SORT 매개 변수에 지정된 언어 정렬을 사용해야합니다. 성능을 향상시키기 위해 언어 비교를 원하는 열에 언어 색인을 정의 할 수도 있습니다.

다시 한 번 세션을 변경해야합니다.

alter session set nls_comp=LINGUISTIC

문서에서 언급했듯이 언어 색인 을 작성하여 성능을 향상시킬 수 있습니다.

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

이 만들 수있는 차이 놀라운 "함수 기반 인덱스 생성"
야곱 Goulden의 근무지

select * from my_table where lower(column_1) LIKE lower('my_string') || '%';대신 왜 다른지 물어봐도 select * from my_table where lower(column_1) LIKE lower('my_string%');될까요? 이점이 있습니까?
lopezvit

1
한 가지 이유는 (대부분의 상황에서) 쿼리가 매개 변수화 된 경우 호출 코드가 항상 @lopezvit의 끝에 %를 연결할 필요는 없습니다.
Ben

1
의 결과를 망칠 문자 regexp_like가있는 경우 그러한 문자열을 벗어날 수있는 방법이 있습니까? 예를 들어 문자열에 $가 있으면 출력이 예상과 다릅니다. // cc @Ben과 다른 사람들은 공유하십시오.
bozzmob

2
` 이스케이프 문자 @bozzmob입니다. 정규 표현식이 작동하는 문자열에가 포함되어 있으면 출력에 차이가 없어야합니다. 정규 표현식 $$리터럴 이 필요한 경우에만 문제가 발생할 수 있습니다 . 특정 문제가있는 경우이 의견 / 응답이 도움이되지 않은 경우 다른 질문을합니다.
Ben

51

어쩌면 당신은 사용해 볼 수 있습니다

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

3
입력 매개 변수가 전체 대문자 일 때 작동하며, 낮거나 혼합되지 않은 경우
sergionni

13
WHERE upper(user_name) LIKE UPPER('%ME%')그때 생각해 봤어 ? :)
Konerak

3
@sergionni 당신은 또한 검색어를 대문자로 사용해야합니다!
Markus Winand

3
@sergionni, 그렇다면 UPPER입력 매개 변수 를 사용하지 않는 이유는 무엇입니까?
Czechnology

5
@ V4Vendetta upper는 인덱스를 잃는 기능을 사용합니다. 인덱스를 사용하여 검색하는 방법을 알고 있습니까?
jcho360

7

Oracle 12c R2에서 다음을 사용할 수 있습니다 COLLATE operator.

COLLATE 연산자는 표현식의 데이터 정렬을 결정합니다. 이 연산자를 사용하면 표준 데이터 정렬 파생 규칙을 사용하여 데이터베이스가 식에 대해 파생 한 데이터 정렬을 재정의 할 수 있습니다.

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"
*/

db <> 바이올린 데모


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

%두 번째 주장에서 ' NLSSORT은 (는) 와일드 카드 가 아닙니다 . 그들은 혼란스러워합니다.
Stefan van den Akker 12

1

당신은 그런 것을 할 수 있습니다 :

where regexp_like(name, 'string$', 'i');
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.