MySQL中文拼音排序的問(wèn)題與解決方案
問(wèn)題
在做通訊錄、人員列表等功能時(shí),經(jīng)常會(huì)碰到按照中文拼音排序的問(wèn)題。
我們?cè)谶@里可以用一個(gè)簡(jiǎn)單的例子進(jìn)行說(shuō)明
先創(chuàng)建測(cè)試數(shù)據(jù)
CREATE TABLE user (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
INSERT INTO user (name) VALUES
('張三'),('李四'),('王五'),('趙六'),('錢(qián)七'),('孫八'),('周九'),('吳十');
下面,我們希望查出數(shù)據(jù),并且按照中文拼音順序排序
很簡(jiǎn)單,這樣就行了
SELECT * FROM user ORDER BY name;
可是,執(zhí)行后卻發(fā)現(xiàn),結(jié)果似乎并不符合預(yù)期

這其實(shí)是因?yàn)?,MySQL 默認(rèn)字符集排序:
utf8mb4_general_ciutf8mb4_unicode_ci
這些排序是 按 Unicode 編碼點(diǎn)排序,而不是拼音順序。
那么,我怎么實(shí)現(xiàn)中文拼音排序呢?
解決辦法
方法一
默認(rèn)字符集排序不支持,那我不用默認(rèn)字符集不就行了,看我的
SELECT * FROM user ORDER BY CONVERT(NAME USING gbk);

如果在 xml 里面使用,注意使用CDATA包裹
<select id="listUsers" resultType="User"> SELECT id, name FROM user ORDER BY <![CDATA[CONVERT(name USING gbk)]]> </select>
可行是可行,但是每次查詢(xún)都要做編碼轉(zhuǎn)化,有沒(méi)有更簡(jiǎn)單粗暴的方法?
方法二
有的兄弟,有的
我們可以跳過(guò)編碼轉(zhuǎn)化這一個(gè)步驟,添加一個(gè)冗余字段,在數(shù)據(jù)變更時(shí)寫(xiě)入拼音不就行了(空間換時(shí)間打法還是太強(qiáng)了)
我們先添加字段
ALTER TABLE user ADD COLUMN pinyin VARCHAR(100) AFTER name;
再導(dǎo)入這樣一個(gè)依賴(lài)
<dependency>
<groupId>com.belerweb</groupId>
<artifactId>pinyin4j</artifactId>
<version>2.5.1</version>
</dependency>
再建立對(duì)應(yīng)工具類(lèi)
public class PinyinUtil {
/**
* @param chinaStr 中文字符串
* @return 中文字符串轉(zhuǎn)拼音 其它字符不變
*/
public static String getPinyin(String chinaStr){
HanyuPinyinOutputFormat formart = new HanyuPinyinOutputFormat();
formart.setCaseType(HanyuPinyinCaseType.LOWERCASE);
formart.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
formart.setVCharType(HanyuPinyinVCharType.WITH_V);
char[] arrays = chinaStr.trim().toCharArray();
String result = "";
try {
for (int i=0;i<arrays.length;i++) {
char ti = arrays[i];
if(Character.toString(ti).matches("[\u4e00-\u9fa5]")){ //匹配是否是中文
String[] temp = PinyinHelper.toHanyuPinyinStringArray(ti,formart);
result += temp[0];
}else{
result += ti;
}
}
} catch (BadHanyuPinyinOutputFormatCombination e) {
e.printStackTrace();
}
return result;
}
}
PinyinUtil.getPinyin()會(huì)根據(jù)中文字符串返回對(duì)應(yīng)的拼音字符串
在涉及到數(shù)據(jù)變更(新增、修改、導(dǎo)入等場(chǎng)景)時(shí),寫(xiě)入冗余字段就行
String pinyin = PinyinUtil.getPinyin(name); user.setPinyin(pinyin);
我們的測(cè)試數(shù)據(jù)表在經(jīng)過(guò)處理后,就變成了這樣

查詢(xún)時(shí),對(duì)冗余字段排序即可
SELECT * FROM user ORDER BY pinyin;

當(dāng)數(shù)據(jù)量超過(guò) 幾百萬(wàn)條以上,方法二的優(yōu)勢(shì)會(huì)明顯
當(dāng)然,方法一不用做多余操作,直接sql搞定,也是一個(gè)優(yōu)點(diǎn)
到此這篇關(guān)于MySQL中文拼音排序的問(wèn)題與解決方案的文章就介紹到這了,更多相關(guān)MySQL中文拼音排序內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
MySQL主從搭建(多主一從)的實(shí)現(xiàn)思路與步驟
通過(guò)MySQL主從配置,可以實(shí)現(xiàn)讀寫(xiě)分離減輕數(shù)據(jù)庫(kù)壓力,最近正好遇到這個(gè)功能,所以這篇文章主要給大家介紹了關(guān)于MySQL主從搭建(多主一從)的實(shí)現(xiàn)思路與步驟,需要的朋友可以參考下2021-05-05
MySQL事務(wù)及Spring隔離級(jí)別實(shí)現(xiàn)原理詳解
這篇文章主要介紹了MySQL事務(wù)及Spring隔離級(jí)別實(shí)現(xiàn)原理詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-05-05
通過(guò)緩存+SQL修改優(yōu)雅地優(yōu)化慢查詢(xún)
本文通過(guò)介紹緩存的基本原理和SQL語(yǔ)句的優(yōu)化手段,以及實(shí)際案例的分析,為讀者提供了一種簡(jiǎn)單而有效的優(yōu)化思路。讀者可以通過(guò)本文了解到如何在不修改程序代碼的情況下,通過(guò)巧妙地運(yùn)用緩存和SQL優(yōu)化技巧,提高程序的性能和響應(yīng)速度。2023-04-04

