@@ -186,7 +186,19 @@ create or replace package body ut_compound_data_helper is
186186
187187 return l_results;
188188 end;
189-
189+
190+ function get_pk_value (a_join_by_xpath varchar2,a_item_data xmltype) return varchar2 is
191+ l_pk_value varchar2(4000);
192+ begin
193+ select listagg(extractvalue(xmlelement("ROW",column_value),a_join_by_xpath),':') within group ( order by 1)
194+ into l_pk_value
195+ from table(xmlsequence(extract(a_item_data,'/*/*')));
196+
197+ return l_pk_value;
198+ exception when no_data_found then
199+ return 'null ';
200+ end;
201+
190202 function get_rows_diff(
191203 a_expected_dataset_guid raw, a_actual_dataset_guid raw, a_diff_id raw,
192204 a_max_rows integer, a_exclude_xpath varchar2, a_include_xpath varchar2,
@@ -195,36 +207,38 @@ create or replace package body ut_compound_data_helper is
195207 l_column_filter varchar2(32767);
196208 l_results tt_row_diffs;
197209 begin
198- l_column_filter := get_columns_filter (a_exclude_xpath,a_include_xpath);
210+ l_column_filter := get_columns_row_filter (a_exclude_xpath,a_include_xpath);
199211
200212 /**
201213 * Since its unordered search we cannot select max rows from diffs as we miss some comparision records
202214 * We will restrict output on higher level of select
215+ * NO_MERGE hint was introduced to prevent optimizer from merging views and rewriting query which in some cases
216+ * lead to second value being null depend on execution plan that been chosen
203217 **/
204-
205218 execute immediate q'[
206- with diff_info as (select item_hash,pk_hash,pk_value from ut_compound_data_diff_tmp ucdc where diff_id = :diff_guid)
219+ with diff_info as (select item_hash,pk_hash,duplicate_no from ut_compound_data_diff_tmp ucdc where diff_id = :diff_guid)
207220 select rn,diff_type,diffed_row,pk_value from
208221 (
209222 select diff_type,diffed_row, dense_rank() over (order by pk_hash) rn,pk_value from
210223 (
211224 select diff_type,diffed_row,pk_hash,pk_value from
212225 (select diff_type,data_item diffed_row,pk_hash,pk_value
213226 from
214- (select nvl(exp.pk_hash, act.pk_hash) pk_hash,nvl(exp.pk_value, act.pk_value) pk_value,
227+ (select /*+NO_MERGE*/ nvl(exp.pk_hash, act.pk_hash) pk_hash,nvl(exp.pk_value, act.pk_value) pk_value,
215228 xmlserialize(content exp.row_data no indent) exp_item,
216229 xmlserialize(content act.row_data no indent) act_item
217230 from
218- (select ucd.*, row_number() over(partition by pk_hash order by row_hash) duplicate_no
231+ (select ucd.*
219232 from
220233 (select ucd.column_value row_data,
221234 r.item_hash row_hash,
222235 r.pk_hash ,
223- r.pk_value,
236+ r.duplicate_no,
237+ ucd.column_value.getclobval() col_val,
224238 ucd.column_value.getRootElement() col_name,
225- ucd.column_value.getclobval() col_val
239+ ut_compound_data_helper.get_pk_value(:join_xpath,r.item_data) pk_value
226240 from
227- (select ]'||l_column_filter||q'[, ucd.item_no, ucd.item_hash, i.pk_hash, i.pk_value
241+ (select ]'||l_column_filter||q'[, ucd.item_no, ucd.item_hash, i.pk_hash, i.duplicate_no
228242 from ut_compound_data_tmp ucd,
229243 diff_info i
230244 where ucd.data_id = :self_guid
@@ -234,16 +248,17 @@ create or replace package body ut_compound_data_helper is
234248 ) ucd
235249 ) exp
236250 join (
237- select ucd.*, row_number() over(partition by pk_hash order by row_hash) duplicate_no
251+ select ucd.*
238252 from
239253 (select ucd.column_value row_data,
240254 r.item_hash row_hash,
241255 r.pk_hash ,
242- r.pk_value,
256+ r.duplicate_no,
257+ ucd.column_value.getclobval() col_val,
243258 ucd.column_value.getRootElement() col_name,
244- ucd.column_value.getclobval() col_val
259+ ut_compound_data_helper.get_pk_value(:join_xpath,r.item_data) pk_value
245260 from
246- (select ]'||l_column_filter||q'[, ucd.item_no, ucd.item_hash, i.pk_hash, i.pk_value
261+ (select ]'||l_column_filter||q'[, ucd.item_no, ucd.item_hash, i.pk_hash, i.duplicate_no
247262 from ut_compound_data_tmp ucd,
248263 diff_info i
249264 where ucd.data_id = :other_guid
@@ -252,7 +267,8 @@ create or replace package body ut_compound_data_helper is
252267 table( xmlsequence( extract(r.item_data,'/*/*') ) ) ucd
253268 ) ucd
254269 ) act
255- on exp.pk_hash = act.pk_hash and exp.duplicate_no = act.duplicate_no
270+ on exp.pk_hash = act.pk_hash and exp.col_name = act.col_name
271+ and exp.duplicate_no = act.duplicate_no
256272 where dbms_lob.compare(exp.col_val, act.col_val) != 0
257273 )
258274 unpivot ( data_item for diff_type in (exp_item as 'Expected:', act_item as 'Actual:') )
@@ -261,15 +277,17 @@ create or replace package body ut_compound_data_helper is
261277 select case when exp.pk_hash is null then 'Extra:' else 'Missing:' end as diff_type,
262278 xmlserialize(content nvl(exp.item_data, act.item_data) no indent) diffed_row,
263279 coalesce(exp.pk_hash,act.pk_hash) pk_hash,
264- null pk_value
265- from (select extract(ucd.item_data,'/*/*') item_data,i.pk_hash
280+ coalesce(exp.pk_value,act.pk_value) pk_value
281+ from (select extract(ucd.item_data,'/*/*') item_data,i.pk_hash,
282+ ut_compound_data_helper.get_pk_value(:join_by,item_data) pk_value
266283 from ut_compound_data_tmp ucd,
267284 diff_info i
268285 where ucd.data_id = :self_guid
269286 and ucd.item_hash = i.item_hash
270287 ) exp
271288 full outer join (
272- select extract(ucd.item_data,'/*/*') item_data,i.pk_hash
289+ select extract(ucd.item_data,'/*/*') item_data,i.pk_hash,
290+ ut_compound_data_helper.get_pk_value(:join_by,item_data) pk_value
273291 from ut_compound_data_tmp ucd,
274292 diff_info i
275293 where ucd.data_id = :other_guid
@@ -282,10 +300,13 @@ create or replace package body ut_compound_data_helper is
282300 ]'
283301 bulk collect into l_results
284302 using a_diff_id,
303+ a_join_by_xpath,
285304 a_exclude_xpath, a_include_xpath, a_expected_dataset_guid,
305+ a_join_by_xpath,
286306 a_exclude_xpath, a_include_xpath, a_actual_dataset_guid,
287- a_expected_dataset_guid, a_actual_dataset_guid,
307+ a_join_by_xpath, a_expected_dataset_guid,a_join_by_xpath , a_actual_dataset_guid,
288308 a_max_rows;
309+
289310 return l_results;
290311 end;
291312
0 commit comments