-
Notifications
You must be signed in to change notification settings - Fork 18
/
Copy pathmerge_counter.sql
171 lines (143 loc) · 5.69 KB
/
merge_counter.sql
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
-- ----------------------------------------------------------------------------------------------
--
-- Script: merge_counter.sql
--
-- Author: Adrian Billington
-- www.oracle-developer.net
--
-- Description: A package to maintain separate INSERT and UPDATE counts from a MERGE.
--
-- I first devised this method for an article for Quest's PL/SQL Pipelines. This
-- article can be found on the oracle-developer.net website at
-- www.oracle-developer.net/display.php?id=220.
--
-- This utility will work for all versions of 9i and above (i.e. when MERGE was
-- introduced).
--
-- A current limitation is that it does not support parallel MERGE. I'm waiting for
-- a documented feature of Oracle 10g to start working so I can put a parallel-
-- enabled version together.
--
-- Usage: Usage is quite simple. We maintain an insert counter, update counter or both.
-- For efficiency, it makes sense to maintain a single counter on the operation that
-- is LEAST likely to occur. For example, if a MERGE is likely to UPDATE 200,000
-- records and INSERT just 5,000, then it makes sense to maintain an insert counter
-- only.
--
-- a) To maintain an insert counter
-- -----------------------------
--
-- MERGE
-- INTO target_table t
-- USING source_table s
-- ON (s.primary_key = t.primary_key)
-- WHEN MATCHED THEN
-- UPDATE
-- SET t.column_name = s.column_name
-- WHEN NOT MATCHED THEN
-- INSERT ( t.primary_key
-- , t.column_name )
-- VALUES ( DECODE(merge_counter.insert_counter,0,s.primary_key)
-- , s.column_name );
--
-- b) To maintain an update counter
-- -----------------------------
--
-- MERGE
-- INTO target_table t
-- USING source_table s
-- ON (s.primary_key = t.primary_key)
-- WHEN MATCHED THEN
-- UPDATE
-- SET t.column_name = DECODE(merge_counter.update_counter,0,s.column_name)
-- WHEN NOT MATCHED THEN
-- INSERT ( t.primary_key
-- , t.column_name )
-- VALUES ( s.primary_key
-- , s.column_name );
--
-- c) Reporting insert and update rowcounts
-- -------------------------------------
--
-- INSERT
-- => if insert counter used, merge_counter.get_insert_count
-- => if update counter used, merge_counter.get_insert_count(sql%rowcount)
--
-- UPDATE
-- => if update counter used, merge_counter.get_update_count
-- => if insert counter used, merge_counter.get_update_count(sql%rowcount)
--
-- To reset the counters, use merge_counter.reset_counters.
--
-- ----------------------------------------------------------------------------------------------
CREATE PACKAGE merge_counter AS
FUNCTION insert_counter
RETURN PLS_INTEGER;
FUNCTION update_counter
RETURN PLS_INTEGER;
FUNCTION get_update_count
RETURN PLS_INTEGER;
FUNCTION get_update_count (
merge_rowcount_in IN PLS_INTEGER
) RETURN PLS_INTEGER;
FUNCTION get_insert_count
RETURN PLS_INTEGER;
FUNCTION get_insert_count (
merge_rowcount_in in PLS_INTEGER
) RETURN PLS_INTEGER;
PROCEDURE reset_counters;
END merge_counter;
/
CREATE PACKAGE BODY merge_counter AS
g_update_counter PLS_INTEGER NOT NULL := 0;
g_insert_counter PLS_INTEGER NOT NULL := 0;
-------------------------------------------------------------------------
FUNCTION insert_counter
RETURN PLS_INTEGER IS
BEGIN
g_insert_counter := g_insert_counter + 1;
RETURN 0;
END insert_counter;
-------------------------------------------------------------------------
FUNCTION update_counter
RETURN PLS_INTEGER IS
BEGIN
g_update_counter := g_update_counter + 1;
RETURN 0;
END update_counter;
-------------------------------------------------------------------------
FUNCTION get_update_count
RETURN PLS_INTEGER is
BEGIN
RETURN g_update_counter;
END get_update_count;
-------------------------------------------------------------------------
FUNCTION get_update_count (
merge_rowcount_in IN PLS_INTEGER
) RETURN PLS_INTEGER IS
BEGIN
RETURN NVL( merge_rowcount_in - g_insert_counter, 0 );
END get_update_count;
-------------------------------------------------------------------------
FUNCTION get_insert_count
RETURN PLS_INTEGER IS
BEGIN
RETURN g_insert_counter;
END get_insert_count;
-------------------------------------------------------------------------
FUNCTION get_insert_count (
merge_rowcount_in IN PLS_INTEGER
) RETURN PLS_INTEGER IS
BEGIN
RETURN NVL( merge_rowcount_in - g_update_counter, 0 );
END get_insert_count;
-------------------------------------------------------------------------
PROCEDURE reset_counters IS
BEGIN
g_update_counter := 0;
g_insert_counter := 0;
END reset_counters;
END merge_counter;
/
CREATE OR REPLACE PUBLIC SYNONYM merge_counter FOR merge_counter;
GRANT EXECUTE ON merge_counter TO PUBLIC;