Wie kann man festlegen, dass Sqlite3 beim Vergleichen von Zeichenfolgen nicht zwischen Groß- und Kleinschreibung unterscheidet?


305

Ich möchte Datensätze aus der SQLite3-Datenbank durch String-Matching auswählen. Wenn ich jedoch '=' in der where-Klausel verwende, habe ich festgestellt, dass bei sqlite3 zwischen Groß- und Kleinschreibung unterschieden wird. Kann mir jemand sagen, wie man einen String verwendet, bei dem die Groß- und Kleinschreibung nicht berücksichtigt wird?

Antworten:


493

Sie können COLLATE NOCASEin Ihrer SELECTAbfrage Folgendes verwenden:

SELECT * FROM ... WHERE name = 'someone' COLLATE NOCASE

Außerdem können Sie in SQLite angeben, dass bei einer Spalte beim Erstellen der Tabelle die Groß- und Kleinschreibung nicht berücksichtigt werden soll, indem Sie in der Spaltendefinition angeben collate nocase(die anderen Optionen sind binary(Standard) und rtrim; siehe hier ). Sie können auch angeben, collate nocasewann Sie einen Index erstellen. Zum Beispiel:

Tabelle erstellen Test
(
  Text_Value Text sortiert Nocase
);

in Testwerte einfügen ('A');
in Testwerte einfügen ('b');
in Testwerte einfügen ('C');

Erstellen Sie den Index Test_Text_Value_Index
  on Test (Text_Value collate nocase);

Ausdrücke, bei denen es Test.Text_Valuesich um Ausdrücke handelt, sollten jetzt nicht mehr zwischen Groß- und Kleinschreibung unterscheiden. Zum Beispiel:

sqlite> wähle Text_Value aus Test, wobei Text_Value = 'B';
Text_Value      
----------------
b               

sqlite> Wählen Sie Text_Value aus der Testreihenfolge von Text_Value aus.
Text_Value      
----------------
EIN               
b               
C.    

sqlite> wählen Sie Text_Value aus der Testreihenfolge von Text_Value desc;
Text_Value      
----------------
C.               
b               
EIN               

Der Optimierer kann den Index möglicherweise auch für die Suche und den Abgleich in der Spalte verwenden, bei denen die Groß- und Kleinschreibung nicht berücksichtigt wird. Sie können dies mit dem explainSQL-Befehl überprüfen , z.

sqlite> EXPLAIN Wählen Sie Text_Value aus Test aus, wobei Text_Value = 'b';
Adr-Opcode p1 p2 p3                               
---------------- -------------- ---------- ---------- ---------------------------------
0 Gehe zu 0 16                                           
1 Ganzzahl 0 0                                            
2 OpenRead 1 3 keyinfo (1, NOCASE)                
3 SetNumColumns 1 2                                            
4 String8 0 0 b                                
5 IsNull -1 14                                           
6 MakeRecord 1 0 a                                
7 MemStore 0 0                                            
8 MoveGe 1 14                                           
9 MemLoad 0 0                                            
10 IdxGE 1 14 +                                
11 Spalte 1 0                                            
12 Rückruf 1 0                                            
13 Weiter 1 9                                            
14 Schließen 1 0                                            
15 Halt 0 0                                            
16 Transaktion 0 0                                            
17 VerifyCookie 0 4                                            
18 Gehe zu 0 1                                            
19 Noop 0 0                                            

20
Nachdem ich die Tabelle mit 'COLLATE NOCASE' (neu) erstellt hatte, bemerkte ich, dass sie viel schneller war als die Abfrage WHERE name = 'jemand' COLLATE NOCASE. VIEL schneller (ungefähr sechs bis zehn Mal?)
DefenestrationDay

10
Gemäß der Dokumentation ist das Hinzufügen COLLATE NOCASEzum Index nicht erforderlich, wenn für das Feld selbst bereits diese Sortierung definiert ist: " Die Standard-Sortierfolge ist die für diese Spalte in der Anweisung CREATE TABLE definierte Sortierfolge. "
Heinzi

29
COLLATE NOCASEfunktioniert nur mit ASCII-Text. Sobald Sie "FIANCÉ" oder "voilà" in Ihren Spaltenwerten haben, wird es nicht mehr mit "fiancé" oder "VOILA" übereinstimmen. Nach dem Aktivieren der ICU-Erweiterung LIKEwird die Groß- und Kleinschreibung nicht berücksichtigt . Dies 'FIANCÉ' LIKE 'fiancé'ist wahr, aber 'VOILA' LIKE 'voilà'immer noch falsch. Und ICU + LIKE hat den Nachteil, dass der Index nicht verwendet wird, sodass er bei großen Tischen langsam sein kann.

Wählen Sie div aus, falls div = 'fail', dann 'FAIL', andernfalls 'PASSED' endet, * von den oben genannten Markierungssortierungen hat nicht funktioniert. Mache ich etwas falsch?
Donner

7
Eine Sache, die mich stolperte: select * from tbl where firstname='john' and lastname='doe' COLLATE NOCASEwird bei Groß- und Kleinschreibung nicht berücksichtigt lastname. Um die Groß- und Kleinschreibung nicht zu berücksichtigen firstname, schreiben Sie Folgendes : select * from tbl where firstname='john' COLLATE NOCASE and lastname='doe'. Es ist spezifisch für diese eine Spalte, nicht für die gesamte whereKlausel.
James Toomey


47

Sie können es so machen:

SELECT * FROM ... WHERE name LIKE 'someone'

(Es ist nicht die Lösung, aber in einigen Fällen sehr praktisch)

"Der LIKE- Operator führt einen Mustervergleich durch. Der Operand rechts enthält das Muster, der linke Operand enthält die Zeichenfolge, die mit dem Muster übereinstimmt. Ein Prozentzeichen ("% ") im Muster entspricht einer beliebigen Folge von Null oder mehr Zeichen in der Zeichenfolge. Ein Unterstrich ("_") im Muster entspricht einem einzelnen Zeichen in der Zeichenfolge. Jedes andere Zeichen entspricht sich selbst oder seinem Äquivalent in Klein- / Großbuchstaben (dh Übereinstimmung ohne Berücksichtigung der Groß- / Kleinschreibung ) . (Ein Fehler: SQLite versteht nur Groß- / Kleinschreibung für ASCII-Zeichen. Der LIKE-Operator unterscheidet zwischen Groß- und Kleinschreibung für Unicode-Zeichen, die außerhalb des ASCII-Bereichs liegen. Beispielsweise ist der Ausdruck 'a' LIKE 'A' WAHR, aber 'æ' LIKE 'Æ'ist falsch.)."


@ MM-BB Ja, es sei denn, wir führen das LIKE für eine Spalte aus, die als COLLATE NOCASE deklariert (oder indiziert) ist, und führen einen vollständigen Scan der Zeilen durch.
Nick Dandoulakis

1
Es ist kein Fehler, es ist eine dokumentierte Einschränkung. Auf derselben Seite, die in der Antwort angegeben ist, wird die ICU-Erweiterung erwähnt, die Unicode-Zeichen verwaltet. (Vielleicht war es 2009 nicht der Fall)
Stenci

40

Dies ist nicht spezifisch für SQLite, aber Sie können es einfach tun

SELECT * FROM ... WHERE UPPER(name) = UPPER('someone')

Der andere Teil des Leistungsproblems besteht darin, die übereinstimmenden Zeilen in der Tabelle zu finden. Unterstützt SQLite3 funktionsbasierte Indizes? In einer solchen Situation ist es normalerweise eine gute Idee, die Suchspalte oder den Ausdruck (z. B. "UPPER (Name)") zu indizieren.
Cheduardo

13
Achten Sie darauf, dass SQLite, wie Cheduardo angedeutet hat, beim Ausführen dieser Abfrage keinen Index für 'Name' verwenden kann. Die DB-Engine muss alle Zeilen vollständig scannen, alle 'Name'-Felder in Großbuchstaben konvertieren und den Vergleich ausführen.
Mathew Waters

1
@ Menge, ja, viel.
Die Berga

4

Eine andere Möglichkeit besteht darin, eine eigene benutzerdefinierte Sortierung zu erstellen. Sie können diese Sortierung dann in der Spalte festlegen oder zu Ihren Auswahlklauseln hinzufügen. Es wird für Bestellungen und Vergleiche verwendet.

Dies kann verwendet werden, um 'VOILA' LIKE 'voilà' zu machen.

http://www.sqlite.org/capi3ref.html#sqlite3_create_collation

Die Sortierfunktion muss eine Ganzzahl zurückgeben, die negativ, null oder positiv ist, wenn die erste Zeichenfolge kleiner, gleich oder größer als die zweite ist.


2

Eine andere Option, die in Ihrem Fall möglicherweise sinnvoll ist oder nicht, besteht darin, eine separate Spalte mit vorab unterstrichenen Werten Ihrer vorhandenen Spalte zu haben. Dies kann mit der SQLite-Funktion ausgefüllt werden LOWER(), und Sie können stattdessen einen Abgleich für diese Spalte durchführen.

Natürlich erhöht dies die Redundanz und das Potenzial für Inkonsistenzen. Wenn Ihre Daten jedoch statisch sind, ist dies möglicherweise eine geeignete Option.


2

Sie können COLLATE NOCASE einfach in Ihrer SELECT-Abfrage verwenden:

SELECT * FROM ... WHERE name = 'someone' COLLATE NOCASE

1

Wenn die Spalte vom Typ charist, müssen Sie den Wert, den Sie abfragen, an Leerzeichen anhängen. Weitere Informationen finden Sie hier . Dies zusätzlich zur Verwendung COLLATE NOCASEoder einer der anderen Lösungen (Upper () usw.).



0

Es funktioniert perfekt für mich. SELECT NAME FROM TABLE_NAME WHERE NAME = 'test Name' COLLATE NOCASE

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.