SQL算术运算需警惕NULL和隐式类型转换陷阱,应使用COALESCE、CAST、NULLIF等显式处理;WHERE中避免左侧计算以防索引失效;跨库除法需统一精度;生成列虽固化逻辑但受确定性、类型声明及更新一致性约束。

SQL里直接用+、-、*、/就能算,但空值和类型不匹配会悄悄出错
算术运算符本身没门槛,但真实数据里NULL和隐式类型转换是最大陷阱。比如price * tax_rate只要任一字段为NULL,整列结果全变NULL;又比如quantity是字符串,'10' * 2在MySQL里可能得出来20,但在PostgreSQL直接报错operator does not exist: text * integer。
实操建议:
- 用
COALESCE(price, 0)或NULLIF(price, 0)提前兜底,别依赖数据库默认行为 - 显式转类型:
CAST(quantity AS INTEGER)或quantity::INTEGER(PostgreSQL) - 除法前加
NULLIF(denominator, 0)防division by zero错误
WHERE里用算术表达式过滤时,索引大概率失效
写WHERE price * 1.1 > 100很直观,但绝大多数数据库无法用上price字段的索引——因为优化器得先算完每行再比,等于全表扫描。
更稳妥的做法:
- 把计算移到右边:
WHERE price > 100 / 1.1(前提是运算可逆) - 如果必须用左边计算,考虑建函数索引(如PostgreSQL的
CREATE INDEX idx_price_tax ON sales ((price * 1.1))) - 避免在WHERE里调用
ROUND()、FLOOR()这类函数,它们同样阻断索引使用
不同数据库对/的结果类型处理差异极大
SELECT 5 / 2在SQL Server返回2(整数除),在PostgreSQL返回2.5(自动转浮点),在MySQL取决于操作数类型:两个整数就截断,一个带小数点就保留精度。
要跨库一致,必须显式控制:
- 强制浮点:写成
5.0 / 2或CAST(5 AS DECIMAL) / 2 - 需要整除时用
TRUNCATE()(MySQL)、FLOOR()(PostgreSQL)或ROUND()配合CAST - 注意
DECIMAL(p,s)的精度声明,price * 1.08若原字段是DECIMAL(10,2),结果可能被截断成DECIMAL(10,2),丢失小数位
生成列(Generated Column)能固化计算逻辑,但不是所有库都支持
MySQL 5.7+、PostgreSQL 12+、SQL Server支持持久化生成列,SQLite只支持虚拟列。语法看着简单:total_price DECIMAL(10,2) AS (price * (1 + tax_rate)) STORED,但背后有硬约束:
- 表达式必须是确定性的(不能含
NOW()、RAND()、子查询) - MySQL要求生成列必须有明确的数据类型声明,且不能是
TEXT/BLOB - PostgreSQL的
STORED列实际是写入时计算并存储,但更新源字段时不会自动刷新——得靠触发器或应用层保证一致性
真正容易被忽略的是权限和迁移成本:生成列一旦建好,改底层字段类型可能失败;某些ORM工具读取表结构时会把生成列当普通字段,导致INSERT语句意外报错。

















