Oracle存储过程:判断表数据是否存在于另一表及代码问题排查
问题分析与修复方案
方法1的问题与修正
原代码存在3个关键错误:
- 子查询
select * from (select * from T1 order by c) where rownum=1返回整行数据,但c=(...)是用单列c和整行做比较,类型不匹配,应只提取c列 insert语句末尾缺少分号,PL/SQL要求每条语句必须以分号结尾- 多层子查询可以简化,提升可读性
修正后的代码:
create or replace procedure proc1 As v_t1_c T1.c%type; Begin -- 获取T1按c排序后的第一条数据的c值 select c into v_t1_c from T1 order by c fetch first 1 row only; if not exists(select 1 from T2 where c = v_t1_c) then -- 插入T1中对应的数据到T2 insert into T2 select * from T1 order by c fetch first 1 row only; end if; End; /
注:fetch first 1 row only是Oracle 12c+的语法,低版本可替换为where rownum=1,但要保证子查询只取目标列。
方法2的问题与修正
原代码的核心问题:
declare位置错误,PL/SQL中变量声明必须放在As和Begin之间,不能在Begin之后select count(*) into var语句末尾缺分号,且group by c会让查询返回多行结果,单个变量var无法接收,会触发"单行子查询返回多行"错误- 用
intersect结合count判断存在性的逻辑不合理
若需求是判断T1首行数据是否存在于T2,不存在则插入,修正后的代码:
create or replace procedure proc1 As var integer; Begin -- 统计T1首行数据在T2中的存在次数 select count(*) into var from T2 where c = (select c from T1 order by c fetch first 1 row only); if var = 0 then insert into T2 select * from T1 order by c fetch first 1 row only; end if; End; /
更简洁的替代方案
无需存储过程,用merge语句可一步完成逻辑,效率更高:
merge into T2 using (select * from T1 order by c fetch first 1 row only) t1_data on (T2.c = t1_data.c) when not matched then insert values t1_data;
内容的提问来源于stack exchange,提问作者Bahy Mohamed
相关产品推荐
相关产品推荐

