如何在MySQL上进行SQL区分大小写的字符串比较?


285

我有一个函数,返回大小写混合的五个字符。如果我对此字符串进行查询,则无论大小写都将返回该值。

如何使MySQL字符串查询区分大小写?



8
请注意,BINARY与区分大小写的比较不同:select'à'like'a'//返回true选择'à'like BINARY'a'//返回false!选择'à'像'a'那样COLLATE latin1_general_cs //返回true因此使用BINARY进行区分大小写的比较的建议是不正确的。
cquezel

3
@cquezel:所以,你是说[选择BINARY'a'之类的'à']应该返回true?无论如何,这与区分大小写的比较有什么关系?
弗朗西斯科·扎拉波佐

3
@FranciscoZarabozo下面的一些人建议使用BINARY比较来进行区分大小写的比较。我只是指出,在其他语言中,这可能无法按预期方式工作,因为BINARY与大小写不同。
cquezel

3
@cquezel我认为'à'与'a'是不同的字母。因此,无论哪种情况,两者之间的比较确实应该是错误的。
Stephane

Answers:


159

http://dev.mysql.com/doc/refman/5.0/zh-CN/case-sensitiveivity.html

默认字符集和排序规则为latin1和latin1_swedish_ci,因此默认情况下非二进制字符串比较不区分大小写。这意味着,如果使用col_name LIKE'a%'搜索,则将获得所有以A或a开头的列值。要使此搜索区分大小写,请确保其中一个操作数具有区分大小写或二进制排序规则。例如,如果要比较均具有latin1字符集的列和字符串,则可以使用COLLATE运算符使两个操作数具有latin1_general_cs或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

如果希望始终以区分大小写的方式对待列,请使用区分大小写或二进制排序规则进行声明。


4
关于如何在phpmyadmin中执行此操作的任何提示?
StevenB 2011年

4
@StevenB:单击列的编辑按钮,然后将整理- > i.imgur.com/7SoEw.png
德拉吉

32
@BT要使utf8列区分大小写,您可以使用bin排序规则,例如:SELECT 'email' COLLATE utf8_bin = 'Email'
piotrekkr

@drudge您如何用区分大小写的排序规则声明一列?
Stephane

1
@StephaneEybert如果您正在寻找对大小写敏感的东西,那么我很幸运在ut8表中的字段中使用varbinary而不是varchar。HTH
Andrew T

724

好消息是,如果您需要进行区分大小写的查询,则很容易做到:

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

34
这正是我想要的。如果可以的话,我会更高。但有一个问题,这对性能有什么影响?我仅在有限的报告内容上使用它,因此对我而言这并不重要,但我很好奇。
adjwilli 2012年

23
为什么这不是答案?这正是我所需要的。
Art Geigel

7
@adjwilli如果该列是索引的一部分,则依赖该索引的查询将遭受性能下降。为了保持性能,您需要实际更改表。
dshin 2013年

6
对于包含具有不同表示形式的相同字符的UTF-8字符串(例如,使用组合字符添加变音符号),这会做什么?这些UTF-8字符串可视为相等:convert(char(0x65,0xcc,0x88) using utf8)(即e¨加)和convert(char(0xc3,0xab) using utf8)(即ë),但增加BINARY会让他们不等。
mvds 2015年

3
作为一个性能示例:我的查询从3,5毫秒(可忽略不计)传递到1.570毫秒(这大约是一个半秒),查询的表包含约180万行。
LLUISSuñol

64

Craig White发表的答案,对性能有很大的影响

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

因为它不使用索引。因此,您要么需要更改表排序规则,如此处https://dev.mysql.com/doc/refman/5.7/en/case-sensitiveivity.html所述

要么

最简单的解决方法是,您应使用值的BINARY。

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

例如。

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行(0.00秒)


10.3.22-MariaDB上,这似乎不区分大小写(使用libmysql
5.6.43

40

您可能要使用LIKE或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'

它的状态为“ a”而不是“ A”


10.3.22-MariaDB上,这似乎不区分大小写(使用libmysql
5.6.43

17

要在使用BINARY之前使用索引,如果您有大表,可以执行以下操作。

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

子查询将导致一个很小的不区分大小写的子集,然后选择唯一的区分大小写的匹配项。


值得一提的是,以上内容仅会根据您的数据提供帮助-不区分大小写的搜索可能会返回相当大的数据子集。
BrynJ

15

在不更改要查询的列的排序规则的情况下执行区分大小写的字符串比较的最正确方法是为要比较的列的值显式指定一个字符集和排序规则。

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

为什么不使用binary

不建议使用binary运算符,因为它会比较编码字符串的实际字节。如果比较使用不同字符集编码的两个字符串的实际字节,则两个应该被视为相同的字符串可能不相等。例如,如果您有一列使用latin1字符集,而服务器/会话字符集是utf8mb4,那么当您将该列与包含重音符号的字符串(例如“café”)进行比较时,将不会匹配包含该字符串的行!这是因为latin1é编码为字节,0xE9utf8其中有两个字节:0xC3A9

为什么要使用convert以及collate

排序规则必须与字符集匹配。因此,如果服务器或会话设置为使用latin1字符集,则必须使用,collate latin1_bin但是如果字符集是utf8mb4,则必须使用collate utf8mb4_bin。因此,最可靠的解决方案是始终将值转换为最灵活的字符集,并对该字符集使用二进制排序规则。

为什么将convertcollate应用于值而不是列?

如果在进行比较之前将任何转换功能应用于列,则会阻止查询引擎使用索引(如果该列存在索引),这可能会大大降低查询速度。因此,最好总是尽可能地转换值。当在两个字符串值之间执行比较并且其中一个具有显式指定的排序规则时,查询引擎将使用该显式排序规则,而不管它应用于哪个值。

口音敏感度

重要的是要注意,MySql不仅对使用_ci排序规则的列不区分大小写(通常是默认设置),而且对重音不敏感。这意味着'é' = 'e'。使用二进制排序规则(或binary运算符)将使字符串比较区分重音和区分大小写。

什么utf8mb4

utf8MySql中的字符集是一个别名,在最近的版本中utf8mb3弃用该别名,因为它不支持4字节字符(这对于编码诸如🐈之类的字符串很重要)。如果希望对MySql 使用UTF8字符编码,则应使用utf8mb4字符集。


8

以下是等于或高于5.5的MySQL版本。

添加到/etc/mysql/my.cnf

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

我尝试的所有其他归类似乎都不区分大小写,只有“ utf8_bin”有效。

此后不要忘记重启mysql:

   sudo service mysql restart

根据http://dev.mysql.com/doc/refman/5.0/en/case-sensitiveivity.html的介绍,还有一个“ latin1_bin”。

mysql启动不接受“ utf8_general_cs”。(我将“ _cs”读为“区分大小写”-???)。


7

您可以使用BINARY这样区分大小写

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

不幸的是,此sql无法使用索引,依赖于该索引的查询会导致性能下降

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

幸运的是,我有一些技巧可以解决这个问题

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

10.3.22-MariaDB上,这似乎不区分大小写(使用libmysql
5.6.43

2

优秀的!

我与您分享了比较密码功能的代码:

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;在开始时添加
adinas

2

无需在数据库级别上进行任何更改,只需要在SQL Query中进行更改即可。

范例-

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

二进制关键字将区分大小写。


1

mysql默认情况下不区分大小写,请尝试将语言排序规则更改为 latin1_general_cs

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.