Wie kann ich in MySQL einen Vergleich von Zeichenfolgen mit Groß- und Kleinschreibung durchführen?

285

Ich habe eine Funktion, die fünf Zeichen mit gemischter Groß- und Kleinschreibung zurückgibt. Wenn ich eine Abfrage für diese Zeichenfolge durchführe, wird der Wert unabhängig von der Groß- und Kleinschreibung zurückgegeben.

Wie kann ich bei MySQL-String-Abfragen zwischen Groß- und Kleinschreibung unterscheiden?

StevenB
quelle
8
Beachten Sie, dass BINARY nicht mit einem Vergleich zwischen Groß- und Kleinschreibung identisch ist: Wählen Sie 'à' wie 'a' // gibt true zurück. Wählen Sie 'à' wie BINARY 'a' // gibt false zurück !!! Wählen Sie 'à' wie 'a'. COLLATE latin1_general_cs // gibt true zurück. Der Vorschlag, BINARY für Vergleiche zwischen Groß- und Kleinschreibung zu verwenden, ist daher falsch.
Cquezel
3
@cquezel: Du sagst also, dass [wähle 'à' wie BINARY 'a'] true zurückgeben soll? Was hat dies auf jeden Fall mit Vergleichen zwischen Groß- und Kleinschreibung zu tun?
Francisco Zarabozo
3
@FranciscoZarabozo Einige Leute unten schlugen vor, den BINARY-Vergleich zu verwenden, um einen Vergleich zwischen Groß- und Kleinschreibung durchzuführen. Ich möchte nur darauf hinweisen, dass dies in anderen Sprachen wahrscheinlich nicht wie erwartet funktioniert, da BINARY nicht mit Groß- und Kleinschreibung identisch ist.
Cquezel
3
@cquezel Ich würde denken, dass 'à' ein anderer Buchstabe als 'a' ist. Der Vergleich zwischen den beiden sollte also in jedem Fall falsch sein.
Stephane

Antworten:

159

http://dev.mysql.com/doc/refman/5.0/en/case-sensitivity.html

Der Standardzeichensatz und die Sortierung sind latin1 und latin1_swedish_ci, sodass bei nicht-binären Zeichenfolgenvergleichen standardmäßig die Groß- und Kleinschreibung nicht berücksichtigt wird. Dies bedeutet, dass Sie bei der Suche mit col_name LIKE 'a%' alle Spaltenwerte erhalten, die mit A oder a beginnen. Stellen Sie sicher, dass bei einem der Operanden zwischen Groß- und Kleinschreibung oder binärer Sortierung unterschieden wird. Wenn Sie beispielsweise eine Spalte und eine Zeichenfolge vergleichen, die beide den Zeichensatz latin1 haben, können Sie den Operator COLLATE verwenden, um zu bewirken, dass jeder Operand die Kollatierung latin1_general_cs oder latin1_bin hat:

col_name COLLATE latin1_general_cs LIKE 'a%'
col_name LIKE 'a%' COLLATE latin1_general_cs
col_name COLLATE latin1_bin LIKE 'a%'
col_name LIKE 'a%' COLLATE latin1_bin

Wenn Sie möchten, dass eine Spalte immer zwischen Groß- und Kleinschreibung unterscheidet, deklarieren Sie sie mit einer Groß- und Kleinschreibung oder einer binären Sortierung.

schuften
quelle
4
Gibt es einen Hinweis, wie dies in phpmyadmin zu tun ist?
StevenB
4
@StevenB: Klicken Sie auf die Schaltfläche Bearbeiten der Spalte, dann die Sortierungs gesetzt -> i.imgur.com/7SoEw.png
drudge
32
@ BT Um utf8 Spalte Groß- und Kleinschreibung zu machen, könnten Sie bin colation verwenden wie:SELECT 'email' COLLATE utf8_bin = 'Email'
piotrekkr
@drudge Wie würden Sie eine Spalte mit einer Sortierung deklarieren, bei der zwischen Groß- und Kleinschreibung unterschieden wird?
Stephane
1
@StephaneEybert Wenn Sie nach einer direkten Groß- und Kleinschreibung suchen, hatte ich das Glück, varbinary anstelle von varchar für ein Feld in der Tabelle ut8 zu verwenden. HTH
Andrew T
724

Die gute Nachricht ist, dass es sehr einfach ist, eine Abfrage durchzuführen, bei der zwischen Groß- und Kleinschreibung unterschieden wird:

SELECT *  FROM `table` WHERE BINARY `column` = 'value'
Craig White
quelle
34
Genau das habe ich gesucht. Ich würde es höher legen, wenn ich könnte. Eine Frage, wie wirkt sich das auf die Leistung aus? Ich verwende es für eine eingeschränkte Berichterstellung, daher ist es in meinem Fall nicht wichtig, aber ich bin neugierig.
Adjwilli
23
Warum ist das nicht die Antwort? Genau das brauchte ich auch.
Art Geigel
7
@adjwilli Wenn die Spalte Teil eines Index war, werden Sie bei Abfragen, die von diesem Index abhängen, einen Leistungseinbruch erleiden. Um die Leistung aufrechtzuerhalten, müssen Sie die Tabelle tatsächlich ändern.
Dshin
6
Was bedeutet dies für UTF-8-Zeichenfolgen, die dasselbe Zeichen mit einer anderen Darstellung enthalten, z. B. die Verwendung eines kombinierten Zeichens zum Hinzufügen eines Umlauts? Diese UTF-8-Zeichenfolgen können als gleich behandelt werden: convert(char(0x65,0xcc,0x88) using utf8)(dh emit ¨hinzugefügt) und convert(char(0xc3,0xab) using utf8)(dh ë), aber durch Hinzufügen BINARYwerden sie ungleich.
MVDS
3
Als Leistungsbeispiel: Meine Abfrage geht von 3,5 ms (vernachlässigbar) bis 1,570 ms (dies sind ungefähr anderthalb Sekunden) und fragt eine Tabelle mit ca. 1,8 Millionen Zeilen ab.
Lluís Suñol
64

Antwort von Craig White gepostet, hat große Leistungseinbußen

SELECT *  FROM `table` WHERE BINARY `column` = 'value'

weil es keine Indizes verwendet. Entweder müssen Sie die Tabellensortierung wie hier erwähnt ändern: https://dev.mysql.com/doc/refman/5.7/en/case-sensitivity.html .

ODER

Am einfachsten zu beheben, sollten Sie ein BINARY von Wert verwenden.

SELECT *  FROM `table` WHERE `column` = BINARY 'value'

Z.B.

mysql> EXPLAIN SELECT * FROM temp1 WHERE BINARY col1 = "ABC" AND col2 = "DEF" ;
+----+-------------+--------+------+---------------+------+---------+------+--------+-------------+
| id | select_type | table  | type | possible_keys | key  | key_len | ref  | rows   | Extra       |
+----+-------------+--------+------+---------------+------+---------+------+--------+-------------+
|  1 | SIMPLE      | temp1  | ALL  | NULL          | NULL | NULL    | NULL | 190543 | Using where |
+----+-------------+--------+------+---------------+------+---------+------+--------+-------------+

VS

mysql> EXPLAIN SELECT * FROM temp1 WHERE col1 = BINARY "ABC" AND col2 = "DEF" ;
+----+-------------+-------+-------+---------------+---------------+---------+------+------+------------------------------------+
| id | select_type | table | type  | possible_keys | key           | key_len | ref  | rows | Extra                              |
+----+-------------+-------+-------+---------------+---------------+---------+------+------+------------------------------------+
|  1 | SIMPLE      | temp1 | range | col1_2e9e898e | col1_2e9e898e | 93      | NULL |    2 | Using index condition; Using where |
+----+-------------+-------+-------+---------------+---------------+---------+------+------+------------------------------------+
enter code here

1 Reihe im Satz (0,00 Sek.)

Nitesh
quelle
Bei 10.3.22-MariaDB (unter Verwendung von libmysql - 5.6.43)
user10398534
40

Anstatt den Operator = zu verwenden, möchten Sie möglicherweise LIKE oder LIKE BINARY verwenden

// this returns 1 (true)
select 'A' like 'a'

// this returns 0 (false)
select 'A' like binary 'a'


select * from user where username like binary 'a'

Es wird 'a' und nicht 'A' in seinem Zustand annehmen

Insoftservice
quelle
Bei 10.3.22-MariaDB (unter Verwendung von libmysql - 5.6.43)
user10398534
17

Um einen Index zu verwenden, bevor Sie BINARY verwenden, können Sie Folgendes tun, wenn Sie große Tabellen haben.

SELECT
   *
FROM
   (SELECT * FROM `table` WHERE `column` = 'value') as firstresult
WHERE
   BINARY `column` = 'value'

Die Unterabfrage würde zu einer wirklich kleinen Teilmenge ohne Berücksichtigung der Groß- und Kleinschreibung führen, von der Sie dann die einzige Übereinstimmung auswählen, bei der die Groß- und Kleinschreibung beachtet wird.

Eric
quelle
Es ist erwähnenswert zu sagen, dass das oben Genannte nur in Abhängigkeit von Ihren Daten hilfreich ist - Ihre Suche ohne Berücksichtigung der Groß- und Kleinschreibung könnte möglicherweise eine ziemlich große Teilmenge von Daten zurückgeben.
BrynJ
15

Die korrekteste Methode zum Durchführen eines Zeichenfolgenvergleichs ohne Berücksichtigung der Groß- und Kleinschreibung, ohne die Sortierung der abgefragten Spalte zu ändern, besteht darin, einen Zeichensatz und eine Sortierung für den Wert, mit dem die Spalte verglichen wird, explizit anzugeben.

select * from `table` where `column` = convert('value' using utf8mb4) collate utf8mb4_bin;

Warum nicht verwenden binary?

Die Verwendung des binaryOperators wird nicht empfohlen, da er die tatsächlichen Bytes der codierten Zeichenfolgen vergleicht. Wenn Sie die tatsächlichen Bytes von zwei Zeichenfolgen vergleichen, die mit den verschiedenen Zeichensätzen codiert wurden, sind zwei Zeichenfolgen, die als gleich angesehen werden sollten, möglicherweise nicht gleich. Wenn Sie beispielsweise eine Spalte haben, die den latin1Zeichensatz verwendet, und Ihr Server- / Sitzungszeichensatz ist utf8mb4, wenn Sie die Spalte mit einer Zeichenfolge vergleichen, die einen Akzent wie "Café" enthält, stimmt sie nicht mit Zeilen überein, die dieselbe Zeichenfolge enthalten! Dies liegt daran , in latin1é als das Byte codiert ist , 0xE9aber in utf8es ist zwei Bytes: 0xC3A9.

Warum convertso gut wie collate?

Kollatierungen müssen mit dem Zeichensatz übereinstimmen. Wenn Ihr Server oder Ihre Sitzung so eingestellt ist, dass der latin1Zeichensatz verwendet collate latin1_binwird utf8mb4, müssen Sie ihn verwenden collate utf8mb4_bin. Wenn Ihr Zeichensatz jedoch so eingestellt ist , müssen Sie ihn verwenden . Daher besteht die robusteste Lösung darin, den Wert immer in den flexibelsten Zeichensatz umzuwandeln und die binäre Sortierung für diesen Zeichensatz zu verwenden.

Warum das convertund collateauf den Wert und nicht auf die Spalte anwenden ?

Wenn Sie vor dem Vergleich eine Transformationsfunktion auf eine Spalte anwenden, wird verhindert, dass die Abfrage-Engine einen Index verwendet, falls für die Spalte einer vorhanden ist, was Ihre Abfrage erheblich verlangsamen kann. Daher ist es immer besser, den Wert nach Möglichkeit zu transformieren. Wenn ein Vergleich zwischen zwei Zeichenfolgenwerten durchgeführt wird und einer von ihnen eine explizit angegebene Kollatierung aufweist, verwendet die Abfrage-Engine die explizite Kollatierung, unabhängig davon, auf welchen Wert sie angewendet wird.

Akzentempfindlichkeit

Es ist wichtig zu beachten, dass MySql nicht nur bei Spalten, bei denen eine _ciSortierung verwendet wird (normalerweise die Standardeinstellung), die Groß- und Kleinschreibung nicht berücksichtigt , sondern auch bei Akzenten nicht berücksichtigt wird . Das bedeutet das 'é' = 'e'. Durch die Verwendung einer binären Kollatierung (oder des binaryOperators) werden Zeichenfolgenvergleiche sowohl akzent- als auch case-abhängig gemacht.

Was ist utf8mb4?

Der utf8Zeichensatz in MySql ist ein Alias, utf8mb3der in neueren Versionen nicht mehr unterstützt wird, da er keine 4-Byte-Zeichen unterstützt (was für die Codierung von Zeichenfolgen wie 🐈 wichtig ist). Wenn Sie die UTF8-Zeichencodierung mit MySQL verwenden möchten, sollten Sie den utf8mb4Zeichensatz verwenden.

Paul Wheeler
quelle
8

Das Folgende gilt für MySQL-Versionen, die gleich oder höher als 5.5 sind.

Zu /etc/mysql/my.cnf hinzufügen

  [mysqld]
  ...
  character-set-server=utf8
  collation-server=utf8_bin
  ...

Alle anderen Kollatierungen, die ich versuchte, schienen die Groß- und Kleinschreibung nicht zu berücksichtigen, nur "utf8_bin" funktionierte.

Vergessen Sie nicht, MySQL danach neu zu starten:

   sudo service mysql restart

Laut http://dev.mysql.com/doc/refman/5.0/en/case-sensitivity.html gibt es auch einen "latin1_bin".

Das "utf8_general_cs" wurde vom MySQL-Start nicht akzeptiert. (Ich habe "_cs" als "case-sensitive" gelesen - ???).

fritzthecat
quelle
7

Sie können BINARY verwenden, um zwischen Groß- und Kleinschreibung zu unterscheiden

select * from tb_app where BINARY android_package='com.Mtime';

Leider kann dieser SQL-Index nicht verwendet werden. Bei Abfragen, die von diesem Index abhängen, tritt ein Leistungseinbruch auf

mysql> explain select * from tb_app where BINARY android_package='com.Mtime';
+----+-------------+--------+------------+------+---------------+------+---------+------+---------+----------+-------------+
| id | select_type | table  | partitions | type | possible_keys | key  | key_len | ref  | rows    | filtered | Extra       |
+----+-------------+--------+------------+------+---------------+------+---------+------+---------+----------+-------------+
|  1 | SIMPLE      | tb_app | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 1590351 |   100.00 | Using where |
+----+-------------+--------+------------+------+---------------+------+---------+------+---------+----------+-------------+

Zum Glück habe ich ein paar Tricks, um dieses Problem zu lösen

mysql> explain select * from tb_app where android_package='com.Mtime' and BINARY android_package='com.Mtime';
+----+-------------+--------+------------+------+---------------------------+---------------------------+---------+-------+------+----------+-----------------------+
| id | select_type | table  | partitions | type | possible_keys             | key                       | key_len | ref   | rows | filtered | Extra                 |
+----+-------------+--------+------------+------+---------------------------+---------------------------+---------+-------+------+----------+-----------------------+
|  1 | SIMPLE      | tb_app | NULL       | ref  | idx_android_pkg           | idx_android_pkg           | 771     | const |    1 |   100.00 | Using index condition |
+----+-------------+--------+------------+------+---------------------------+---------------------------+---------+-------+------+----------+-----------------------+  
xiezefan
quelle
Bei 10.3.22-MariaDB (unter Verwendung von libmysql - 5.6.43)
user10398534
2

Ausgezeichnet!

Ich teile mit Ihnen Code aus einer Funktion, die Passwörter vergleicht:

SET pSignal =
(SELECT DECODE(r.usignal,'YOURSTRINGKEY') FROM rsw_uds r WHERE r.uname =
in_usdname AND r.uvige = 1);

SET pSuccess =(SELECT in_usdsignal LIKE BINARY pSignal);

IF pSuccess = 1 THEN
      /*Your code if match*/
ELSE
      /*Your code if don't match*/

END IF;
Victor Enrique
quelle
declare pSuccess BINARY;
Müssen
2

Auf DB-Ebene müssen keine Änderungen vorgenommen werden. Sie müssen lediglich Änderungen an SQL Query vornehmen, damit dies funktioniert.

Beispiel -

"SELECT * FROM <TABLE> where userId = '" + iv_userId + "' AND password = BINARY '" + iv_password + "'";

Durch das binäre Schlüsselwort wird die Groß- und Kleinschreibung beachtet.

Pappu Mehta
quelle
1

MySQL unterscheidet standardmäßig nicht zwischen Groß- und Kleinschreibung. Ändern Sie die Sprachkollatierung in latin1_general_cs

Ohmusama
quelle