Oracle'da büyük / küçük harfe duyarsız arama


228

Ve LIKEdiğer karşılaştırma işleçlerinin varsayılan davranışı büyük / =küçük harfe duyarlıdır.

Onları büyük / küçük harfe duyarsız hale getirmek mümkün mü?


Bazı örnek aramaların, kullanıcı_adı üzerinde bir dizin olsa bile tam tablo taramasıyla sonuçlanacağını hatırlatmak isteriz.
JonSG

8
REGEXP_LIKE(username,'me','i')LIKE yerine kullanmayı düşündünüz mü ?
kubanczyk

5
Hayır,
BENİM

Yanıtlar:


82

10gR2'den beri Oracle, NLS_COMPve NLS_SORTsession parametrelerini ayarlayarak dize karşılaştırmalarının davranışında ince ayar yapmaya izin verir :

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

Büyük / küçük harfe duyarlı olmayan dizinler de oluşturabilirsiniz:

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

Bu bilgiler, Oracle'ın büyük / küçük harfe duyarlı olmayan aramalarından alınmıştır . Makale bahsediyor REGEXP_LIKEama iyi eski =ile de çalışıyor gibi görünüyor .


10gR2'den eski sürümlerde bu gerçekten yapılamaz ve aksan duyarsız aramaya ihtiyacınız yoksa, normal yaklaşım UPPER()hem sütun hem de arama ifadesidir.


1
Bu iyi çalışıyor, ancak GÜNCELLEMELERİ GİBİ / = operatörlerini kullanarak çok yavaş yapıyor ...... :(
Saqib Ali

1
@SaqibAli Keyfi LIKEifadeler (örneğin WHERE foo LIKE '%abc%') dizine eklenemezlerse yeterince yavaşlar, özellikle büyük / küçük harf duyarlılığıyla ilgili olduğunu düşünmüyorum.
Álvaro González

1
Bunları, kabuk ortamında olduğu gibi SQLPLUS dışında da ayarlayabilirsiniz. Örneğin, Perl betiğinde şunu kullanarak DBD::Oracle, $ENV{NLS_SORT} = 'BINARY_CI'; $ENV{NLS_COMP} = 'LINGUISTIC';`DBI-> connect` çağırmadan önce yazabilirsiniz.
mivk

hey ALTER SESSIONsadece düzeltme yerel örneğinizi değiştirir ve geçerli oturum gibi yani yani kapatıp yeniden açarsanız sıfırlama olurdu anlamına mı geliyor. Mevcut değerlerin ne olduğunu görebilmemin bir yolu var mı, eğer her yerde ısrar ederse orijinal ayarlara geri dönebilirim ...
Seabizkit

305

Oracle'da tam metin dizinleri kullanmadan büyük / küçük harfe duyarlı olmayan bir arama yapmanın 3 ana yolu vardır.

Nihayetinde hangi yöntemi seçtiğiniz bireysel koşullarınıza bağlıdır; hatırlanması gereken en önemli şey, performansı artırmak için büyük / küçük harfe duyarlı olmayan arama için doğru bir şekilde indekslemeniz gerektiğidir.

1. Sütununuzu ve dizenizi aynı şekilde kullanın.

Sen kullanarak aynı durumda olmak tüm verilerinizi zorlayabilir UPPER()ya LOWER():

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

veya

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

Eğer column_1üzerinde endeksli değildir upper(column_1)ya lower(column_1)uygun olarak, bu tam bir tablo taraması zorlayabilir. Bundan kaçınmak için işlev tabanlı bir dizin oluşturabilirsiniz .

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

LIKE kullanıyorsanız %, aradığınız dizenin etrafında bir araya getirmeniz gerekir .

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

Bu SQL Fiddle , tüm bu sorgularda neler olduğunu gösterir. Bir dizinin ne zaman kullanıldığını ve ne zaman kullanılmadığını gösteren Açıklama Planlarını not edin.

2. Normal ifadeler kullanın.

Oracle 10g'den itibaren REGEXP_LIKE()kullanılabilir. Büyük / 'i'küçük harfe duyarlı olmayan arama yapmak için _match_parameter_ belirtebilirsiniz .

Bunu bir eşitlik operatörü olarak kullanmak için, karat ve dolar işareti ile belirtilen dizenin başlangıcını ve bitişini belirtmelisiniz.

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

LIKE eşdeğerini gerçekleştirmek için bunlar çıkarılabilir.

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

Dizeniz normal ifade motoru tarafından farklı yorumlanacak karakterler içerebileceğinden buna dikkat edin.

Bu SQL Fiddle size REGEXP_LIKE () kullanımı dışında aynı örnek çıktıyı gösterir.

3. Oturum düzeyinde değiştirin.

NLS_SORT parametre sıralaması ve çeşitli karşılaştırma operatörleri, dahil olmak üzere harmanlama sırasını düzenleyen =ve benzerlerini içerir. Oturumu değiştirerek ikili, büyük / küçük harfe duyarlı olmayan bir sıralama belirleyebilirsiniz. Bu, bu oturumda gerçekleştirilen her sorgunun büyük / küçük harfe duyarlı olmayan parametreler gerçekleştireceği anlamına gelir.

alter session set nls_sort=BINARY_CI

Farklı bir dil belirtmek veya BINARY_AI kullanarak aksanı duyarsız bir arama yapmak istiyorsanız, dilsel sıralama ve dize araması hakkında birçok ek bilgi vardır.

Ayrıca NLS_COMP parametresini değiştirmeniz gerekecektir ; alıntılamak:

NLS_SORT parametresine uyan tam işleçler ve sorgu cümleleri NLS_COMP parametresinin değerine bağlıdır. Bir işleç veya yan tümce NLS_COMP tarafından belirlenen NLS_SORT değerine uymuyorsa, kullanılan harmanlama BINARY olur.

Varsayılan NLS_COMP değeri BINARY; ancak LINGUISTIC, Oracle'ın NLS_SORT değerine dikkat etmesi gerektiğini belirtir:

WHERE deyimindeki ve PL / SQL bloklarındaki tüm SQL işlemleri için karşılaştırmalar NLS_SORT parametresinde belirtilen dilbilimsel sıralamayı kullanmalıdır. Performansı artırmak için, dil üzerinde karşılaştırma yapmak istediğiniz sütunda bir dil dizini tanımlayabilirsiniz.

Yani, bir kez daha, oturumu değiştirmeniz gerekiyor

alter session set nls_comp=LINGUISTIC

Belgelerde belirtildiği gibi, performansı artırmak için bir dil dizini oluşturmak isteyebilirsiniz

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

"fonksiyona dayalı bir endeks yarat" Bu ne kadar büyük bir fark yaratabilir
Jacob Goulden

select * from my_table where lower(column_1) LIKE lower('my_string') || '%';Bunun yerine neden farklı olduğunu sorabilir miyim select * from my_table where lower(column_1) LIKE lower('my_string%');? Herhangi bir avantaj sağlıyor mu?
lopezvit

1
Bunun bir nedeni, sorgunuzun parametrelenmiş olması durumunda (çoğu durumda büyük olasılıkla), arama kodunuzun her zaman% @lopezvit üzerinde% değerini birleştirmesi gerekmez.
Ben

1
Eğer sonucu bozacak bazı karakterler varsa regexp_like, bu dizelerden kaçmanın bir yolu var mı? Bir örnek vermek gerekirse, dizede $ varsa çıktı beklediğimiz gibi olmayacaktır. // cc @Ben ve diğerleri lütfen paylaşın.
bozzmob

2
` @bozzmob çıkış karakteridir . Normal ifadenin üzerinde çalıştığı dize a içeriyorsa, çıktıda herhangi bir fark olmamalıdır $, bu yalnızca $normal ifadenizde bir değişmez ifadeye ihtiyacınız varsa sorunlara neden olabilir . Belirli bir sorununuz varsa, bu yorum / yanıt yardımcı olmadıysa başka bir soru soracağım.
Ben

51

belki kullanmayı deneyebilirsin

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

3
giriş parametresi büyük harf olduğunda ve daha düşük veya karışık ise çalışmaz
sergionni

13
O zaman düşündün mü WHERE upper(user_name) LIKE UPPER('%ME%')? :)
Konerak

3
@sergionni arama terimini de büyük harfle yazmalısınız!
Markus Winand

3
@sergionni, öyleyse neden UPPERgiriş parametresinde de kullanmıyorsunuz ?
Çek Cumhuriyeti'nde

5
@ V4Vendetta upperindeksi kaybettiğiniz fonksiyonu kullanarak, indeksi kullanarak nasıl arama yapılacağına dair bir fikriniz var mı?
jcho360

7

Oracle 12c R2'den şunları kullanabilirsiniz COLLATE operator:

COLLATE işleci, bir ifadenin harmanlamasını belirler. Bu işleç, standart harmanlama türetme kurallarını kullanarak veritabanının ifade için türeteceği harmanlamayı geçersiz kılmanıza olanak tanır.

COLLATE işleci, adlandırılmış bir harmanlama veya sözde harmanlama belirtebileceğiniz bir collation_name argümanı alır. Harmanlama adı boşluk içeriyorsa, adı çift tırnak içine almanız gerekir.

Demo:

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 <> keman demosu


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

%Senin kapatıldığı ikinci argüman 'ın NLSSORTedilir değil , doğru joker olması gerekiyordu? Biraz kafa karıştırıyorlar.
Stefan van den Akker

1

böyle bir şey yapabilirsiniz:

where regexp_like(name, 'string$', 'i');
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.