触发器进行数据校验(去重、异常处理)
一、前提
根据地市企业名称和统一社会信用代码不一致,以及来源部门和统一社会信用代码不一致导致的数据错误率上升。来如何解决?
下面的流程图为大致的解决思路:
二、思路
按照如上的来,触发器里面核验的写法可以如下:
如下参数:
(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的时候,会跳过后续的判断,我个人理解要判断,也许可能我陷入到判断的固定思维。