天天看點

無法運作的update問題解析

今天有個同僚向我回報一個問題,說是客戶在部署他們提供的一個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='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字段的值,需要修改為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' 

這個問題的解決就告一段落了。

這個案例帶給我的啟示就是看似是限制導緻的問題,一般運維人員可能會直接認為是資料問題把問題直接退給開發人員,其實從開發人員的角度來說,去進一步排查這個問題就會顯得很困難,不知道該從何開始。

其實問題最後的原因就是語句的修改不夠規範和全面導緻限制的校驗失敗,發現這個問題的過程還是需要一些耐心的。