直接写 price * 0.9 不报错但结果可能异常:NULL 导致全结果为 NULL,数据类型隐式转换因库而异(如 PostgreSQL 用 NUMERIC,SQLite 用浮点),且易溢出;应显式处理 NULL、控制精度、避免运算导致索引失效。

SELECT 里直接写 price * 0.9 会出问题吗?
不会报错,但结果可能和你想的不一样——尤其是遇到 NULL 或数据类型隐式转换时。price 是 INT,0.9 是浮点字面量,多数数据库会把整数提升为浮点再算,但 PostgreSQL 会先尝试用 NUMERIC 算,而 SQLite 可能全程用浮点近似。更麻烦的是:只要 price 是 NULL,整个 price * 0.9 就是 NULL,不是 0,也不是空字符串。
实操建议:
- 显式处理
NULL:用COALESCE(price, 0) * 0.9或IFNULL(price, 0) * 0.9(MySQL/SQLite) - 控制精度:PostgreSQL 推荐写成
price * 0.9::DECIMAL(10,2);SQL Server 用CONVERT(DECIMAL(10,2), price) * 0.9 - 避免意外截断:如果
price是SMALLINT,乘以大系数(如* 1000)可能溢出,加个CAST(price AS BIGINT)更稳
为什么 SELECT COUNT(*) + 1 在某些场景下返回 1 而不是预期值?
因为 COUNT(*) 是聚合函数,它让整条语句变成聚合查询——如果没有 GROUP BY,整张表被压成一行,此时加常量没问题;但一旦你混写了非聚合字段(比如 SELECT name, COUNT(*) + 1),多数数据库(PostgreSQL、SQL Server)直接报错:column "name" must appear in the GROUP BY clause;MySQL 5.7+ 默认也拒绝这种“模糊分组”。
实操建议:
- 确认是否真需要每行都加 1:如果是,别用
COUNT(*),改用窗口函数COUNT(*) OVER() + 1 - 如果只是想给结果集编号,用
ROW_NUMBER() OVER(ORDER BY id)更准确 - MySQL 用户注意:若启用了
sql_mode=STRICT_TRANS_TABLES,ONLY_FULL_GROUP_BY(默认开启),必须显式GROUP BY才能混用聚合与非聚合字段
WHERE price * 1.1 > 100 会导致索引失效?
极大概率会。数据库优化器通常无法在表达式左侧使用索引,尤其当列参与运算时——price * 1.1 是计算值,不是原始索引键。即使 price 上有索引,这个条件也无法走索引查找(Index Seek),只能全表扫描或索引扫描(Index Scan)后逐行计算。
实操建议:
- 重写为范围等价形式:
WHERE price > 100 / 1.1(前提是除法不引入精度误差) - 对常用计算建生成列并索引(MySQL 5.7+/PostgreSQL 12+):
ALTER TABLE products ADD COLUMN price_with_tax DECIMAL(10,2) STORED AS (price * 1.1),然后在该列建索引 - 避免在
WHERE或JOIN ON中对索引列做函数调用,比如WHERE UPPER(name) = 'ABC'同样有这问题
不同数据库对除法 / 的处理差异有多大?
非常大。MySQL 和 SQL Server 的 / 做整数除法时会截断小数(5 / 2 = 2),而 PostgreSQL 和 SQLite 默认返回浮点结果(5 / 2 = 2.5)。更隐蔽的是:SQL Server 中两个整数相除,结果仍是整数,哪怕你 SELECT 的是 5.0 / 2,只要字面量没带小数点,它就按整数算。
实操建议:
- 强制浮点运算:写成
5.0 / 2、CAST(5 AS FLOAT) / 2或5e0 / 2 - 整数除法取余统一用
%(MySQL/SQL Server/PostgreSQL)或MOD()(SQLite) - 跨库迁移时重点检查所有含
/的 WHERE 和 SELECT 表达式,尤其涉及分页、比例计算、税率换算的逻辑
最易被忽略的一点:算术表达式里的空格、括号顺序、负号位置,在不同方言中可能改变运算优先级或触发隐式类型转换。比如 -10 + 5 * 2 没问题,但 price - 10 + 5 * 2 和 price - (10 + 5) * 2 差得远——别靠记忆,该加括号就加。

















