问题
在工作中偶尔会遇到这样的问题:SQL script重复执行时会报错。
理想的状态下,SQL script跑一遍就够了,是不会重复执行的,但是实际情况往往很复杂。
比如Dev同学在开发时在A环境把他写的那个脚本单独执行了一遍,而在下一个测试周期的时候,测试同学又在A环境把所有DB脚本都执行了一遍,然后就报错了。
如下示例,这里错误的原因在于重复创建表。
例1
create table tableA (col1 char(10), col2 number);
SQL Error: ORA-00955: name is already used by an existing object
再举一个例子,反复执行插入语句虽然可能不会报错(如果没有constraint的话),但是却造成了数据冗余,甚至会影响Data Quality。
例2
insert into tableA values ('ItemA', 10);
原因
这个问题有两个方面的原因:
- 执行DB脚本的人在不同的的开发周期中往往不是同一个人,且缺乏各个脚本在不同环境的执行记录。
- DB脚本本身不可(适合)重复执行。
解决方案
解决的方案也有两个方面:
一是,规定Dev一般只在开发环境做测试,如果在其他环境跑了脚本要及时Roll Back。另外,创建一张表,用来记录各个DB脚本在不同环境的执行记录:时间戳,执行人员,成功或失败。
二是,写可重复执行的DB Script。比如上面的两个例子可以改成:
例子1-1
declare
isexists number;
begin
select count(*) into isexists from all_tables where table_name='tableA' and owner = 'sysA';
if isexists = 1 then
execute immediate 'drop table "sysA"."tableA" purge';
end if;
execute immediate 'create table tableA (col1 char(10), col2 number)';
end;
例子2-1
declare
countNum number;
begin
select count(*) into countNum from tableA where col1 = 'ItemA';
if countNum > 0 then
delete from tableA where col1 = 'ItemA';
insert into tableA values ('ItemA', 20);
end if;
commit;
end;
总的来说,在写DDL或者DML的时候,多一个心思,考虑一下这段代码可否被重复执行,然后根据需要多加一些判断条件,即可以使程序的鲁棒性更好。