SQL Server字符集排序规则:大小写敏感设置,让你的查询不再“左右为难“
同样的SQL,有的库能查出来,有的库查不出来?问题可能出在排序规则上!
大家好。今天来聊聊一个容易被忽视但非常重要的数据库设置——排序规则(Collation)。
你是否遇到过这样的情况:
开发环境查询WHERE name = 'abc'能查到ABC,生产环境却查不到?
两个库联查时报错"无法解决排序规则冲突"?
用户输入'张三',数据库里存的是'张 三'(全角空格),死活匹配不上?
这些问题都跟排序规则有关。
排序规则决定了SQL Server如何处理:
大小写:abc = ABC?
重音:café = cafe?
假名类型:日语的平假名和片假名是否等同?
字符宽度:全角字符和半角字符是否等同?
USE [master]GOALTER DATABASE [你的数据库名]COLLATE Chinese_PRC_CI_AIGO
效果:查询'abc'能匹配到'ABC'、'Abc'、'aBc'
USE [master]GOALTER DATABASE [你的数据库名]COLLATE Chinese_PRC_CS_AIGO
排序规则名称由三部分组成:语言_前缀_后缀
Chinese_PRC_CI_AI_WS└─┬─┘ └┬┘ └┬┘ └┬┘│ │ │ └── WS:区分宽度│ │ └────── AI:不区分重音│ └────────── CI:不区分大小写└─────────────── 简体中文
| CI | 'A' = 'a' | |
| CS | 'A' ≠ 'a' | |
| AI | 'é' = 'e' | |
| AS | 'é' ≠ 'e' | |
| KS | ||
| KI | ||
| WS | 'A'(全角) ≠ 'A'(半角) | |
| WI | 'A'(全角) = 'A'(半角) |
| 公司最常用 | ||||
-- 查看服务器排序规则SELECT SERVERPROPERTY('Collation') AS 服务器排序规则-- 查看数据库排序规则SELECT name, collation_name FROM sys.databasesWHERE name = DB_NAME()-- 查看某列的排序规则SELECTTABLE_NAME,COLUMN_NAME,COLLATION_NAMEFROM INFORMATION_SCHEMA.COLUMNSWHERE COLLATION_NAME IS NOT NULL
-- 问题:用户输入"admin",但数据库存的是"ADMIN",查不到-- 解决:修改数据库为不区分大小写ALTER DATABASE UserDB COLLATE Chinese_PRC_CI_AS
-- 错误:无法解决排序规则冲突SELECT * FROM db1.Users u1JOIN db2.Users u2 ON u1.Name = u2.Name-- 解决1:临时转换SELECT * FROM db1.Users u1JOIN db2.Users u2 ON u1.Name = u2.Name COLLATE Chinese_PRC_CI_AS-- 解决2:修改其中一个库的排序规则(需要评估影响)ALTER DATABASE db2 COLLATE Chinese_PRC_CI_AS
-- 密码验证必须区分大小写-- 可以在查询时临时指定排序规则SELECT * FROM UsersWHERE Username = @usernameAND Password = @passwordAND Password COLLATE Chinese_PRC_CS_AS = @password
修改后可能需要重建索引 |
-- 1. 备份数据库BACKUP DATABASE MyDB TO DISK = 'D:\Backup\MyDB.bak'-- 2. 设置为单用户模式ALTER DATABASE MyDB SET SINGLE_USER WITH ROLLBACK IMMEDIATE-- 3. 修改排序规则ALTER DATABASE MyDB COLLATE Chinese_PRC_CI_AS-- 4. 恢复多用户模式ALTER DATABASE MyDB SET MULTI_USER-- 5. 重建索引(可选,建议执行)USE MyDBEXEC sp_recompile N'所有用户表' -- 实际需要逐个表重建
-- 创建时直接指定CREATE DATABASE MyNewDBCOLLATE Chinese_PRC_CS_AS
-- 不改变数据库,只在这条查询中生效SELECT * FROM UsersWHERE Name = 'admin' COLLATE Chinese_PRC_CS_AS-- 列级别指定SELECTName,Name COLLATE Chinese_PRC_CS_AS AS SensitiveNameFROM Users
-- 问题:查询大小写不敏感,但实际是敏感的?-- 排查当前数据库排序规则SELECT DATABASEPROPERTYEX(DB_NAME(), 'Collation') AS 排序规则-- 如果包含CS(Case-Sensitive),就是区分大小写-- 需要改为CI(Case-Insensitive)
| CI/CS | |
| AI/AS | |
| Chinese_PRC_CI_AS | |
一句话:CI不区分大小写(宽松),CS区分大小写(严格),大多数业务系统选Chinese_PRC_CI_AS就对了!
阅读原文:原文链接