觸發器進行數據校驗(去重、異常處理)
一、前提
根據地市企業名稱和統一社會信用代碼不一致,以及來源部門和統一社會信用代碼不一致導致的數據錯誤率上升。來如何解決?
下面的流程圖爲大致的解決思路:
二、思路
按照如上的來,觸發器裏面覈驗的寫法可以如下:
如下參數:
(v_count 用來保存查詢後的uscc的值)
(T_CS20201119 企業或部門覈查表,插入的數據根據name去匹配uscc)
create or replace trigger 許可觸發器
before INSERT or UPDATE on t_xzxklqx
referencing OLD AS OLD NEW AS NEW
for each row
declare
v_count varchar2(18);
begin
if inserting then
select uscc into v_count from T_CS20201119 t where name=:new.XK_XZJG;
if (:new.XK_XKJGDM != v_count) then
RAISE_APPLICATION_ERROR(-20000,'部門統一社會信用代碼錯誤');
end if;
end if;
end 許可觸發器;
上述觸發器爲:當插入數據的時候,根據插入的許可機構名稱
去匹配覈驗表
(企業和機構部門表)中的名稱,從而取覈驗表
中的uscc(統一社會信用代碼)。在根據取出來的uscc賦值給v_count 對插入的許可機構的編碼進行匹配,當不匹配的時候,會出錯‘部門統一社會信用代碼錯誤’。
三、重複等問題
但是這時候會出現以下問題:
需要完整且實時更新的企業和部門的核驗表?
覈驗表有重複數據怎麼辦?
當傳輸數據中的企業不存在覈驗表的時候,跳過覈驗(阻止報錯後續說明)?
1A:針對第一個問題,目前只能對接工商的企業信息表和編辦的部門機構統一社會信息代碼表。
2A:針對第二個問題。當有核驗表重複的數據的時候,一個查詢會返回多個結果,進行覈驗的時候會出現多個uscc對應一個的情況從而會報錯。通俗點就是聯誼的時候,不是1對1,而是好幾個對一個,無法相匹配。所以我們可以去重查詢,只查詢覈驗表
最新同步的數據去進行匹配。避免多對一的情況發生。語句修改如下:標紅的爲上面語句的新增項:
select uscc into v_count
from (select row_number() over(partition by NAME order by 時間字段 desc) a,
t.NAME,t.USCC
from T_CS20201119 t
where 1 = 1 )
where a = 1
and name=:new.XK_XZJG;
新增了去重查詢:根據企業名稱進行時間字段倒序排列,取第一個重複企業的企業數據。
3A: 按照回答二的語句來看,解決了重複的數據,但是當我們傳一條覈查表裏面沒有的企業
的數據的時候,會報如下錯誤:
沒有找到任何數據原因來自: 當我們查詢覈查表的時候,如果沒找到的話,會返回無值,並不是返回空值,
。所以會導致未找到任何數據。
在思考之後,只增加了一個用法,如下:
select min(uscc)
into v_count
from (select row_number() over(partition by NAME order by 時間字段 desc) a, t.NAME,t.USCC
from T_CS20201119 t
where 1 = 1 )
where a = 1 and name=:new.XK_XZJG;
我在uscc增加了min(),不能查詢到企業的時候,只返回空值,從而跳過了‘未找到任何數據’
這個錯誤。
且經過多次測試,沒有任何異常
測試方法:一共三個測試用例:
測試用例 | 情況 | 結果 |
---|---|---|
NAME:安徽省臨泉縣發展改革委 USCC: 11341221003171913L |
符合 企業(部門)覈查表的NAME和USCC | 可以正常導入 |
NAME:安徽省臨泉縣發展改革委 USCC: 1134122100317 |
NAME能匹配上企業(部門)覈查表,但是USCC不匹配 | 導入失敗,報錯信息爲:ORA-20000: 部門統一社會信用代碼錯誤 正常的導入失敗報錯信息 |
NAME:安徽省臨泉縣發展改革委123 USCC: 11341221003171913L |
NAME能不匹配上企業(部門)覈查表。 | 可以正常導入,當傳輸數據中的企業不存在覈驗表的時候,跳過覈驗 |
所以整合上訴的要求,該判斷語句如下:
select min(uscc) into v_count
from (select row_number() over(partition by NAME order by 時間字段 desc) a, t.NAME,t.USCC from T_CS20201119 t where 1 = 1 )
where a = 1 and name=:new.XK_XZJG;
if (:new.XK_XKJGDM != v_count) then
RAISE_APPLICATION_ERROR(-20000,'部門統一社會信用代碼錯誤');
end if;
填報我測試多次都毫無問題。
四、其餘方法與思考
但是這個我難以自說其圓,原因是,當部門無法在覈查表中查詢的時候,返回的值是空值。但是按照下一步 if(:new.XK_XKJGDM != v_count)這個來看,:new.XK_XKJGDM是肯定不等於空值的,肯定會報錯誤信息,但是實際上。並沒有出錯,才疏學淺,不知道怎麼回事,我百度也無結果。但我個人覺得不嚴謹,有知道原理的可以告知我。
所以語句我經過了更改如下:標紅爲更改處
select nvl
(min(uscc),0
) into v_count
from (select row_number() over(partition by NAME order by 時間字段 desc) a, t.NAME,t.USCC from T_CS20201119 t where 1 = 1 ) where a = 1 and name=:new.XK_XZJG;
if(v_count!=0) then
if (:new.XK_XKJGDM != v_count) then
RAISE_APPLICATION_ERROR(-20000,'部門統一社會信用代碼錯誤');
end if;
end if;
函數NVL的語法爲:NVL(eExpression1, eExpression2) ,如果 eExpression1 的計算結果爲 null 值,則 NVL( ) 返回 eExpression2。如果 eExpression1 的計算結果不是 null 值,則返回 eExpression1。
但是還得加上min() ,因爲不加上min()的話,就像這樣:nvl(uscc,0),企業不存在覈查表的時候,返回的無值,而不是空值,查詢結果沒辦法替換成0,會報錯‘未找到任何數據’。
當爲空值的時候,賦予v_count =0
,不做任何判斷,當v_count不等於0的時候
,則就判斷上傳數據的企業(部門)編碼是否與覈查表一致。不一致則會報錯提醒。
另外還有一種方法,no_data_found異常處理,和min的結果一樣,獲取到null值,直接跳過判斷:語句如下,修改處標紅:
begin
select uscc
into v_count
from (select row_number() over(partition by NAME order by sj desc) a, t.NAME,t.USCC from T_CS20201119 t where 1 = 1 ) where a = 1 and name=:new.XK_XZJG;
exception
when NO_DATA_FOUND then
v_count := null;
end;
if (:new.XK_XKJGDM != v_count) then
RAISE_APPLICATION_ERROR(-20000,'部門統一社會信用代碼錯誤');
end if;
去掉了min(),當語句查詢的時候,覈查表中沒有該企業的時候,會查出無值,正常情況下會報錯‘未找到任何數據’
。但是這時候用no_data_found異常處理。給他賦予爲null的值,從而跳過覈驗。只要報了NO_DATA_FOUND異常,都會立即stop,要麼跳轉到exception,要麼返回null,不再繼續執行。
方法應該還有很多。
目的就是如何覈驗企業名稱和統一社會信用代碼是否和正確的核驗表是否一致,用來保證數據質量。
重要的是我不知道就是爲什麼賦值爲空值和null的時候,會跳過後續的判斷,我個人理解要判斷,也許可能我陷入到判斷的固定思維。