Given a source table:
create table source_after (
binary_path varchar2(40),
hostname varchar2(40),
change_column varchar2(40),
flag varchar2(20) default 'open'
);
insert all
into source_after (binary_path,hostname,change_column) values ('java','b','DMZ')
into source_after (binary_path,hostname,change_column) values ('apache','c','drn')
into source_after (binary_path,hostname,change_column) values ('NEW','NEW','NEW')
select * from dual;
--------
binary_path hostname flag change_column
java b open DMZ
apache c open drn
NEW NEW open NEW
And a destination table:
create table destination (
binary_path varchar2(40),
hostname varchar2(40),
change_column varchar2(40),
flag varchar2(20)
);
insert all
into destination (binary_path,hostname,change_column) values ('python','a','drn')
into destination (binary_path,hostname,change_column) values ('java','b','drn')
into destination (binary_path,hostname,change_column) values ('apache','c','drn')
into destination (binary_path,hostname,change_column) values ('spark','d','drn')
select * from dual;
------
binary_path hostname change_column flag
python a drn null
java b drn null
apache c drn null
spark d drn null
The primary key of both tables is the combination (binary_path,hostname)
. I want to merge into destination the changes of source_after
.
These should be:
- If the primary key in
destination
is present insource_after
, I want to updatechange_column
indestination
with the value ofsource_after
. - If the primary key in
destination
is not present insource_after
, I want to mark theflag
column asclosed
. - If the primary key in
source_after
is not present indestination
, I want to insert the row present insource_after
which is not present indestination
.
I have tried this:
merge into destination d
using (select * from source_after) s on (d.hostname = s.hostname and d.binary_path = s.binary_path)
when matched then update
set
d.change_column = s.change_column,
d.flag = s.flag
when not matched then insert
(d.binary_path,d.hostname,d.change_column,d.flag)
values
(s.binary_path,s.hostname,s.change_column,s.flag)
;
binary_path hostname change_column flag
python a drn null
java b DMZ open
apache c drn open
spark d drn null
NEW NEW NEW open
It solves problem 1
and 3
, but not problem 2
which is marking the column flag
as closed.
CodePudding user response:
If I understood you correctly, that won't work - not in a single statement.
- If something MATCHES, you can UPDATE it
- If there's NO MATCH, you can INSERT it
- You can't combine NO MATCH with UPDATE, which means that you'll have to write two statements
CodePudding user response:
You can use a FULL OUTER JOIN
in the USING
clause and correlate on the ROWID
pseudo-column for the destination between the USING
clause and the target of the MERGE
:
MERGE INTO destination d
USING (
SELECT d.ROWID AS rid,
s.*
FROM destination d
FULL OUTER JOIN source_after s
ON (d.hostname = s.hostname AND d.binary_path = s.binary_path)
) s
ON (s.rid = d.ROWID)
WHEN MATCHED THEN
UPDATE
SET d.change_column = COALESCE(s.change_column, d.change_column),
d.flag = COALESCE(s.flag, 'closed')
WHEN NOT MATCHED THEN
INSERT (d.binary_path,d.hostname,d.change_column,d.flag)
VALUES (s.binary_path,s.hostname,s.change_column,s.flag);
Which, for the sample data, changes the destination
table to:
BINARY_PATH | HOSTNAME | CHANGE_COLUMN | FLAG |
---|---|---|---|
python | a | drn | closed |
java | b | DMZ | open |
apache | c | drn | open |
spark | d | drn | closed |
NEW | NEW | NEW | open |
CodePudding user response:
merge into destination d
using (
select s.binary_path, s.hostname, s.change_column, s.flag from source_after s
union all
select d.binary_path, d.hostname, d.change_column, 'closed' from destination d
where not exists(select 1 from source_after s where s.binary_path = d.binary_path and s.hostname = d.hostname)
) s
on (d.hostname = s.hostname and d.binary_path = s.binary_path)
when matched then update
set
d.change_column = s.change_column,
d.flag = s.flag
when not matched then insert
(d.binary_path,d.hostname,d.change_column,d.flag)
values
(s.binary_path,s.hostname,s.change_column,s.flag)
;