Hello Tom,
I have 2 tables Source and Target, I want Target table to be in sync with Source as and when query runs.
Following is the columns structure of both of the tables. I want all columns except (Contact_no) have to be in sync in Target table.
CREATE TABLE T_SOURCE (ID NUMBER(5) , Part_no VARCHAR2(10), Country_Code VARCHAR2(2), Contact_no NUMBER(10));
INSERT INTO T_SOURCE VALUES (1, 'AB123', 'IN',2512121212);
INSERT INTO T_SOURCE VALUES (2, 'AD345', 'US',2518571122);
INSERT INTO T_SOURCE VALUES (3, 'RT123', 'CH',2512121212);
INSERT INTO T_SOURCE VALUES (4, 'UY123', 'EN',2587452548);
Source Table
================================================
Unique_ID Part_no Country_Code Contact_no
1 AB123 IN 2512121212
2 AD345 US 2518571122
3 RT123 CH 2512121212
4 UY123 EN 2587452548
CREATE TABLE T_TARGET (ID NUMBER(5) , Part_no VARCHAR2(10), Country_Code VARCHAR2(2), Action CHAR(1));
Initially i will copy 3 columns data into Target table with Action = "I".
INSERT INTO T_TARGET SELECT ID,Part_no,Country_Code,'I' FROM T_SOURCE;
Target Table
===============================================
Unique_ID Part_no Country_Code Action
1 AB123 IN I
2 AD345 US I
3 RT123 CH I
4 UY123 EN I
Now as and when SQL runs it will update, insert or delete Target table as per Source table with Action flag.
Next Day Source Table changed
================================================
Unique_ID Part_no Country_Code Contact_no
1 AB123 US 2512121212 -- Updated Country_Code as "US"
2 AD345 US 2518571122 -- No Change
3 RT123 CH 2512121212 -- Deleted from Source
4 UY123 EN 2587452548 -- No Change
5 APD25 DL 1111111111 -- New Inserted
Target Table
===============================================
Unique_ID Part_no Country_Code Action
1 AB123 US U
2 AD345 US I
3 RT123 CH D -- Deleted from Source
4 UY123 EN I
5 APD25 DL I -- Newly Inserted
I have written below Merge statement but its not working properly, after initial insert with Action flag "I" when i execute, it is updating all the records with action flag as "U"
MERGE INTO Target d2
USING (SELECT Unique_id, Part_no, Country_code
FROM Source
UNION ALL
SELECT a.Unique_id, a.Part_no, a.Country_code
FROM Target a LEFT JOIN Source b ON a.Unique_id=b.Unique_id
WHERE b.Unique_id IS NULL
) d
ON (d2.Unique_id=d.Unique_id)
WHEN NOT MATCHED THEN
INSERT(Unique_id, Part_no, Country_code, Action)
VALUES(d.Unique_id, d.Part_no, d.Country_code, 'I')
WHEN MATCHED THEN
UPDATE SET d2.Action = 'U', d2.Country_code = d.Country_code;
-- DELETE WHERE d2.loc='DELETE ME';
Kindly help me on this.
If you run merge twice with the same source data, the first pass will load any missing rows. And on the second execution all the rows in the source are in the target. So you'll update all the rows!
To avoid this, remove rows from the source already in the target with MINUS or NOT EXISTS.
While you're at it, to identify the deleted rows change the outer join to return columns from the source.
So your source query would be something along the lines of:
(
SELECT id, Part_no, Country_code
FROM T_SOURCE
MINUS
SELECT id, Part_no, Country_code
FROM T_TARGET
)
UNION ALL
SELECT a.id, b.Part_no, b.Country_code
FROM T_TARGET a
LEFT JOIN T_SOURCE b
ON a.id=b.id
WHERE b.id IS NULL
Then in the MATCHED clause you can check if source.part_no is null to delete or flag it as needed:
CREATE TABLE T_SOURCE (
ID NUMBER(5) , Part_no VARCHAR2(10),
Country_Code VARCHAR2(2), Contact_no NUMBER(10)
);
CREATE TABLE T_TARGET (
ID NUMBER(5) , Part_no VARCHAR2(10),
Country_Code VARCHAR2(2), Action CHAR(1)
);
INSERT INTO T_SOURCE VALUES (1, 'AB123', 'IN',2512121212);
INSERT INTO T_SOURCE VALUES (2, 'AD345', 'US',2518571122);
INSERT INTO T_SOURCE VALUES (3, 'RT123', 'CH',2512121212);
INSERT INTO T_SOURCE VALUES (4, 'UY123', 'EN',2587452548);
INSERT INTO T_TARGET SELECT ID,Part_no,Country_Code,'I' FROM T_SOURCE;
commit;
delete t_source;
INSERT INTO T_SOURCE VALUES (1, 'AB123', 'US',2512121212);
INSERT INTO T_SOURCE VALUES (2, 'AD345', 'US',2518571122);
INSERT INTO T_SOURCE VALUES (4, 'UY123', 'EN',2587452548);
INSERT INTO T_SOURCE VALUES (5, 'UY123', 'EN',1111111111);
commit;
MERGE INTO T_TARGET d2
USING ((
SELECT id, Part_no, Country_code
FROM T_SOURCE
MINUS
SELECT id, Part_no, Country_code
FROM T_TARGET
)
UNION ALL
SELECT a.id, b.Part_no, b.Country_code
FROM T_TARGET a
LEFT JOIN T_SOURCE b
ON a.id=b.id
WHERE b.id IS NULL
) d
ON (d2.id=d.id)
WHEN NOT MATCHED THEN
INSERT(id, Part_no, Country_code, Action)
VALUES(d.id, d.Part_no, d.Country_code, 'I')
WHEN MATCHED THEN
UPDATE SET d2.Action = 'U', d2.Country_code = d.Country_code
DELETE WHERE d.part_no is null;
select * from T_TARGET;
ID PART_NO COUNTRY_CODE ACTION
1 AB123 US U
2 AD345 US I
4 UY123 EN I
5 UY123 EN I
rollback;
MERGE INTO T_TARGET d2
USING ((
SELECT id, Part_no, Country_code
FROM T_SOURCE
MINUS
SELECT id, Part_no, Country_code
FROM T_TARGET
)
UNION ALL
SELECT a.id, b.Part_no, b.Country_code
FROM T_TARGET a
LEFT JOIN T_SOURCE b
ON a.id=b.id
WHERE b.id IS NULL
) d
ON (d2.id=d.id)
WHEN NOT MATCHED THEN
INSERT(id, Part_no, Country_code, Action)
VALUES(d.id, d.Part_no, d.Country_code, 'I')
WHEN MATCHED THEN
UPDATE SET
d2.Action = case
when d.part_no is not null then 'U'
else 'D'
end,
d2.Country_code = case
when d.part_no is not null then d.Country_code
else d2.Country_code
end;
select * from T_TARGET;
ID PART_NO COUNTRY_CODE ACTION
1 AB123 US U
2 AD345 US I
3 RT123 CH D
4 UY123 EN I
5 UY123 EN I