Come posso fare un confronto di stringhe maiuscole e minuscole SQL su MySQL?


285

Ho una funzione che restituisce cinque caratteri con maiuscole e minuscole. Se eseguo una query su questa stringa, verrà restituito il valore indipendentemente dal caso.

Come posso rendere le query stringa MySQL sensibili al maiuscolo / minuscolo?



8
Nota che BINARY non è lo stesso del confronto case sensitive: seleziona 'à' like 'a' // restituisce true seleziona 'à' like BINARY 'a' // restituisce false !!! seleziona 'à' like 'a' COLLATE latin1_general_cs // restituisce true Quindi il suggerimento di usare BINARY per il confronto case sensitive è errato.
cquezel,

3
@cquezel: Quindi stai dicendo che [seleziona 'à' come BINARY 'a'] dovrebbe tornare vero ?? In ogni caso, cosa c'entra questo con i confronti case sensitive?
Francisco Zarabozo,

3
@FranciscoZarabozo alcune persone di seguito hanno suggerito di utilizzare il confronto BINARY per eseguire il confronto case sensitive. Sto solo sottolineando che in altre lingue, questo probabilmente non funzionerà come previsto poiché BINARY non è uguale al maiuscolo / minuscolo.
cquezel,

3
@cquezel Penso che 'à' sia una lettera diversa da 'a'. Quindi il confronto tra i due dovrebbe effettivamente essere falso in ogni caso.
Stephane,

Risposte:


159

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

Il set di caratteri e le regole di confronto predefiniti sono latin1 e latin1_swedish_ci, pertanto i confronti di stringhe non binari non fanno distinzione tra maiuscole e minuscole per impostazione predefinita. Ciò significa che se si cerca con col_name COME 'a%', si ottengono tutti i valori di colonna che iniziano con A o a. Per rendere sensibile questa distinzione tra maiuscole e minuscole, accertarsi che uno degli operandi abbia una distinzione tra maiuscole e minuscole o binaria. Ad esempio, se si stanno confrontando una colonna e una stringa che hanno entrambi il set di caratteri latin1, è possibile utilizzare l'operatore COLLATE per far sì che l'operando abbia le regole di confronto latin1_general_cs o latin1_bin:

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

Se si desidera che una colonna sia sempre trattata in modo sensibile al maiuscolo / minuscolo, dichiararla con una distinzione tra maiuscole e minuscole o binaria.


4
qualche suggerimento su come farlo in phpmyadmin?
StevenB,

4
@StevenB: Fare clic sul pulsante Modifica della colonna, quindi impostare le regole di confronto -> i.imgur.com/7SoEw.png
drudge

32
@BT Per rendere la distinzione tra maiuscole e minuscole della colonna utf8 è possibile utilizzare la combinazione bin come:SELECT 'email' COLLATE utf8_bin = 'Email'
piotrekkr

@drudge Come dichiareresti una colonna con un confronto tra maiuscole e minuscole?
Stephane,

1
@StephaneEybert se stai cercando la distinzione tra maiuscole e minuscole, ho avuto fortuna nell'usare varbinary invece di varchar per un campo nella tabella ut8. HTH
Andrew T,

725

La buona notizia è che se è necessario effettuare una query con distinzione tra maiuscole e minuscole, è molto semplice:

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

34
Questo e 'esattamente quello che stavo cercando. Vorrei salire di più se potessi. Una domanda però, che effetto ha questo sulle prestazioni? Lo sto usando su una cosa di segnalazione limitata, quindi non è importante nel mio caso, ma sono curioso.
adjwilli,

23
Perché questa non è la risposta? Questo è esattamente anche quello di cui avevo bisogno.
Art Geigel,

7
@adjwilli Se la colonna faceva parte di un indice, si subirà un calo delle prestazioni in caso di query basate su tale indice. Per mantenere le prestazioni, è necessario modificare effettivamente la tabella.
Dshin,

6
Cosa farà questo per le stringhe UTF-8 contenenti lo stesso carattere con una rappresentazione diversa, ad esempio usando un carattere combinato per aggiungere un umlaut? Queste stringhe UTF-8 potrebbero essere considerate uguali: convert(char(0x65,0xcc,0x88) using utf8)(cioè econ l' ¨aggiunta) e convert(char(0xc3,0xab) using utf8)(cioè ë), ma l'aggiunta BINARYle renderà disuguali.
mvds

3
Come esempio di prestazioni: la mia query passa da 3,5ms (trascurabile) a 1.570ms (questo è circa un secondo e mezzo), interrogando una tabella con circa 1,8 milioni di righe.
Lluís Suñol,

64

La risposta inviata da Craig White, ha un grosso rigore per le prestazioni

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

perché non usa gli indici. Quindi, o è necessario modificare le regole di confronto delle tabelle come menzionato qui https://dev.mysql.com/doc/refman/5.7/en/case-sensitivity.html .

O

Correzione più semplice, dovresti usare un BINARY di valore.

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

Per esempio.

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 riga nel set (0,00 sec)


Questo non sembra fare distinzione tra maiuscole e minuscole su 10.3.22-MariaDB (usando libmysql - 5.6.43)
user10398534

40

Invece di usare l'operatore =, potresti voler usare LIKE o LIKE BINARY

// 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'

Ci vorrà 'a' e non 'A' nelle sue condizioni


Questo non sembra fare distinzione tra maiuscole e minuscole su 10.3.22-MariaDB (usando libmysql - 5.6.43)
user10398534

17

Per utilizzare un indice prima di usare il BINARY, puoi fare qualcosa del genere se hai tabelle di grandi dimensioni.

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

La sottoquery comporterebbe un sottoinsieme veramente piccolo senza distinzione tra maiuscole e minuscole, di cui si seleziona l'unica corrispondenza sensibile al maiuscolo / minuscolo.


Vale la pena di commentare per dire che quanto sopra aiuterà solo a seconda dei tuoi dati: la tua ricerca insensibile alle maiuscole potrebbe potenzialmente restituire un sottoinsieme piuttosto ampio di dati.
BrynJ,

15

Il modo più corretto per eseguire un confronto tra maiuscole e minuscole senza modificare le regole di confronto della colonna da interrogare è specificare esplicitamente un set di caratteri e regole di confronto per il valore a cui viene confrontata la colonna.

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

Perché non usare binary?

L'uso binarydell'operatore non è consigliabile perché confronta i byte effettivi delle stringhe codificate. Se si confrontano i byte effettivi di due stringhe codificate utilizzando i diversi set di caratteri, due stringhe che devono essere considerate uguali potrebbero non essere uguali. Ad esempio, se si dispone di una colonna che utilizza il latin1set di caratteri e il set di caratteri del server / sessione è utf8mb4, quindi quando si confronta la colonna con una stringa contenente un accento come "café", non corrisponderà alle righe contenenti quella stessa stringa! Questo perché in latin1E è codificato come il byte 0xE9ma utf8è due byte: 0xC3A9.

Perché usare convertcosì come collate?

Le regole di confronto devono corrispondere al set di caratteri. Pertanto, se il server o la sessione è impostato per utilizzare il latin1set di caratteri, è necessario utilizzare, collate latin1_binma se è impostato il set di caratteri, è utf8mb4necessario utilizzare collate utf8mb4_bin. Pertanto, la soluzione più solida è convertire sempre il valore nel set di caratteri più flessibile e utilizzare le regole di confronto binarie per quel set di caratteri.

Perché applicare la converte collateal valore e non la colonna?

Quando si applica una funzione di trasformazione a una colonna prima di effettuare un confronto, si impedisce al motore di query di utilizzare un indice se ne esiste uno per la colonna, che potrebbe rallentare notevolmente la query. Pertanto è sempre meglio trasformare il valore invece dove possibile. Quando viene eseguito un confronto tra due valori di stringa e uno di essi ha un confronto esplicitamente specificato, il motore di query utilizzerà il confronto esplicito, indipendentemente dal valore a cui viene applicato.

Sensibilità all'accento

È importante notare che MySql non è solo sensibile al maiuscolo / minuscolo per le colonne che utilizzano una _cifascicolazione (che è in genere l'impostazione predefinita), ma è anche insensibile all'accento . Questo significa che 'é' = 'e'. L'uso di un confronto binario (o binarydell'operatore) renderà il confronto delle stringhe sensibile all'accento e al maiuscolo / minuscolo.

Che cosa è utf8mb4?

Il utf8set di caratteri in MySql è un alias per il utf8mb3quale è stato deprecato nelle versioni recenti perché non supporta caratteri a 4 byte (che è importante per la codifica di stringhe come 🐈). Se desideri utilizzare la codifica dei caratteri UTF8 con MySql, dovresti utilizzare il utf8mb4set di caratteri.


8

Di seguito è riportato per le versioni di MySQL uguali o superiori a 5.5.

Aggiungi a /etc/mysql/my.cnf

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

Tutte le altre raccolte che ho provato sembravano non distinguere tra maiuscole e minuscole, solo "utf8_bin" ha funzionato.

Non dimenticare di riavviare mysql dopo questo:

   sudo service mysql restart

Secondo http://dev.mysql.com/doc/refman/5.0/en/case-sensitivity.html esiste anche un "latin1_bin".

"Utf8_general_cs" non è stato accettato dall'avvio di mysql. (Ho letto "_cs" come "case sensitive" - ​​???).


7

Puoi usare BINARY per maiuscole e minuscole in questo modo

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

sfortunatamente questo sql non può usare l'indice, subirai un calo delle prestazioni sulle query basate su tale indice

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

Fortunatamente, ho alcuni trucchi per risolvere questo problema

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

Questo non sembra fare distinzione tra maiuscole e minuscole su 10.3.22-MariaDB (usando libmysql - 5.6.43)
user10398534

2

Eccellente!

Condivido con te il codice di una funzione che confronta le password:

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;

declare pSuccess BINARY;
Devo

2

Non c'è bisogno di cambiare nulla a livello di DB, devi solo cambiare in SQL Query funzionerà.

Esempio -

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

La parola chiave binaria farà distinzione tra maiuscole e minuscole.


1

mysql non fa distinzione tra maiuscole e minuscole per impostazione predefinita, prova a cambiare la lingua di confronto latin1_general_cs

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.