Ricerca senza distinzione tra maiuscole e minuscole in Oracle


228

Il comportamento predefinito di LIKEe degli altri operatori di confronto, =ecc. È sensibile al maiuscolo / minuscolo.

È possibile renderli insensibili alle maiuscole / minuscole?


Ricordo amichevole che alcune delle ricerche di esempio daranno luogo a una scansione della tabella completa anche se esiste un indice su nome_utente.
JonSG

8
Hai preso in considerazione l'uso REGEXP_LIKE(username,'me','i')invece di LIKE?
Kubanczyk,

5
no, LIKE funziona bene per me
sergionni,

Risposte:


82

Da 10gR2, Oracle consente di ottimizzare il comportamento dei confronti di stringhe impostando i parametri NLS_COMPe NLS_SORTsession:

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

Puoi anche creare indici senza distinzione tra maiuscole e minuscole:

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

Queste informazioni sono state tratte da ricerche senza distinzione tra maiuscole e minuscole Oracle . L'articolo menziona REGEXP_LIKEma sembra funzionare anche con il buon vecchio =.


Nelle versioni precedenti a 10gR2 non si può davvero fare e l'approccio abituale, se non è necessaria una ricerca senza accento accento , è solo UPPER()la colonna e l'espressione di ricerca.


1
Funziona bene, ma rende gli AGGIORNAMENTI usando gli operatori LIKE / = molto lenti ...... :(
Saqib Ali

1
@SaqibAli Le LIKEespressioni arbitrarie (ad es. WHERE foo LIKE '%abc%') Sono già abbastanza lente se non possono essere indicizzate, non penso che sia specificamente correlato alla sensibilità del caso.
Álvaro González,

1
Puoi anche impostarli al di fuori di SQLPLUS, come nell'ambiente shell. Ad esempio in uno script Perl usando DBD::Oracle, è possibile scrivere $ENV{NLS_SORT} = 'BINARY_CI'; $ENV{NLS_COMP} = 'LINGUISTIC';prima di chiamare `DBI-> connect`.
marzo

hey ALTER SESSIONmodifica l' unica istanza locale della correzione e significa che è la sessione corrente, cioè se chiudo e riapro avrebbe ripristinato. C'è un modo in cui posso vedere quali sono i valori attuali in modo che se persistesse ovunque posso tornare alle impostazioni originali ...
Seabizkit

305

Esistono 3 modi principali per eseguire una ricerca senza distinzione tra maiuscole e minuscole in Oracle senza utilizzare gli indici full-text.

In definitiva, quale metodo scegli dipende dalle tue circostanze individuali; la cosa principale da ricordare è che per migliorare le prestazioni è necessario indicizzare correttamente la ricerca senza distinzione tra maiuscole e minuscole.

1. Casella identica alla colonna e alla stringa.

Puoi forzare tutti i tuoi dati nello stesso caso usando UPPER()o LOWER():

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

o

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

Se column_1non è indicizzato upper(column_1)o lower(column_1), a seconda dei casi, ciò può forzare una scansione completa della tabella. Per evitare ciò, è possibile creare un indice basato sulle funzioni .

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

Se stai usando LIKE, devi concatenare un %intorno alla stringa che stai cercando.

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

Questo violino SQL dimostra cosa succede in tutte queste query. Nota i piani esplicativi, che indicano quando viene utilizzato un indice e quando non lo è.

2. Usa espressioni regolari.

Da Oracle 10g in poi REGEXP_LIKE()è disponibile. È possibile specificare _match_parameter_ 'i', al fine di eseguire ricerche senza distinzione tra maiuscole e minuscole.

Per usarlo come operatore di uguaglianza devi specificare l'inizio e la fine della stringa, che è indicata dal carato e dal simbolo del dollaro.

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

Per eseguire l'equivalente di LIKE, questi possono essere rimossi.

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

Fai attenzione poiché la stringa può contenere caratteri che verranno interpretati in modo diverso dal motore delle espressioni regolari.

Questo violino SQL mostra lo stesso output di esempio tranne che per l'utilizzo di REGEXP_LIKE ().

3. Modificarlo a livello di sessione.

Il parametro NLS_SORT regola la sequenza di confronto per l'ordinamento e i vari operatori di confronto, inclusi =e LIKE. È possibile specificare un ordinamento binario, senza distinzione tra maiuscole e minuscole, modificando la sessione. Ciò significa che ogni query eseguita in quella sessione eseguirà parametri senza distinzione tra maiuscole e minuscole.

alter session set nls_sort=BINARY_CI

Ci sono molte informazioni aggiuntive sull'ordinamento linguistico e la ricerca di stringhe se si desidera specificare una lingua diversa o eseguire una ricerca senza accento mediante BINARY_AI.

Sarà inoltre necessario modificare il parametro NLS_COMP ; per citare:

Gli operatori esatti e le clausole di query che obbediscono al parametro NLS_SORT dipendono dal valore del parametro NLS_COMP. Se un operatore o una clausola non obbedisce al valore NLS_SORT, come determinato da NLS_COMP, le regole di confronto utilizzate sono BINARY.

Il valore predefinito di NLS_COMP è BINARY; ma LINGUISTIC specifica che Oracle dovrebbe prestare attenzione al valore di NLS_SORT:

I confronti per tutte le operazioni SQL nella clausola WHERE e nei blocchi PL / SQL devono utilizzare l'ordinamento linguistico specificato nel parametro NLS_SORT. Per migliorare le prestazioni, puoi anche definire un indice linguistico sulla colonna per il quale desideri confronti linguistici.

Quindi, ancora una volta, è necessario modificare la sessione

alter session set nls_comp=LINGUISTIC

Come indicato nella documentazione, potresti voler creare un indice linguistico per migliorare le prestazioni

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

"crea un indice basato sulle funzioni" Incredibile che differenza possa fare
Jacob Goulden il

Posso chiederti perché è diverso da fare select * from my_table where lower(column_1) LIKE lower('my_string') || '%';invece di select * from my_table where lower(column_1) LIKE lower('my_string%');? Dà qualche vantaggio?
Lopezvit,

1
Un motivo potrebbe essere se la tua query è paramerterizzata (probabilmente nella maggior parte delle situazioni), quindi il tuo codice chiamante non deve sempre concatenare una% alla fine @lopezvit.
Ben

1
Se ci sono alcuni personaggi che rovineranno il risultato regexp_like, c'è un modo per sfuggire a tali stringhe? Dando un esempio, se la stringa ha $, l'output non sarà come quello che ci aspettiamo. // cc @Ben e altri per favore condividi.
Bozzmob,

2
` è il carattere di escape @bozzmob. Non dovrebbe esserci alcuna differenza nell'output se la stringa su cui sta funzionando l'espressione regolare contiene un $, ciò può causare problemi solo se è necessario un valore $letterale nell'espressione regolare. Se hai un problema specifico, farei un'altra domanda se questo commento / risposta non ha aiutato.
Ben

51

forse puoi provare a usare

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

3
funziona quando il parametro di input è tutto maiuscolo, e se inferiore o misto non lo fa
sergionni

13
Ci hai pensato WHERE upper(user_name) LIKE UPPER('%ME%')allora? :)
Konerak,

3
@sergionni devi anche mettere in maiuscolo il termine di ricerca!
Markus Winand,

3
@sergionni, allora perché non usi anche UPPERil parametro di input?
Cecologia

5
@ V4Vendetta utilizzando la upperfunzione perdi l'indice, hai idea di come effettuare la ricerca utilizzando l'indice?
jcho360,

7

Da Oracle 12c R2 è possibile utilizzare COLLATE operator:

L'operatore COLLATE determina le regole di confronto per un'espressione. Questo operatore consente di sovrascrivere le regole di confronto che il database avrebbe derivato per l'espressione utilizzando le regole di derivazione delle regole di confronto standard.

L'operatore COLLATE accetta un argomento, nome_collation, per il quale è possibile specificare una raccolta o una pseudo-raccolta denominata. Se il nome della collation contiene uno spazio, è necessario racchiuderlo tra virgolette doppie.

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 <> demo violino


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

I %nel primo argomento del secondo nonNLSSORT sono fatti per essere jolly, giusto? Sono un po 'confusi.
Stefan van den Akker,

1

puoi fare qualcosa del genere:

where regexp_like(name, 'string$', 'i');
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.