MySQL'de SQL büyük / küçük harfe duyarlı dize karşılaştırmasını nasıl yapabilirim?


285

Karışık karakter ile beş karakter döndüren bir işlevi var. Bu dizede bir sorgu yaparsanız, durum ne olursa olsun değeri döndürür.

MySQL dizesi sorgularını büyük / küçük harfe duyarlı hale nasıl getirebilirim?



8
BINARY'ın büyük / küçük harfe duyarlı karşılaştırmayla aynı olmadığına dikkat edin: 'à' gibi 'a' // seçin true döndürür 'à' BINARY gibi 'a' // yanlış döndürür !!! 'à' gibi 'seçin' a 'COLLATE latin1_general_cs // true değerini döndürür Bu nedenle, büyük / küçük harfe duyarlı karşılaştırma için BINARY kullanma önerisi yanlıştır.
cquezel

3
@cquezel: Yani, [IN 'İKİLİ' a 'gibi' à 'seçeneğini seçmenizin doğru dönmesi gerektiğini mi söylüyorsun ?? Her durumda, büyük / küçük harfe duyarlı karşılaştırmalar ile ne ilgisi var?
Francisco Zarabozo

3
@FranciscoZarabozo Aşağıdaki bazı kişiler büyük / küçük harfe duyarlı karşılaştırma yapmak için BINARY karşılaştırmasını kullanmasını önerdi. Sadece diğer dillerde, BINARY'ın büyük / küçük harfe duyarlı olmadığı için muhtemelen beklendiği gibi çalışmayacağını belirtiyorum.
cquezel

3
@cquezel 'à' harfinin 'a' harfinden farklı bir harf olduğunu düşünürüm. Dolayısıyla, ikisi arasındaki karşılaştırma, durum ne olursa olsun yanlış olmalıdır.
Stephane

Yanıtlar:


159

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

Varsayılan karakter kümesi ve harmanlama latin1 ve latin1_swedish_ci şeklindedir, bu nedenle ikili olmayan dize karşılaştırmaları varsayılan olarak büyük / küçük harfe duyarlı değildir. Diğer bir deyişle, 'a%' sütun_adı ile arama yaparsanız, A veya a ile başlayan tüm sütun değerlerini alırsınız. Bu arama büyük / küçük harfe duyarlı hale getirmek için, işlenenlerden birinin büyük / küçük harfe duyarlı veya ikili harmanlama olduğundan emin olun. Örneğin, her ikisi de latin1 karakter kümesine sahip bir sütun ve bir dize karşılaştırıyorsanız, işlenenlerden birinin latin1_general_cs veya latin1_bin harmanlamasına sahip olmasını sağlamak için COLLATE işlecini kullanabilirsiniz:

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

Bir sütunun her zaman büyük / küçük harfe duyarlı şekilde işlenmesini istiyorsanız, büyük / küçük harfe duyarlı veya ikili bir harmanlama ile bildirin.


4
phpmyadmin bunu yapmak için herhangi bir ipucu?
StevenB

4
@StevenB: Sütunun Düzenle düğmesini tıklayın, ardından Harmanlama -> i.imgur.com/7SoEw.png
drudge

32
@BT utf8 sütun büyük / küçük harf duyarlı yapmak için bin colation kullanabilirsiniz gibi:SELECT 'email' COLLATE utf8_bin = 'Email'
piotrekkr

@drudge Büyük / küçük harfe duyarlı harmanlama içeren bir sütunu nasıl bildirirsiniz?
Stephane

1
@StephaneEybert Eğer düz kasa duyarlılığı arıyorsanız ut8 tablosundaki bir alan için varchar yerine varbinary kullanmakta şansım oldu. HTH
Andrew T

725

İyi haber şu ki, büyük / küçük harfe duyarlı bir sorgu yapmanız gerekiyorsa, bunu yapmak çok kolaydır:

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

34
Tam da aradığım şey buydu. Yapabilseydim daha yüksek olurdum. Yine de bir soru, bunun performans üzerindeki etkisi nedir? Ben sınırlı bir raporlama şey üzerinde kullanıyorum, bu yüzden benim durumumda önemli değil, ama merak ediyorum.
adjwilli

23
Bu neden cevap değil? Tam da ihtiyacım olan şey bu.
Art Geigel

7
@adjwilli Sütun bir dizinin parçasıysa, o dizine bağlı sorgularda bir performans isabeti alırsınız. Performansı korumak için tabloyu değiştirmeniz gerekir.
dshin

6
Aynı karakteri farklı bir temsile sahip UTF-8 dizeleri için ne yapacak? Örn. Bir nokta işareti eklemek için birleştirme karakteri kullanma? Bunlar UTF-8 dizeleri eşit olarak muamele edilebilir: convert(char(0x65,0xcc,0x88) using utf8)(yani ebirlikte ¨eklendi) ve convert(char(0xc3,0xab) using utf8)(yani ë), ancak ekleyerek BINARYonları eşitsiz hale getirecektir.
mvds

3
Bir performans örneği olarak: benim sorgu 3,5ms (ihmal edilebilir) 1.570ms (bu yaklaşık bir buçuk) geçer, 1.8M satır aproks ile bir tablo sorgulama.
Lluís Suñol

64

Tarafından gönderildi Craig White, büyük performans cezası var

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

çünkü dizin kullanmıyor. Bu nedenle, tablo harmanlamasını burada belirtildiği gibi değiştirmeniz gerekir https://dev.mysql.com/doc/refman/5.7/en/case-sensitivity.html .

VEYA

En kolay düzeltme, bir BINARY değeri kullanmalısınız.

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

Örneğin.

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

Sette 1 satır (0.00 sn)


Bu olmayı görünmüyor harf duyarlı üzerinde 10.3.22-mariadb (- 5.6.43 libmysql kullanarak)
user10398534

40

= İşlecini kullanmak yerine, GİBİ veya GİBİ İKİLİ gibi kullanmak isteyebilirsiniz

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

Durumunda 'A' değil 'a' alacaktır


Bu olmayı görünmüyor harf duyarlı üzerinde 10.3.22-mariadb (- 5.6.43 libmysql kullanarak)
user10398534

17

İKİLİ'yi kullanmadan önce bir dizinden yararlanmak için büyük tablolarınız varsa böyle bir şey yapabilirsiniz.

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

Alt sorgu, küçük / büyük harfe duyarlı olmayan bir alt kümeyle sonuçlanır.


Yukarıdakilerin yalnızca verilerinize bağlı olarak yardımcı olacağını söylemek önemlidir.
BrynJ

15

Sorgulanan sütunun harmanlamasını değiştirmeden büyük / küçük harfe duyarlı bir dize karşılaştırması yapmanın en doğru yolu, sütunun karşılaştırıldığı değer için açıkça bir karakter kümesi ve harmanlama belirtmektir.

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

Neden kullanmıyorsunuz binary?

Kullanılması binaryo kodlanmış dizeleri gerçek byte karşılaştırır çünkü operatörü önerilmez. Farklı karakter kümeleri kullanılarak kodlanan iki dizenin gerçek baytlarını karşılaştırırsanız, aynı kabul edilmesi gereken iki dizge eşit olmayabilir. Örneğin, latin1karakter kümesini kullanan bir sütununuz varsa ve sunucu / oturum karakter kümeniz ise utf8mb4, sütunu 'café' gibi bir aksan içeren bir dize ile karşılaştırdığınızda, aynı dizeyi içeren satırlarla eşleşmez! İçinde olmasıdır latin1é byte olarak kodlanan 0xE9ama utf8iki bayt: 0xC3A9.

Neden kullanılmalıdır convertsıra sıra collate?

Harmanlamalar karakter kümesiyle eşleşmelidir. Bu nedenle sunucunuz veya oturumunuz latin1karakter kümesini kullanacak şekilde ayarlanmışsa, kullanmanız gerekir collate latin1_binancak karakter kümeniz ise utf8mb4kullanmanız gerekir collate utf8mb4_bin. Bu nedenle en sağlam çözüm, değeri her zaman en esnek karakter kümesine dönüştürmek ve bu karakter kümesi için ikili harmanlamayı kullanmaktır.

Neden convertve collatedeğerini sütuna değil, değere uygulayın ?

Bir karşılaştırma yapmadan önce bir sütuna herhangi bir dönüştürme işlevi uyguladığınızda, sorgu motorunun sütun için bir dizin varsa, sorgunuzu önemli ölçüde yavaşlatabilecek bir dizin kullanmasını engeller. Bu nedenle değeri mümkün olan yerlerde dönüştürmek her zaman daha iyidir. İki dize değeri arasında bir karşılaştırma yapıldığında ve bunlardan birinde açıkça belirtilen bir harmanlama varsa, sorgu motoru hangi değere uygulandığına bakılmaksızın açık harmanlamayı kullanır.

Vurgu Hassasiyeti

MySql'in yalnızca bir _ciharmanlama (genellikle varsayılan olan) kullanan sütunlar için büyük / küçük harfe duyarlı olmadığını , aynı zamanda aksan duyarlı olmadığını da belirtmek önemlidir . Bu demektir 'é' = 'e'. İkili bir harmanlama (veya binaryoperatör) kullanmak, dize karşılaştırmalarını aksan duyarlı olduğu kadar büyük / küçük harf duyarlı hale getirir.

Nedir utf8mb4?

utf8MySql karakter kümesi için bir takma ad utf8mb3edildiği son sürümlerinde kaldırılmış o (🐈 gibi dizeleri kodlamak için önemlidir) 4 baytlık karakterleri desteklemediği için. Kullanmak isterseniz UTF8 karakter kodlamasını MySQL ile ardından kullanmakta olmalıdır utf8mb4charset.


8

Aşağıda 5.5'e eşit veya daha yüksek MySQL sürümleri bulunmaktadır.

/Etc/mysql/my.cnf dosyasına ekle

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

Denediğim diğer tüm harmanlamalar büyük / küçük harfe duyarlı görünmüyordu, sadece "utf8_bin" çalıştı.

Bundan sonra mysql'yi yeniden başlatmayı unutmayın:

   sudo service mysql restart

Http://dev.mysql.com/doc/refman/5.0/en/case-sensitivity.html'ye göre bir de "latin1_bin" var.

"Utf8_general_cs" mysql başlangıcı tarafından kabul edilmedi. ("_Cs" i "büyük / küçük harfe duyarlı" olarak okudum - ???).


7

BINARY işlevini, bu gibi hassas durumlar için kullanabilirsiniz

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

ne yazık ki bu sql endeksi kullanamaz, bu endekse bağlı sorgularda bir performans isabeti çekeceksiniz

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

Neyse ki, bu sorunu çözmek için birkaç hilem var

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

Bu öyle görünmüyor harf duyarlı üzerinde 10.3.22-mariadb (- 5.6.43 libmysql kullanarak)
user10398534

2

Mükemmel!

Sizinle, şifreleri karşılaştıran bir fonksiyondan kod paylaşıyorum:

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;Başlangıçta eklemeniz gerekiyor
adinas

2

DB düzeyinde bir şey değiştirmeye gerek yok, sadece çalışacak SQL Sorgu değişiklikleri yapmanız gerekir.

Misal -

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

İkili anahtar kelime büyük / küçük harfe duyarlı hale getirir.


1

mysql varsayılan olarak büyük / küçük harfe duyarlı değildir, dil harmanlamasını şu şekilde değiştirmeyi deneyin: latin1_general_cs

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.