Suchen ohne Berücksichtigung der Groß- und Kleinschreibung in Oracle

227

Das Standardverhalten von LIKEund den anderen Vergleichsoperatoren =usw. unterscheidet zwischen Groß- und Kleinschreibung.

Ist es möglich, sie unabhängig von Groß- und Kleinschreibung zu machen?

sergionni
quelle
Freundliche Erinnerung daran, dass einige der Beispielsuchen zu einem vollständigen Tabellenscan führen, selbst wenn ein Index für Benutzername vorhanden ist.
JonSG
8
Haben Sie darüber nachgedacht, REGEXP_LIKE(username,'me','i')anstelle von LIKE zu verwenden?
Kubanczyk
5
Nein, LIKE funktioniert in
Ordnung

Antworten:

82

Seit 10gR2 ermöglicht Oracle die Feinabstimmung des Verhaltens von Zeichenfolgenvergleichen durch Festlegen der Parameter NLS_COMPund und der NLS_SORTSitzung:

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

Sie können auch Indizes erstellen, bei denen die Groß- und Kleinschreibung nicht berücksichtigt wird:

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

Diese Informationen stammen aus Oracle-Suchanfragen ohne Berücksichtigung der Groß- und Kleinschreibung . Der Artikel erwähnt, REGEXP_LIKEaber es scheint auch mit guten alten zu funktionieren =.


In Versionen älter als 10gR2 kann es nicht wirklich und die übliche Vorgehensweise durchgeführt werden, wenn Sie nicht brauchen Akzent unempfindlichen ist die Suche, um nur UPPER()sowohl die Säule und der Suchausdruck.

Álvaro González
quelle
1
Dies funktioniert gut, aber es macht die UPDATES mit den Operatoren LIKE / = sehr langsam ...... :(
Saqib Ali
1
@SaqibAli Beliebige LIKEAusdrücke (z. B. WHERE foo LIKE '%abc%') sind bereits langsam genug, wenn sie nicht indiziert werden können. Ich glaube nicht, dass sie speziell mit der Groß- und Kleinschreibung zusammenhängen.
Álvaro González
1
Sie können diese auch außerhalb von SQLPLUS festlegen, wie in der Shell-Umgebung. Zum Beispiel können Sie in einem Perl-Skript mit DBD::Oracleschreiben, $ENV{NLS_SORT} = 'BINARY_CI'; $ENV{NLS_COMP} = 'LINGUISTIC';bevor Sie `DBI-> connect` aufrufen.
Mivk
hey ändert ALTER SESSIONnur die lokale Instanz der Korrektur und bedeutet dies wie Ihre aktuelle Sitzung, dh wenn ich sie schließe und wieder öffne, würde sie zurückgesetzt. Gibt es eine Möglichkeit, wie ich sehen kann, was die aktuellen Werte sind, so dass ich, wenn es überall bestehen
bleibt,
305

Es gibt drei Möglichkeiten, in Oracle eine Suche ohne Berücksichtigung der Groß- und Kleinschreibung ohne Verwendung von Volltextindizes durchzuführen.

Welche Methode Sie wählen, hängt letztendlich von Ihren individuellen Umständen ab. Beachten Sie vor allem, dass Sie zur Verbesserung der Leistung eine korrekte Indizierung für die Suche ohne Berücksichtigung der Groß- und Kleinschreibung vornehmen müssen.

1. Groß- und Kleinschreibung Ihrer Spalte und Ihrer Zeichenfolge.

Sie können erzwingen, dass alle Ihre Daten der gleiche Fall sind, indem Sie UPPER()oder verwenden LOWER():

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

oder

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

Wenn dies column_1nicht indiziert ist upper(column_1)oder lower(column_1)gegebenenfalls, kann dies einen vollständigen Tabellenscan erzwingen. Um dies zu vermeiden, können Sie einen funktionsbasierten Index erstellen .

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

Wenn Sie LIKE verwenden, müssen Sie eine %Zeichenfolge um die gesuchte Zeichenfolge verketten .

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

Diese SQL-Geige zeigt, was in all diesen Abfragen passiert. Beachten Sie die Erklärungspläne, die angeben, wann ein Index verwendet wird und wann nicht.

2. Verwenden Sie reguläre Ausdrücke.

Ab Oracle 10g REGEXP_LIKE()ist verfügbar. Sie können den _match_parameter_ angeben 'i', um eine Suche ohne Berücksichtigung der Groß- und Kleinschreibung durchzuführen.

Um dies als Gleichheitsoperator zu verwenden, müssen Sie den Anfang und das Ende der Zeichenfolge angeben, die durch das Karat und das Dollarzeichen gekennzeichnet sind.

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

Um das Äquivalent von LIKE auszuführen, können diese entfernt werden.

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

Seien Sie vorsichtig damit, da Ihre Zeichenfolge möglicherweise Zeichen enthält, die von der Engine für reguläre Ausdrücke unterschiedlich interpretiert werden.

Diese SQL-Geige zeigt Ihnen dieselbe Beispielausgabe, außer dass REGEXP_LIKE () verwendet wird.

3. Ändern Sie es auf Sitzungsebene.

Der Parameter NLS_SORT regelt die Sortierreihenfolge für die Bestellung und die verschiedenen Vergleichsoperatoren, einschließlich =und LIKE. Sie können eine binäre Sortierung ohne Berücksichtigung der Groß- und Kleinschreibung angeben, indem Sie die Sitzung ändern. Dies bedeutet, dass jede in dieser Sitzung durchgeführte Abfrage Parameter ohne Berücksichtigung der Groß- und Kleinschreibung ausführt.

alter session set nls_sort=BINARY_CI

Es gibt viele zusätzliche Informationen zur sprachlichen Sortierung und Zeichenfolgensuche, wenn Sie eine andere Sprache angeben oder eine akzentunempfindliche Suche mit BINARY_AI durchführen möchten.

Sie müssen auch den Parameter NLS_COMP ändern . zitieren:

Die genauen Operatoren und Abfrageklauseln, die dem Parameter NLS_SORT entsprechen, hängen vom Wert des Parameters NLS_COMP ab. Wenn ein Operator oder eine Klausel den von NLS_COMP festgelegten NLS_SORT-Wert nicht befolgt, lautet die verwendete Sortierung BINARY.

Der Standardwert von NLS_COMP ist BINARY. LINGUISTIC gibt jedoch an, dass Oracle auf den Wert von NLS_SORT achten soll:

Vergleiche für alle SQL-Operationen in der WHERE-Klausel und in PL / SQL-Blöcken sollten die im Parameter NLS_SORT angegebene sprachliche Sortierung verwenden. Um die Leistung zu verbessern, können Sie auch einen Sprachindex für die Spalte definieren, für die Sie Sprachvergleiche wünschen.

Sie müssen also die Sitzung erneut ändern

alter session set nls_comp=LINGUISTIC

Wie in der Dokumentation erwähnt, möchten Sie möglicherweise einen Sprachindex erstellen , um die Leistung zu verbessern

create index my_linguistc_index on my_table 
   (NLSSORT(column_1, 'NLS_SORT = BINARY_CI'));
Ben
quelle
"Erstellen Sie einen funktionsbasierten Index" Erstaunlich, welchen Unterschied dies machen kann
Jacob Goulden
Darf ich fragen , warum es anders zu tun , select * from my_table where lower(column_1) LIKE lower('my_string') || '%';statt select * from my_table where lower(column_1) LIKE lower('my_string%');? Gibt es einen Vorteil?
Lopezzvit
1
Ein Grund wäre, wenn Ihre Abfrage paramerterisiert ist (wahrscheinlich in den meisten Situationen), dann muss Ihr aufrufender Code nicht immer ein% am Ende von @lopezvit verketten.
Ben
1
Wenn es einige Charaktere gibt, die das Ergebnis durcheinander bringen regexp_like, gibt es eine Möglichkeit, solchen Zeichenfolgen zu entkommen? Wenn der String beispielsweise $ enthält, entspricht die Ausgabe nicht den Erwartungen. // cc @Ben und andere bitte teilen.
Bozzmob
2
` ist das Escapezeichen @bozzmob. Es sollte keinen Unterschied in der Ausgabe geben, wenn die Zeichenfolge, mit der der reguläre Ausdruck arbeitet, a enthält $. Dies kann nur dann zu Problemen führen, wenn Sie ein $Literal in Ihrem regulären Ausdruck benötigen . Wenn Sie ein bestimmtes Problem haben, würde ich eine andere Frage stellen, wenn dieser Kommentar / diese Antwort nicht geholfen hat.
Ben
51

Vielleicht kannst du es versuchen

SELECT user_name
FROM user_master
WHERE upper(user_name) LIKE '%ME%'
V4Vendetta
quelle
3
es funktioniert, wenn der Eingabeparameter ganz in Großbuchstaben geschrieben ist, und wenn es
klein
13
Hast du damals darüber nachgedacht WHERE upper(user_name) LIKE UPPER('%ME%')? :)
Konerak
3
@sergionni Sie müssen auch den Suchbegriff in Großbuchstaben schreiben!
Markus Winand
3
@sergionni, warum verwendest du dann nicht auch UPPERden Eingabeparameter?
Czechnology
5
@ V4Vendetta mit der upperFunktion, dass Sie den Index verlieren, haben Sie eine Idee, wie Sie mit dem Index suchen können?
jcho360
7

Ab Oracle 12c R2 können Sie Folgendes verwenden COLLATE operator:

Der Operator COLLATE bestimmt die Sortierung für einen Ausdruck. Mit diesem Operator können Sie die Kollatierung, die die Datenbank für den Ausdruck abgeleitet hätte, mithilfe von Standardregeln für die Ableitung von Kollatierungen überschreiben.

Der COLLATE-Operator verwendet ein Argument, collation_name, für das Sie eine benannte Kollatierung oder Pseudokollatierung angeben können. Wenn der Sortiername ein Leerzeichen enthält, müssen Sie den Namen in doppelte Anführungszeichen setzen.

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 <> Geigen-Demo

Lukasz Szozda
quelle
2
select user_name
from my_table
where nlssort(user_name, 'NLS_SORT = Latin_CI') = nlssort('%AbC%', 'NLS_SORT = Latin_CI')
Clodoaldo Neto
quelle
Die %im ersten bis zweiten Argument NLSSORTsind keine Platzhalter, oder? Sie verwirren irgendwie.
Stefan van den Akker
1

Sie können so etwas tun:

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