现状描述
今天,开发人员找到我,订单报错,分析后定位到一条sql:
SELECT
忽略内容,
t.amount-
(SELECT
COUNT(gd.subs_id)
FROM
隐藏表名 AS gd
WHERE gd.order_id = t.order_id
AND gd.contract_type = 57
AND gd.buyorsell = 1
AND gd.status NOT IN (- 2, - 3)) AS amount_left_s
FROM
原表名 t
WHERE t.domain_no = 2300
AND t.order_id = 61083
手动在从库执行此条sql,果然报错:BIGINT UNSIGNED value is out of range in(xxx)
解决过程
1.从报错来看,是字段类型超过限制导致,因此将计算字段分拆,看能否执行通过:
t.amount-
(SELECT
COUNT(gd.subs_id)
FROM
隐藏表名 AS gd
WHERE gd.order_id = t.order_id
AND gd.contract_type = 57
AND gd.buyorsell = 1
AND gd.status NOT IN (- 2, - 3)) AS amount_left_s
改为
t.amount ,
(SELECT
COUNT(gd.subs_id)
FROM
隐藏表名 AS gd
WHERE gd.order_id = t.order_id
AND gd.contract_type = 57
AND gd.buyorsell = 1
AND gd.status NOT IN (- 2, - 3)) AS amount_left_s
两个字段,结论是可以查询出结果,且值如下图:
两值相减为负数,符合报错的含义,将此结果反映给开发,开发人员认为是产品逻辑的问题,去重写逻辑了。
2.虽然业务上此问题解决了,但是技术上,就报错本身,可以再深入研究下。我创建了一张表:
执行如下语句发现报错:
select a,b,a-b from t;
错误代码: 1690
BIGINT UNSIGNED value is out of range in '(`aaa`.`t`.`a` - `aaa`.`t`.`b`)'
做如下的表结果更改仍然报错:
说明只要参与计算的字段存在unsigend设置,就会执行失败。若是两个字段都取消unsigned设置,则会查询出结果:(SELECT a,b,a-b FROM t;)
3.反映到上面业务上的情况,假设允许最终结果为负值,则有如下两种方案:
(1)后一个字段为子查询,且结果为count,因此只需要更改前面字段类型为signed即可。将t.amount字段类型修改为signed。
(2)当业务不允许ddl表时,可以修改sql语句,临时转换字段类型进行处理,以我自建表为例,刚才语句可以做如下改写:
SELECT a,b,a-b FROM t;
修改为
select a,b,cast(a as signed)-cast(b as signed) from t;