必须两端同步转换才能实现大小写不敏感匹配,如where upper(name) = upper('alice');只转一边会导致比较失效且索引无法下推,而collate等方案跨库兼容性差、行为不一致。

直接用 UPPER() 或 LOWER() 两端同时转换,是最可靠、跨库可用的精确匹配方案。 其他方式(如 COLLATE、ILIKE)要么数据库不支持,要么行为不一致,或隐含索引风险。
为什么不能只转一边?
常见错误是写成 WHERE UPPER(name) = 'alice' 或 WHERE name = UPPER('alice')。这两种都无效:前者把字段转大写后跟小写字符串比,后者拿原始大小写混合的字段直接跟大写值比,两边根本不在同一“大小写平面”上。
必须两端同步转换:
WHERE UPPER(name) = UPPER('alice')WHERE LOWER(name) = LOWER('alice')
注意:CONCAT() 后再套 UPPER() 也适用,但需配合 COALESCE() 防 NULL 中断表达式,例如:UPPER(CONCAT(COALESCE(first_name,''), COALESCE(last_name,'')))。
COLLATE 在不同数据库里表现差异极大
COLLATE 不是通用解法,它在各数据库中生效条件、语法、性能影响完全不同:
- MySQL:支持临时加
COLLATE utf8mb4_0900_as_cs,但如果字段本身是_bin或_cs规则,且没建对应 collation 的索引,查询会跳过索引——看似写得简洁,实则慢得隐蔽 - PostgreSQL:不支持
WHERE col COLLATE ... = 'val'这种写法;COLLATE "en-u-ks-level2"要求启用 ICU,且版本兼容性差;日常应优先用ILIKE(仅限模糊)或LOWER()(精确) - SQL Server:支持
COLLATE SQL_Latin1_General_CP1_CI_AS,但 JOIN 时若两边 collation 不一致,会直接报Cannot resolve collation conflict - SQLite:不允许查询中加
COLLATE,只接受建表时声明name TEXT COLLATE NOCASE;临时写WHERE name COLLATE NOCASE = 'ABC'会语法错误
函数索引是性能关键,但容易被忽略
用 UPPER(name) = UPPER(?) 写法天然无法命中普通索引。如果字段数据量大,必须补函数索引:
- PostgreSQL:
CREATE INDEX idx_users_upper_name ON users (UPPER(name)); - MySQL 8.0+:
CREATE INDEX idx_users_upper_name ON users ((UPPER(name)));(注意双括号) - SQL Server:
CREATE INDEX idx_users_upper_name ON users (UPPER(name)); - SQLite:
CREATE INDEX idx_users_upper_name ON users (UPPER(name));
漏建这个索引,哪怕只查 10 万行,也可能从毫秒级退化为秒级——而这个瓶颈在开发阶段几乎不会暴露。
真正难的不是写出能跑的语句,而是确认当前字段的 collation 实际生效逻辑、判断是否已有函数索引、并在迁移或换库时守住大小写行为的一致性。这些细节不出现在 SQL 里,却决定线上查询会不会突然变慢或漏数据。










