MySQL用COLLATE utf8mb4_general_ci可实现不区分大小写的索引友好匹配;PostgreSQL推荐ILIKE或LOWER()配函数索引;SQLite需建表时指定COLLATE NOCASE;跨库统一用LOWER()但须建对应函数索引。

MySQL里用COLLATE做不区分大小写匹配最省事
直接在WHERE条件里加COLLATE utf8mb4_general_ci(或utf8mb4_0900_as_cs以外的_ci结尾校对规则),就能让等值比较自动忽略大小写。不用改数据、不用套函数,查询还能走索引——前提是字段本身用了支持_ci的校对规则。
常见错误现象:SELECT * FROM users WHERE name = 'Alice'查不到'alice',但表里明明有;其实只是字段定义是utf8mb4_bin或utf8mb4_0900_as_cs这种严格校对规则。
- 确认字段校对规则:查
SHOW CREATE TABLE users,看name列末尾是不是_ci - 临时生效:加
COLLATE只影响当前表达式,比如WHERE name COLLATE utf8mb4_general_ci = 'alice' - 永久生效:建表时指定
name VARCHAR(50) COLLATE utf8mb4_general_ci,或用ALTER TABLE修改列 - 注意:如果字段是
BINARY类型或显式声明_bin校对,COLLATE必须显式写出,否则无效
PostgreSQL里用ILIKE或LOWER要小心索引失效
ILIKE是PG原生不区分大小写的操作符,语义清晰,且在有合适索引(如LOWER(name)函数索引)时能走索引;而LOWER(name) = LOWER('input')写法更通用,但默认不会命中普通B-tree索引。
使用场景:想快速改一句SQL就跑通,又不想动表结构,优先选ILIKE;如果已在其他地方大量用LOWER(),保持风格一致也行。
-
ILIKE支持通配符,比如name ILIKE '%bob%',LOWER()做不到这点 - 性能关键路径上,必须建函数索引:
CREATE INDEX idx_users_name_lower ON users (LOWER(name)) - 别写
WHERE LOWER(name) = LOWER($1)却没建对应索引——全表扫描立马出现 - 注意:PG 12+ 支持
COLLATION语法,但不如ILIKE直觉,日常少用
SQLite里没COLLATE选项?用NOCASE collation代替
SQLite不支持MySQL那种动态COLLATE后缀,但建表时可以指定COLLATE NOCASE,之后所有等值比较和ORDER BY都自动忽略大小写。
容易踩的坑:很多人试了WHERE name COLLATE NOCASE = 'ABC'发现报错,因为SQLite只允许在CREATE TABLE或CREATE INDEX里声明collation,不能在查询里临时加。
- 建表时写:
name TEXT COLLATE NOCASE,之后WHERE name = 'abc'就能匹配'ABC' - 已有表?只能用
LOWER(name) = LOWER('abc'),但记得给LOWER(name)建索引:CREATE INDEX idx_name_lower ON table_name (LOWER(name)) - 注意:
NOCASE只对ASCII字母有效,遇到带重音符号的字符(如é)可能不准确
跨数据库写法统一?LOWER最保险但代价明确
如果SQL要跑在MySQL/PG/SQLite甚至SQL Server上,LOWER(col) = LOWER(? )是唯一真正可移植的写法。但它天然牺牲两点:索引利用率、表达简洁性。
为什么还提它?因为很多ORM或中间层会自动帮你加LOWER(),或者你根本没法控制底层SQL的校对规则。
- 必须同步建函数索引,否则每次都是全表扫——MySQL/PG/SQLite都一样
- 参数绑定时,确保传入的值也经过
LOWER()处理,避免一边大写一边小写白忙活 - 别在
WHERE里嵌套多层函数,比如LOWER(TRIM(name)),索引基本作废,且可读性暴跌 - SQL Server用户注意:
LOWER()在默认校对下本就忽略大小写,加不加效果一样,但显式写出更易维护
真正麻烦的从来不是写法本身,而是索引要不要建、建在哪、建完有没有被用上——查EXPLAIN比背语法重要得多。

















