前段時間在工作中測試提出了一個BUG,讓我把根據ID查詢區分大小寫的功能去掉,大小寫都隨便查,然后我在SQL的位置加上了UPPER(id) = UPPER(#{id})
的寫法,而同事知道這個問題后的反映是"MySQL查詢不是本就不區分大小寫嗎",后來我找機會簡單了解了一下才明白,MySQL區分大小寫取決於數據庫的排序規則,今天在這里記錄一下
一般創建數據庫都會使用utf8
編碼,對應兩種常用的排序規則就是utf8_bin
和utf8_general_ci
,其中utf8_bin
就是區分大小的排序規則,另一個就是不區分大小寫的排序規則,接下來針對排序規則進行一些簡單的測試
注意:本人使用的Navicat客戶端工具,其他客戶端工具可能會對測試結果造成影響(例如SQLyog)
先測試區分大小寫的排序規則
-- 創建區分大小寫的數據庫
CREATE DATABASE test DEFAULT CHARACTER SET utf8 COLLATE utf8_bin;
-- 選擇數據庫
USE test;
-- 創建一張測試表
CREATE TABLE aaa (
id VARCHAR(16),
PRIMARY KEY(id)
);
-- 插入測試數據
INSERT INTO aaa VALUES('abc');
-- 正常查詢,可以查詢到結果
SELECT id FROM aaa WHERE id = 'abc';
-- 修改大小寫后,查詢不到結果
SELECT id FROM aaa WHERE id = 'abC';
可以看出排序規則為bin
的數據庫使用查詢是區分大小寫的,然后再測試一下不區分大小寫的
-- 創建不區分大小寫的數據庫
CREATE DATABASE test2 DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
-- 選擇數據庫
USE test2;
-- 創建一張測試表
CREATE TABLE aaa (
id VARCHAR(16),
PRIMARY KEY(id)
);
-- 插入測試數據
INSERT INTO aaa VALUES('abc');
-- 正常查詢,可以查詢到結果
SELECT id FROM aaa WHERE id = 'abc';
-- 修改大小寫后同樣可以查詢到結果
SELECT id FROM aaa WHERE id = 'abC';
可以看出general_ci
是不區分大小寫的,有了結論后我們把test
庫修改為不區分大小寫試試看
-- 將數據庫的排序規則修改為utf8_general_ci
ALTER DATABASE test CHARACTER SET utf8 COLLATE utf8_general_ci;
-- 選擇test數據庫
USE test;
-- 再次查詢,還是查詢不到結果
SELECT id FROM aaa WHERE id = 'abC';
這里已經把數據庫的排序規則修改了,怎么還是查不到數據呢?原因是因為直接改庫只對以后創建的表生效,並不會對已存在的表造成影響,這里新建一張表來測試一下
CREATE TABLE bbb (
id VARCHAR(16),
PRIMARY KEY(id)
);
INSERT INTO bbb VALUES('bbb');
SELECT id FROM bbb WHERE id = 'bBb';
果然,后續創建的表是不區分大小寫的,接下來需要讓已經創建的表也不區分大小寫,這里直接修改表的排序規則試試
-- 將表的排序規則修改為utf8_general_ci
ALTER TABLE aaa DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
-- 再次查詢,還是查詢不到結果
SELECT id FROM aaa WHERE id = 'abC';
修改表的排序規則不行,那就修改字段(列)的排序規則
-- 將字段的排序規則修改為utf8_general_ci
ALTER TABLE aaa MODIFY id VARCHAR(16) CHARACTER SET utf8 COLLATE utf8_general_ci;
-- 再次查詢,查詢成功!
SELECT id FROM aaa WHERE id = 'abC';
通過測試我們可以知道,排序規則分別有三個生效的作用域,分別是 列、表、庫,而他們之間生效的優先級為列 > 表 > 庫
,只要列的排序規則修改成功,表和庫的排序規則對於列來說就不重要了
經過測試了解到如果想要某個字段不區分大小寫查詢,就執行如下SQL修改他的排序規則即可:
ALTER TABLE [表名] MODIFY [字段名] [字段類型] CHARACTER SET utf8 COLLATE utf8_general_ci;
如果表中有大批字段需要修改的話一個一個改很麻煩,可以調用這段SQL修改表以及表中所有字段
ALTER TABLE [表名] CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;
擴展
其實除了utf8_general_ci
排序規則之外,utf8_unicode_ci
同樣不區分大小寫,只不過unicode
相對於general
效率較低,但是查詢精准度更高一些,詳情點擊這里(其實我也不懂)