今天有个同事向我反馈一个问题,说是客户在部署他们提供的一个sql语句时,报了ora错误,想让我帮忙看看是什么原因。
update sub_errs set error_status = 'READY_TO_RECYCLE' WHERE sub_appl_id = 3008 AND ENTITY_ID = 8336079 AND MASTER_TRX_ID = 202809364 and error_status = 'PENDING_DEPENDENCY'
Error report -
SQL Error: ORA-02290: ????????????????????????????? (APPO.SUB_ERRS_1CK)
首先看错误,还真接上小语种了,自己百度翻译了下,是违反约束条件的意思,也是开个玩笑,这个问题可以通过oerr来查看oracle的解释。
02290, 00000, "check constraint (%s.%s) violated"
// *Cause: The values being inserted do not satisfy the named check
// constraint.
// *Action: do not insert values that violate the constraint.
可以看出应该是约束的地方出问题了,从约束的命名来看是以CK结尾,即check constraint。
查看user_constraints中的search_condition字段,条件着实复杂,search_condition的条件如下:
(depen_ind='S' AND error_status='PENDING_DEPENDENCY')
OR (depen_ind='S' AND error_status='COMPLETED')
OR (depen_ind='S' AND error_status='PURGED')
OR depen_ind='B'
OR depen_ind='N'
即对于指定的字段 error_status 需要满足上面的这些条件。这个check constraint算是一个比较复杂的约束了。
可能有些人看这个约束就有点晕,到底是希望满足条件还是不满足条件啊。
我们可以类比一下,如果是not null constraint,可能约束就是类似 xxxx is not null的形式,这个时候是希望这个字段不为空的,即满足条件。所以这个问题是希望对 error_status ,满足上面的条件才行。
给同事解释了一通,让他去看看是不是现有环境中存在数据问题,是不是因为数据问题导致条件不满足的。
结果过了一会同事又过来向我确认,说按照那个条件查出的结果和原有的一致的。都是19条数据。
因为表中的数据很多,所以为了尽快复现这个问题,自己采用了exp的query选项导出数据, 这样就会只导出19条数据,数据量就小多了,导入到一个测试环境中,就可以大胆的测试了。
exp xxxxx/xxx file=a.dmp tables=sub_errs query=\" where sub_appl_id = 3008 AND ENTITY_ID = 8336079 \"
我先根据id来抽取数据,抽取出19条数据来,然后在测试用户中使用对应的约束进行修改,看看问题是否会复现。
导入数据很顺利,19条数据很快就导入了。
imp xxxxx/xxxx file=a.dmp tables= sub_errs indexes=n grants=n ignore=Y constraints=n buffer=9102000
这个时候尝试重现,发现问题依旧。
这个时候我们把问题拆分一下,先把update改写成为select语句。数据条数是19条。
select count(*) from sub_errs WHERE sub_appl_id = 3008 AND ENTITY_ID = 8336079 AND MASTER_TRX_ID = 202809364 and error_status = 'PENDING_DEPENDENCY'
and
((depen_ind='S' AND error_status='PENDING_DEPENDENCY')
OR (depen_ind='S' AND error_status='COMPLETED')
OR (depen_ind='S' AND error_status='PURGED')
OR depen_ind='B'
OR depen_ind='N')
这个时候其实约束的验证条件进行校验 error_status和depen_ind这两个字段,因为现有的数据中depen_ind已经是S了,所以数据上没有问题。
然后我们进一步分析。update会把error_status修改为'READY_TO_RECYCLE',这个时候细看过滤条件中,是没有符合的error_status校验的,这个时候depen_ind还是S,就会出问题,
因为这个时候从depen_ind+error_status还是单纯考虑depen_ind都是有问题的,和验证条件是有冲突的。
这个时候因为error_status是READY_TO_RECYCLE',所以第1,2两个条件不会起作用,考虑第3,4个条件,就会发现没有匹配的情况。难怪会抛错。
((depen_ind='S' AND error_status='PENDING_DEPENDENCY')
OR (depen_ind='S' AND error_status='COMPLETED')
OR (depen_ind='S' AND error_status='PURGED')
OR depen_ind='B'
OR depen_ind='N')
明白了这点之后,就提醒同事,脚本应该存在问题,也修改同时修改depen_ind字段的值,需要修改为B或者N,这个由他们来做进一步的确认了。
最后修改后的语句为:
update sub_errs set error_status = 'READY_TO_RECYCLE',depen_ind='N' WHERE sub_appl_id = 3008 AND ENTITY_ID = 8336079 AND MASTER_TRX_ID = 202809364 and error_status = 'PENDING_DEPENDENCY'
这个问题的解决就告一段落了。
这个案例带给我的启示就是看似是约束导致的问题,一般运维人员可能会直接认为是数据问题把问题直接退给开发人员,其实从开发人员的角度来说,去进一步排查这个问题就会显得很困难,不知道该从何开始。
其实问题最后的原因就是语句的修改不够规范和全面导致约束的校验失败,发现这个问题的过程还是需要一些耐心的。
update sub_errs set error_status = 'READY_TO_RECYCLE' WHERE sub_appl_id = 3008 AND ENTITY_ID = 8336079 AND MASTER_TRX_ID = 202809364 and error_status = 'PENDING_DEPENDENCY'
Error report -
SQL Error: ORA-02290: ????????????????????????????? (APPO.SUB_ERRS_1CK)
首先看错误,还真接上小语种了,自己百度翻译了下,是违反约束条件的意思,也是开个玩笑,这个问题可以通过oerr来查看oracle的解释。
02290, 00000, "check constraint (%s.%s) violated"
// *Cause: The values being inserted do not satisfy the named check
// constraint.
// *Action: do not insert values that violate the constraint.
查看user_constraints中的search_condition字段,条件着实复杂,search_condition的条件如下:
(depen_ind='S' AND error_status='PENDING_DEPENDENCY')
OR (depen_ind='S' AND error_status='COMPLETED')
OR (depen_ind='S' AND error_status='PURGED')
OR depen_ind='B'
OR depen_ind='N'
即对于指定的字段 error_status 需要满足上面的这些条件。这个check constraint算是一个比较复杂的约束了。
可能有些人看这个约束就有点晕,到底是希望满足条件还是不满足条件啊。
我们可以类比一下,如果是not null constraint,可能约束就是类似 xxxx is not null的形式,这个时候是希望这个字段不为空的,即满足条件。所以这个问题是希望对 error_status ,满足上面的条件才行。
给同事解释了一通,让他去看看是不是现有环境中存在数据问题,是不是因为数据问题导致条件不满足的。
结果过了一会同事又过来向我确认,说按照那个条件查出的结果和原有的一致的。都是19条数据。
因为表中的数据很多,所以为了尽快复现这个问题,自己采用了exp的query选项导出数据, 这样就会只导出19条数据,数据量就小多了,导入到一个测试环境中,就可以大胆的测试了。
exp xxxxx/xxx file=a.dmp tables=sub_errs query=\" where sub_appl_id = 3008 AND ENTITY_ID = 8336079 \"
导入数据很顺利,19条数据很快就导入了。
imp xxxxx/xxxx file=a.dmp tables= sub_errs indexes=n grants=n ignore=Y constraints=n buffer=9102000
这个时候尝试重现,发现问题依旧。
这个时候我们把问题拆分一下,先把update改写成为select语句。数据条数是19条。
select count(*) from sub_errs WHERE sub_appl_id = 3008 AND ENTITY_ID = 8336079 AND MASTER_TRX_ID = 202809364 and error_status = 'PENDING_DEPENDENCY'
and
((depen_ind='S' AND error_status='PENDING_DEPENDENCY')
OR (depen_ind='S' AND error_status='COMPLETED')
OR (depen_ind='S' AND error_status='PURGED')
OR depen_ind='B'
OR depen_ind='N')
这个时候其实约束的验证条件进行校验 error_status和depen_ind这两个字段,因为现有的数据中depen_ind已经是S了,所以数据上没有问题。
然后我们进一步分析。update会把error_status修改为'READY_TO_RECYCLE',这个时候细看过滤条件中,是没有符合的error_status校验的,这个时候depen_ind还是S,就会出问题,
因为这个时候从depen_ind+error_status还是单纯考虑depen_ind都是有问题的,和验证条件是有冲突的。
这个时候因为error_status是READY_TO_RECYCLE',所以第1,2两个条件不会起作用,考虑第3,4个条件,就会发现没有匹配的情况。难怪会抛错。
((depen_ind='S' AND error_status='PENDING_DEPENDENCY')
OR (depen_ind='S' AND error_status='COMPLETED')
OR (depen_ind='S' AND error_status='PURGED')
OR depen_ind='B'
OR depen_ind='N')
明白了这点之后,就提醒同事,脚本应该存在问题,也修改同时修改depen_ind字段的值,需要修改为B或者N,这个由他们来做进一步的确认了。
最后修改后的语句为:
update sub_errs set error_status = 'READY_TO_RECYCLE',depen_ind='N' WHERE sub_appl_id = 3008 AND ENTITY_ID = 8336079 AND MASTER_TRX_ID = 202809364 and error_status = 'PENDING_DEPENDENCY'
这个问题的解决就告一段落了。
这个案例带给我的启示就是看似是约束导致的问题,一般运维人员可能会直接认为是数据问题把问题直接退给开发人员,其实从开发人员的角度来说,去进一步排查这个问题就会显得很困难,不知道该从何开始。
其实问题最后的原因就是语句的修改不够规范和全面导致约束的校验失败,发现这个问题的过程还是需要一些耐心的。