UPPER和LOWER是标量函数,仅作用于单个字符串字段,不能用于整行或通配符;对NULL返回NULL;中文等无大小写字符原样返回;多列拼接需先处理NULL再转换;WHERE中滥用会导致索引失效,应建函数索引。

SQL里UPPER和LOWER只能处理字符串字段,不能直接转整个结果集
很多人试过 SELECT UPPER(*) FROM table,发现报错——因为 UPPER 是标量函数,只接受单个字符串表达式作为参数,不支持通配符或整行。它作用对象是列值,不是结果集结构。
常见错误现象:ERROR: function upper(record) does not exist(PostgreSQL)、ORA-00909: invalid number of arguments(Oracle)或 MySQL 的 FUNCTION schema.upper does not exist,本质都是传了非字符串类型进去。
- 使用场景:清洗姓名、城市名、状态码等需要统一大小写的文本字段
- 不能对数字、日期、NULL 直接用
UPPER;MySQL 会静默转成字符串再处理,但 PostgreSQL 和 SQL Server 会直接报错 - 如果字段可能为 NULL,
UPPER(NULL)结果仍是NULL,无需额外判空(除非业务要求转成空字符串)
不同数据库对UPPER/LOWER的字符集敏感性差异很大
中文、日文、俄文字母本身没有大小写概念,所以 UPPER('你好') 在所有主流数据库里都原样返回;真正受影响的是拉丁字母、带重音符号的西欧字符(如 é、ñ),而它们的表现取决于数据库的 collation 设置。
例如在 MySQL 中:UPPER('café') 在 utf8mb4_unicode_ci 下返回 CAFÉ,但在 utf8mb4_bin 下可能返回 CAFÉ 或 CAFé(取决于具体实现版本);PostgreSQL 则严格依赖操作系统 locale,LC_CTYPE 设为 en_US.UTF-8 才能正确处理 ß → SS 这类德语转换。
- MySQL 8.0+ 支持
UPPER(str COLLATE utf8mb4_0900_as_cs)显式指定排序规则 - PostgreSQL 推荐用
upper(str::text)配合set lc_ctype = 'en_US.UTF-8'确保一致性 - SQL Server 默认使用数据库级 collation,改字段 collation 成本高,不如在应用层处理特殊字符
想让多列同时大写?别堆叠UPPER,用CONCAT或字符串拼接更可控
有人想把姓名和部门合并后转大写,写成 UPPER(last_name + ', ' + dept_name),这在 SQL Server 可行,但在 MySQL 里 + 是加法运算符,会报错;PostgreSQL 则根本不支持 + 拼字符串。
正确做法是先拼再转,且注意空值陷阱:任何一列是 NULL,整个 CONCAT 结果就是 NULL(MySQL)或需用 || 加 COALESCE(PostgreSQL)。
- MySQL:
UPPER(CONCAT(COALESCE(first_name, ''), ' ', COALESCE(last_name, ''))) - PostgreSQL:
UPPER(COALESCE(first_name, '') || ' ' || COALESCE(last_name, '')) - SQL Server:
UPPER(ISNULL(first_name, '') + ' ' + ISNULL(last_name, '')) - 避免写
UPPER(col1), UPPER(col2)后在应用层拼——网络传输和内存开销更大
性能影响很小,但WHERE里滥用UPPER会导致索引失效
SELECT * FROM users WHERE UPPER(name) = 'JOHN' 看似合理,实际会让 name 字段上的普通 B-tree 索引完全失效(除非建函数索引)。因为数据库无法预知 UPPER(name) 的值对应哪些原始值,只能全表扫描。
解决办法不是“少用”,而是提前规划:如果业务高频查大写匹配,就该建函数索引或冗余字段。
- PostgreSQL:
CREATE INDEX idx_users_upper_name ON users (UPPER(name)); - MySQL 8.0+:
CREATE INDEX idx_upper_name ON users ((UPPER(name))); - SQL Server:
CREATE INDEX idx_upper_name ON users (name) INCLUDE (id);+ 查询改用WHERE name = 'john'并确保查询条件也小写(更推荐) - 如果只是偶尔导出报表用,
UPPER在 SELECT 列表里完全没性能压力
最常被忽略的一点:函数索引只在显式调用同名函数时才命中,比如你建了 UPPER(name) 索引,但写 WHERE name LIKE 'JOHN%' 依然走不了。

















