具有多个条件的SQL合并语句

时间:2017-04-26 17:14:50

标签: sql plsql merge conditional-statements

我要求在SQL上实现一些业务规则(在PL / SQL块中):我需要评估这些规则并根据结果执行相应的更新,删除或插入目标表。

我的数据库模型包含" staging"和一个真实的"表。真实的表存储过去插入的记录,而暂存的记录包含" fresh"来自某个地方的数据需要合并到真实数据中。

基本上这些是我的商业规则:

  1. 登台 MINUS 真实之间的差异 - > 行插入真实的
  2. 真实之间的差异 MINUS 登台 - > 从真实
  3. 删除
  4. PK是相同但其他任何字段不同的行:更新
  5. (那些" MINUS "将比较所有字段以获得相等并区分第三种情况)

    我还没有想出通过使用合并声明来完成这些任务而不会在规则之间重叠的方法:对合并结构的任何建议?是否可以在同一个合并中一起完成所有这些?

    谢谢!

1 个答案:

答案 0 :(得分:0)

如果我理解你的任务正确遵循代码应该做的工作:

--drop table real;
--drop table stag;

create table real (
  id NUMBER,
  col1 NUMBER,
  col2 VARCHAR(10)
);

create table stag (
  id NUMBER,
  col1 NUMBER,
  col2 VARCHAR(10)
);

insert into real values (1, 1, 'a');
insert into real values (2, 2, 'b');
insert into real values (3, 3, 'c');
insert into real values (4, 4, 'd');
insert into real values (5, 5, 'e');
insert into real values (6, 6, 'f');
insert into real values (7, 6, 'g'); -- PK the same but at least one column different
insert into real values (8, 7, 'h'); -- PK the same but at least one column different
insert into real values (9, 9, 'i');
insert into real values (10, 10, 'j'); -- in real but not in stag

insert into stag values (1, 1, 'a');
insert into stag values (2, 2, 'b');
insert into stag values (3, 3, 'c');
insert into stag values (4, 4, 'd');
insert into stag values (5, 5, 'e');
insert into stag values (6, 6, 'f');
insert into stag values (7, 7, 'g'); -- PK the same but at least one column different
insert into stag values (8, 8, 'g'); -- PK the same but at least one column different
insert into stag values (9, 9, 'i');
insert into stag values (11, 11, 'k'); -- in stag but not in real

merge into real
     using (WITH w_to_change AS (
              select *
                from (select stag.*, 'I' as action from stag
                       minus
                      select real.*, 'I' as action from real
                     )
               union (select real.*, 'D' as action from real
                       minus 
                      select stag.*, 'D' as action from stag
                     )
            )
            , w_group AS (
              select id, max(action) as max_action
                from w_to_change
               group by id
            )
            select w_to_change.*
              from w_to_change
              join w_group
                on w_to_change.id = w_group.id
               and w_to_change.action = w_group.max_action
           ) tmp
   on (real.id = tmp.id)
 when matched then
   update set real.col1 = tmp.col1, real.col2 = tmp.col2
   delete where tmp.action = 'D'
 when not matched then
   insert (id, col1, col2) values (tmp.id, tmp.col1, tmp.col2);