web-dev-qa-db-fra.com

Recherche insensible à la casse dans Oracle

Le comportement par défaut de LIKE et des autres opérateurs de comparaison, = etc, est sensible à la casse.

Est-il possible de les rendre insensibles à la casse?

210
sergionni

Depuis 10gR2, Oracle permet d'affiner le comportement des comparaisons de chaînes en définissant les NLS_COMP et NLS_SORT paramètres de session:

_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
_

Vous pouvez également créer des index non sensibles à la casse:

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

Cette information provient de recherches insensibles à la casse Oracle . L'article mentionne _REGEXP_LIKE_ mais il semble également fonctionner avec le bon vieux _=_.


Dans les versions antérieures à 10gR2, cela ne peut pas vraiment être fait et l'approche habituelle, si vous n'avez pas besoin d'une recherche sans accent , est de simplement UPPER() la colonne et l'expression de recherche.

77
Álvaro González

Il existe trois méthodes principales pour effectuer une recherche sensible à la casse dans Oracle sans utiliser d'index de texte intégral.

En fin de compte, quelle méthode vous choisissez dépend de votre situation personnelle; l'essentiel à retenir est que pour améliorer les performances, vous devez indexer correctement les recherches insensibles à la casse.

1. Cassez votre colonne et votre chaîne de la même manière.

Vous pouvez forcer toutes vos données à être identiques si vous utilisez UPPER() ou LOWER() :

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

ou

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

Si column_1 n'est pas indexé sur upper(column_1) ou lower(column_1), selon le cas, cela peut forcer une analyse complète de la table. Pour éviter cela, vous pouvez créer un index basé sur la fonction .

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

Si vous utilisez LIKE, vous devez concaténer un % autour de la chaîne recherchée.

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

This SQL Fiddle montre ce qui se passe dans toutes ces requêtes. Notez les plans Explain, qui indiquent quand un index est utilisé et quand il ne l’est pas.

2. Utilisez des expressions régulières.

À partir d'Oracle 10g REGEXP_LIKE() est disponible. Vous pouvez spécifier le paramètre _match_parameter_ 'i' afin d'effectuer une recherche ne respectant pas la casse.

Afin de l'utiliser comme opérateur d'égalité, vous devez spécifier le début et la fin de la chaîne, indiquée par le carat et le signe dollar.

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

Afin d'effectuer l'équivalent de LIKE, ceux-ci peuvent être supprimés.

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

Faites attention à ceci car votre chaîne peut contenir des caractères qui seront interprétés différemment par le moteur des expressions régulières.

This SQL Fiddle vous montre le même exemple de sortie, à l'exception de l'utilisation de REGEXP_LIKE ().

3. Modifiez-le au niveau de la session.

Le paramètre NLS_SORT gouverne la séquence de classement pour la commande et les divers opérateurs de comparaison, y compris = et LIKE. Vous pouvez spécifier un tri binaire, insensible à la casse, en modifiant la session. Cela signifie que chaque requête effectuée dans cette session exécutera des paramètres insensibles à la casse.

alter session set nls_sort=BINARY_CI

Il existe de nombreuses informations supplémentaires autour de tri linguistique et recherche de chaîne si vous souhaitez spécifier une autre langue ou effectuer une recherche sans accent, à l'aide de BINARY_AI.

Vous devrez également modifier le paramètre NLS_COMP ; citer:

Les opérateurs et les clauses de requête exacts qui obéissent au paramètre NLS_SORT dépendent de la valeur du paramètre NLS_COMP. Si un opérateur ou une clause n'obéit pas à la valeur NLS_SORT, comme déterminé par NLS_COMP, le classement utilisé est BINARY.

La valeur par défaut de NLS_COMP est BINARY; mais, LINGUISTIC précise qu'Oracle doit prêter attention à la valeur de NLS_SORT:

Les comparaisons de toutes les opérations SQL de la clause WHERE et des blocs PL/SQL doivent utiliser le tri linguistique spécifié dans le paramètre NLS_SORT. Pour améliorer les performances, vous pouvez également définir un index linguistique sur la colonne pour laquelle vous souhaitez des comparaisons linguistiques.

Donc, encore une fois, vous devez modifier la session

alter session set nls_comp=LINGUISTIC

Comme indiqué dans la documentation, vous pouvez créer un index linguistique pour améliorer les performances.

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

peut-être que vous pouvez essayer d'utiliser

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

Depuis Oracle 12c R2, vous pouvez utiliser COLLATE operator :

L'opérateur COLLATE détermine le classement d'une expression. Cet opérateur vous permet de remplacer le classement que la base de données aurait dérivé pour l'expression à l'aide de règles de dérivation de classement standard.

L'opérateur COLLATE accepte un argument, nom_classement, pour lequel vous pouvez spécifier un classement nommé ou un pseudo-classement. Si le nom de classement contient un espace, vous devez le mettre entre guillemets.

Démo:

_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 <> démo fiddle

6
Lukasz Szozda
select user_name
from my_table
where nlssort(user_name, 'NLS_SORT = Latin_CI') = nlssort('%AbC%', 'NLS_SORT = Latin_CI')
2
Clodoaldo Neto

vous pouvez faire quelque chose comme ça:

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