MySQL에서 SQL 대소 문자 구분 문자열 비교를 어떻게 할 수 있습니까?


285

대소 문자를 혼합하여 5자를 반환하는 함수가 있습니다. 이 문자열에서 쿼리를 수행하면 대소 문자에 관계없이 값을 반환합니다.

MySQL 문자열 쿼리를 대소 문자를 구분하려면 어떻게해야합니까?



8
BINARY는 대소 문자 구분 비교와 동일하지 않습니다. select 'à'like 'a'// true를 리턴합니다. BINARY 'a'와 같은 select 'à'// false를 리턴합니다 !!! select 'à'like 'a'COLLATE latin1_general_cs // true를 반환하므로 대소 문자 구분 비교에 BINARY를 사용하라는 제안이 잘못되었습니다.
cquezel

3
@cquezel : 그래서, 당신은 [BINARY 'a'와 같은 'select'à ']가 true를 반환해야한다고 말하고 있습니까? 어쨌든 대소 문자 구분 비교와 어떤 관련이 있습니까?
Francisco Zarabozo

3
@FranciscoZarabozo 아래의 일부 사람들은 대소 문자 구분을 비교하기 위해 BINARY 비교를 사용하도록 제안했습니다. 다른 언어에서는 BINARY가 대소 문자를 구분하지 않으므로 예상대로 작동하지 않을 것입니다.
cquezel

3
@cquezel 나는 'à'가 'a'와 다른 문자라고 생각합니다. 따라서 두 경우의 비교는 실제로 어떤 경우에도 거짓이어야합니다.
Stephane

답변:


159

http://dev.mysql.com/doc/refman/5.0/en/case-sensitivity.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

4
@StevenB : 열의 편집 버튼을 클릭 한 다음 데이터 정렬-> i.imgur.com/7SoEw.png
drudge

32
@BT utf8 컬럼의 대소 문자를 구분하기 위해 다음과 같은 bin 콜 레이션을 사용할 수 있습니다.SELECT 'email' COLLATE utf8_bin = 'Email'
piotrekkr

@drudge 대소 문자 구분 데이터 정렬을 사용하여 열을 어떻게 선언 하시겠습니까?
Stephane

1
@StephaneEybert 대소 문자 구분을 찾고 있다면 ut8 테이블의 필드에 varchar 대신 varbinary를 사용하는 것이 운이 좋았습니다. HTH
Andrew T

724

좋은 소식은 대소 문자를 구분하는 쿼리를 작성해야 할 경우 매우 쉽다는 것입니다.

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

34
이것이 바로 내가 찾던 것입니다. 가능하다면 더 높이 올라갈 것입니다. 그러나 이것이 성능에 어떤 영향을 미칩니 까? 제한된보고에 사용하고 있으므로 제 경우에는 중요하지 않지만 궁금합니다.
adjwilli

23
이것이 왜 대답이 아닌가? 이것이 바로 내가 필요한 것입니다.
Art Geigel

7
@adjwilli 열이 인덱스의 일부인 경우 해당 인덱스에 의존하는 쿼리에서 성능이 저하됩니다. 성능을 유지하려면 실제로 테이블을 변경해야합니다.
dshin

6
조합 문자를 사용하여 움라우트를 추가하는 등 다른 표현으로 동일한 문자를 포함하는 UTF-8 문자열의 경우 어떻게됩니까? 이러한 UTF-8 문자열은 convert(char(0x65,0xcc,0x88) using utf8)(즉 e, ¨추가 된) 및 convert(char(0xc3,0xab) using utf8)(ie ë) 와 동일하게 취급 될 수 있지만 추가 BINARY하면 문자열이 동일 하지 않게됩니다.
mvds

3
성능 예 : 내 쿼리는 3,5ms (무시할 수 있음)에서 1.570ms (약 1/2 초)로 전달되어 1.8M 행의 앞줄이있는 테이블을 쿼리합니다.
Lluís Suñol

64

답변을 Craig White에 의해 게시 함

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

인덱스를 사용하지 않기 때문입니다. 따라서 https://dev.mysql.com/doc/refman/5.7/en/case-sensitivity.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 사용)
user10398534

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 사용)
user10398534

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é에서 바이트로 인코딩 0xE9되지만 utf82 바이트 이기 때문입니다 0xC3A9.

convert뿐만 아니라 사용 collate합니까?

데이터 정렬은 문자 집합과 일치해야합니다. 따라서 서버 나 세션이 latin1문자 세트를 사용하도록 설정된 collate latin1_bin경우 사용해야 하지만 문자 세트가 utf8mb4있는 경우을 사용해야 collate utf8mb4_bin합니다. 따라서 가장 강력한 솔루션은 항상 값을 가장 유연한 문자 집합으로 변환하고 해당 문자 집합에 이진 데이터 정렬을 사용하는 것입니다.

열이 아닌 값에 convertand collate를 적용하는 이유는 무엇 입니까?

비교하기 전에 열에 변환 함수를 적용하면 열에 대한 인덱스 엔진이 있으면 쿼리 엔진에서 인덱스를 사용하지 못하게되어 쿼리 속도가 크게 느려질 수 있습니다. 따라서 가능한 경우 항상 값을 변환하는 것이 좋습니다. 두 문자열 값간에 비교가 수행되고 그 중 하나에 명시 적으로 지정된 데이터 정렬이있는 경우 쿼리 엔진은 적용되는 값에 관계없이 명시 적 데이터 정렬을 사용합니다.

악센트 감도

MySql은 _ci데이터 정렬 (일반적으로 기본값)을 사용하는 열에 대해 대소 문자를 구분하지 않을 뿐만 아니라 악센트를 구분하지 않습니다. 이것은 의미합니다 'é' = 'e'. 이진 데이터 정렬 사용binary 연산자)을 사용하면 문자열 비교가 악센트와 대소 문자를 구분합니다.

무엇입니까 utf8mb4?

utf8MySql 의 문자 집합은 4 바이트 문자를 지원하지 않기 때문에 최근 버전에서 더 이상 사용되지 않는 별칭입니다. utf8mb3이는 🐈과 같은 문자열을 인코딩하는 데 중요합니다. 당신이 사용하고자하는 경우에는 UTF8 문자 인코딩 MySQL과를 당신이 사용되어야한다 캐릭터 세트를.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-sensitivity.html 에 따르면 "latin1_bin"도 있습니다.

"utf8_general_cs"는 mysql 시작에 의해 받아 들여지지 않았다. ( "_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 사용)
user10398534

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

DB 수준에서 아무것도 변경할 필요가 없으며 SQL 쿼리에서 변경하면됩니다.

예 -

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

이진 키워드는 대소 문자를 구분합니다.


1

mysql은 기본적으로 대소 문자를 구분하지 않습니다. 언어 데이터 정렬을 latin1_general_cs

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.