Y W Chin
asked on
ORACLE Merge SQL Logging
Hi Expert,
I have following stored procedure using merge SQL.
I am trying to find a way to log which record have been inserted or updated by the merge SQL.
May I know is there a way to achieve this?
CREATE OR REPLACE PROCEDURE PRC_001_CD IS
BEGIN
MERGE INTO tmp_cd_01 D USING (select * from tmp_cd_02) S
ON (D.i_id = S.i_id AND D.e_id = S.c_no)
WHEN MATCHED THEN
UPDATE SET
D.c_date = D.c_date
WHERE S.d_ind = 1
DELETE
WHERE S.d_ind = 1
WHEN NOT MATCHED THEN
INSERT (i_id, e_id, e_date, l_code, c_date)
VALUES
(
S.i_id,
S.c_no,
S.e_date,
S.l_code,
S.c_date
)
where S.d_ind = 0;
COMMIT;
END;
I have following stored procedure using merge SQL.
I am trying to find a way to log which record have been inserted or updated by the merge SQL.
May I know is there a way to achieve this?
CREATE OR REPLACE PROCEDURE PRC_001_CD IS
BEGIN
MERGE INTO tmp_cd_01 D USING (select * from tmp_cd_02) S
ON (D.i_id = S.i_id AND D.e_id = S.c_no)
WHEN MATCHED THEN
UPDATE SET
D.c_date = D.c_date
WHERE S.d_ind = 1
DELETE
WHERE S.d_ind = 1
WHEN NOT MATCHED THEN
INSERT (i_id, e_id, e_date, l_code, c_date)
VALUES
(
S.i_id,
S.c_no,
S.e_date,
S.l_code,
S.c_date
)
where S.d_ind = 0;
COMMIT;
END;
you could also create a materialized_view_log on table tmp_cd_01
and changes will be recorded into that mvl
and changes will be recorded into that mvl
I agree with Geert that usually you should not put a commit inside a procedure. Usually it is best to allow the calling program to control commits.
I don't know of a way in a merge statement to log how many records get inserted compared to how many get updated. One option would be to write a separate function that you call first. This function would need a cursor with a "where" clause like the "on" clause in your merge. This function could return a "U" if the query finds a matching row, and an "I" when it doesn't.
I have three concerns with your merge statement:
1. This won't change anything: "UPDATE SET
D.c_date = D.c_date"
Maybe that should be: "UPDATE SET
D.c_date = S.c_date"?
2. The first "WHERE S.d_ind = 1"
should maybe be: "WHERE D.d_ind = 1"
3. You cannot delete from the source table like this: "DELETE
WHERE S.d_ind = 1"
According to the Oracle12 documentation: (https://docs.oracle.com/database/121/SQLRF/statements_9017.htm#SQLRF01606)
"Specify the DELETE where_clause to clean up data in a table while populating or updating it. The only rows affected by this clause are those rows in the destination table that are updated by the merge operation."
I don't know of a way in a merge statement to log how many records get inserted compared to how many get updated. One option would be to write a separate function that you call first. This function would need a cursor with a "where" clause like the "on" clause in your merge. This function could return a "U" if the query finds a matching row, and an "I" when it doesn't.
I have three concerns with your merge statement:
1. This won't change anything: "UPDATE SET
D.c_date = D.c_date"
Maybe that should be: "UPDATE SET
D.c_date = S.c_date"?
2. The first "WHERE S.d_ind = 1"
should maybe be: "WHERE D.d_ind = 1"
3. You cannot delete from the source table like this: "DELETE
WHERE S.d_ind = 1"
According to the Oracle12 documentation: (https://docs.oracle.com/database/121/SQLRF/statements_9017.htm#SQLRF01606)
"Specify the DELETE where_clause to clean up data in a table while populating or updating it. The only rows affected by this clause are those rows in the destination table that are updated by the merge operation."
1. Use after update/insert/delete trigger on that table, if you want to log
2. Do not use Commit
3. If PL/SQL then can use if then else and insert entry in your log table
2. Do not use Commit
3. If PL/SQL then can use if then else and insert entry in your log table
I assumed you want to know changed record in target table, not source table. So;
You can add two column on target table named as INSERT_DATE, UPDATE_DATE
In insert part of merge statement use SYSDATE as insert_date
In update part of merge statement Set update_date as SYSDATE
Something like this
You can add two column on target table named as INSERT_DATE, UPDATE_DATE
In insert part of merge statement use SYSDATE as insert_date
In update part of merge statement Set update_date as SYSDATE
Something like this
MERGE INTO tmp_cd_01 d
USING (SELECT * FROM tmp_cd_02) s
ON (d.i_id = s.i_id AND d.e_id = s.c_no)
WHEN MATCHED THEN
UPDATE SET d.c_date = d.c_date, d.update_date = SYSDATE
WHERE s.d_ind = 1
DELETE
WHERE s.d_ind = 1
WHEN NOT MATCHED THEN
INSERT (i_id
, e_id
, e_date
, l_code
, c_date
, insert_date)
VALUES (s.i_id
, s.c_no
, s.e_date
, s.l_code
, s.c_date
, SYSDATE)
WHERE s.d_ind = 0;
This question needs an answer!
Become an EE member today
7 DAY FREE TRIALMembers can start a 7-Day Free trial then enjoy unlimited access to the platform.
View membership options
or
Learn why we charge membership fees
We get it - no one likes a content blocker. Take one extra minute and find out why we block content.
don't put a commit in the procedure ...
use a trigger on the changed table tmp_cd_01 to post a record in a log table