MySQL字段等值查詢時,尾部有空格也能匹配上的坑


一、現象

CREATE TABLE `user_info` (
  `id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主鍵自增ID',
  `user_name` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '名字',
 
  PRIMARY KEY (`id`),
  KEY `idx_user_name` (`user_name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用戶表';
 
INSERT INTO user_info(user_name) values('adu');
INSERT INTO user_info(user_name) values('adu '); #一個空格
INSERT INTO user_info(user_name) values('adu    '); #四個空格

 

如上有個user_info表,我們分別插入'adu'、'adu '、'adu    '三個用戶。

但我們在查詢時卻遇到一個詭異的現象:

SELECT * FROM adu_user_info WHERE user_name = 'adu';
SELECT * FROM adu_user_info WHERE user_name = 'adu '; #一個空格
SELECT * FROM adu_user_info WHERE user_name = 'adu  '; #兩個空格
 

無論查詢中尾部帶有幾個空格,結果是一樣的,都會命中'adu'、'adu '、'adu    '三個用戶

 

二、原因

查詢MySQL的官方文檔(https://dev.mysql.com/doc/refman/5.7/en/char.html),原來MySQL的校對規則基於PAD SPACE,這就意味着CHAR、VARCHAR、TEXT等字符串的等值比較(“=”)會忽略掉尾部的空格

 

而且這也符合SQL標准,無需設置也無法改變(參考:https://stackoverflow.com/questions/10495692/mysql-comparison-operator-spaces)。

 

三、想要精確查詢的解決方案

3.1 like

like不會忽略尾部的空格。

SELECT * FROM adu_user_info WHERE user_name LIKE 'adu';
SELECT * FROM adu_user_info WHERE user_name LIKE 'adu '; #一個空格
SELECT * FROM adu_user_info WHERE user_name LIKE 'adu    '; #四個空格

 

3.2 binary

binary不是函數,是類型轉換運算符,它用來強制它后面的字符串為一個二進制字符串,可以理解成精確匹配。

SELECT * FROM adu_user_info WHERE user_name = BINARY 'adu';
SELECT * FROM adu_user_info WHERE user_name = BINARY 'adu '; #一個空格
SELECT * FROM adu_user_info WHERE user_name = BINARY 'adu    '; #四個空格

注:這里的BINARY關鍵字要放在“=”的后邊,以便有效利用該字段的索引。

四、結論

  • MySQL的CHAR、VARCHAR、TEXT等字符串字段在等值比較("=")時,基於PAD SPACE校對規則,會忽略掉尾部的空格
  • 在存儲時,不會自動截斷尾部的空格,會按原值存儲
  • 如果想要精確查詢就不能用等值查詢(“=”),而應改用like或binary

五、參考

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM