简体   繁体   English

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

[英]SQL merge statement with multiple conditions

I have a requirement with some business rules to implement on SQL (within a PL/SQL block): I need to evaluate such rules and according to the result perform the corresponding update, delete or insert into a target table. 我有一些要在SQL上(在PL / SQL块内)实现的业务规则的要求:我需要评估这些规则,并根据结果执行相应的更新,删除或插入目标表。

My database model contains a "staging" and a "real" table. 我的数据库模型包含一个“ staging”和一个“ real”表。 The real table stores records inserted in the past and the staging one contains "fresh" data coming from somewhere that needs to be merged into the real one. 真实表存储了过去插入的记录,而暂存表包含需要合并到真实表中的某处的“新”数据。

Basically these are my business rules: 基本上,这些是我的业务规则:

  1. Delta between staging MINUS real --> Insert rows into the real 分期 在没有 真实之间三角洲- >行插入到现实
  2. Delta between real MINUS staging --> Delete rows from the real 实际 减号 分段之间的增量->从真实 减号中 删除
  3. Rows which PK is the same but any other fields different: Update . PK相同但其他字段不同的行: Update

(Those " MINUS " will compare ALL the fields to get equality and distinguise the 3rd case) (那些“ MINUS ”将比较所有字段以获得相等性并区分第三种情况)

I haven't figured out the way to accomplish such tasks without overlapping between rules by using a merge statement: Any suggestion for the merge structure? 我还没有想出通过使用merge语句在规则之间没有重叠的情况下完成这些任务的方法:对合并结构有任何建议吗? Is it possible to do it all together within the same merge? 是否可以在同一合并中一起完成所有操作?

Thank you! 谢谢!

If I understand you task correctly following code should do the job: 如果我正确理解您的任务,则应使用以下代码来完成任务:

--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);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM