SQL除零错误排查:已尝试CAST、NULLIF仍未解决
首先,咱们直接说问题根源:你的discount计算逻辑里,当pricebefore字段转换后的值为0时,就会触发除零错误。而你遇到的“移除ORDER BY就正常”的情况,其实是数据库执行计划差异导致的巧合——当加上ORDER BY CAST(price AS Float) asc时,数据库会先对所有符合条件的行计算discount字段(为了完成全局排序),只要有任何一行pricebefore为0,就会立刻报错;但如果没有ORDER BY,数据库可能先执行LIMIT/OFFSET取分页数据,再计算discount,刚好当前分页的行里没有pricebefore为0的,所以没触发错误,但这只是暂时的,后续分页还是可能踩坑。
你提到用了CAST、NULLIF但无效,大概率是NULLIF的用法不对。正确的做法是把分母部分用NULLIF包裹,让分母为0时返回NULL,这样除法运算结果会变成NULL而非抛出错误。修改后的SQL应该是这样:
$sql = "SELECT *, (cast(price as numeric(20, 4))*100)/NULLIF(cast(pricebefore as numeric(20, 4)), 0) - 100 AS discount FROM products ORDER BY CAST(price AS Float) asc LIMIT $no_of_records_per_page OFFSET $offset";
这里NULLIF(cast(pricebefore as numeric(20, 4)), 0)的作用是:如果转换后的pricebefore等于0,就返回NULL,否则返回转换后的值。当分母是NULL时,整个除法表达式的结果会是NULL,不会触发除零错误。
另外还有个小建议:CAST(price AS Float)可能会带来精度问题,如果你price本身是数值类型,直接用price asc排序就好;如果是字符串类型,建议用CAST(price AS numeric(20,4))排序,避免Float的精度丢失。
内容的提问来源于stack exchange,提问作者Ilaroz

