一、現象
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('lingyejun'); #無空格 INSERT INTO user_info(user_name) values('lingyejun '); #一個空格 INSERT INTO user_info(user_name) values('lingyejun '); #四個空格
如上有個user_info表,我們分別插入'lingyejun'、'lingyejun '、'lingyejun '三個用戶。
但我們在查詢時卻遇到一個詭異的現象:
SELECT * FROM user_info WHERE user_name = 'lingyejun'; #無空格 SELECT * FROM user_info WHERE user_name = 'lingyejun '; #一個空格 SELECT * FROM user_info WHERE user_name = 'lingyejun '; #兩個空格
SELECT * FROM user_info WHERE user_name = 'lingyejun '; #四個空格
二、原因
查詢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 user_info WHERE user_name LIKE 'lingyejun'; SELECT * FROM user_info WHERE user_name LIKE 'lingyejun '; #一個空格 SELECT * FROM user_info WHERE user_name LIKE 'lingyejun '; #四個空格
3.2 binary
binary不是函數,是類型轉換運算符,它用來強制它後面的字符串爲一個二進制字符串,可以理解成精確匹配。
SELECT * FROM user_info WHERE user_name = BINARY 'lingyejun'; SELECT * FROM user_info WHERE user_name = BINARY 'lingyejun '; #一個空格 SELECT * FROM user_info WHERE user_name = BINARY 'lingyejun '; #四個空格
注:這裏的BINARY關鍵字要放在“=”的後邊,以便有效利用該字段的索引。
四、結論
- MySQL的CHAR、VARCHAR、TEXT等字符串字段在等值比較("=")時,基於PAD SPACE校對規則,會忽略掉尾部的空格;
- 在存儲時,不會自動截斷尾部的空格,會按原值存儲;
- 如果想要精確查詢就不能用等值查詢(“=”),而應改用like或binary。
本篇文章如有幫助到您,請給「翎野君」點個贊,感謝您的支持。