I have two tables with same structure. Let it be 3 columns and a primary key, which are all number values.
Both tables should have similar values, but there are some different values present in the tables. I need to find out these values and at which positions they exist. How can I write the script for this in Oracle SQL Developer?
I tried it using joins and cursors. I'm new to this PL/SQL scripting, thus its not easy for me to understand it. so any kind of help is appreciated! Happy coding!
CREATE OR REPLACE PACKAGE mismatch_finder IS
PROCEDURE find_mismatch_values;
FUNCTION row_finder_tb1(pkey number) RETURN table1%rowtype;
FUNCTION row_finder_tb2(pkey number) RETURN table2%rowtype;
END mismatch_finder;
CREATE OR REPLACE PACKAGE BODY mismatch_finder AS
PROCEDURE find_mismatch_values AS
CURSOR CUR IS
select pk from(select * from table1 minus select * from table2); REC CUR%rowtype; t1 table1%rowtype; t2 table2%rowtype; col_count number := 1;
BEGIN
OPEN CUR; LOOP FETCH CUR into REC; EXIT when CUR%NOTFOUND;
t1 := row_finder_tb1(REC.pk); t2 := row_finder_tb2(REC.pk);
IF (t1.column_1 != t2.column_1) THEN dbms_output.put_line('Value missmatch at key value' || REC.pk || ' column number ' || col_count || ' Table 1 value is : ' || t1.column_1 || ' and Table 2 value is : ' || t2.column_1);
END IF; col_count := col_count 1;
IF (t1.column_2 != t2.column_2) THEN dbms_output.put_line('Value missmatch at key value' || REC.pk || ' column number ' || col_count || ' Table 1 value is : ' || t1.column_2 || ' and Table 2 value is : ' || t2.column_2);
END IF; col_count := col_count 1;
IF (t1.column_3 != t2.column_3) THEN dbms_output.put_line('Value missmatch at key value' || REC.pk || ' column number ' || col_count || ' Table 1 value is : ' || t1.column_3 || ' and Table 2 value is : ' || t2.column_3);
END IF; col_count := 1;
END LOOP; CLOSE CUR;
END find_mismatch_values;
FUNCTION row_finder_tb1(p_key number) RETURN table1%rowtype IS
TEMP table1%rowtype;
BEGIN
select * into TEMP from table1 where table1.pk = p_key; RETURN(TEMP);
END row_finder_tb1;
FUNCTION row_finder_tb2(p_key number) RETURN table2%rowtype IS
TEMP table2%rowtype;
BEGIN
select * into TEMP from table2 where table2.pk = p_key; RETURN(TEMP);
END row_finder_tb2;
END mismatch_finder;
CodePudding user response:
Here's one way to do it:
- Pivot all columns into rows with added column ID (c_id in cte_tb1, cte_tb2), which makes (id, c_id) the primary key of both tables.
- Assume both tables have the same number of IDs and rows (change the inner join to outer join if not)
- Join both pivoted CTE tables and compare values.
create table tb1 (
id int,
c1 int,
c2 int,
c3 int
);
create table tb2 (
id int,
c1 int,
c2 int,
c3 int
);
insert into tb1 values (1, 11, 12, 13), (2, 21, 22, 23), (3, 31, 32, 33), (4, 41, 42, 43);
insert into tb2 values (1, 11, 12, 13), (2, 22, 22, 23), (3, 31, 33, 35), (4, 42, 43, 44);
with cte_tb1 as (
select id, 1 as c_id, c1 as value from tb1
union all
select id, 2 as c_id, c2 as value from tb1
union all
select id, 3 as c_id, c3 as value from tb1),
cte_tb2 as (
select id, 1 as c_id, c1 as value from tb2
union all
select id, 2 as c_id, c2 as value from tb2
union all
select id, 3 as c_id, c3 as value from tb2)
select t1.id as id,
t1.c_id as col_id,
t1.value as t1_value,
t2.value as t2_value
from cte_tb1 t1
join cte_tb2 t2
using (id, c_id)
where t1.value != t2.value
order by 1,2;
Result:
id|col_id|t1_value|t2_value|
-- ------ -------- --------
2| 1| 21| 22|
3| 2| 32| 33|
3| 3| 33| 35|
4| 1| 41| 42|
4| 2| 42| 43|
4| 3| 43| 44|
CodePudding user response:
You can join the tables and use the CASE expressions to show differences. With sample data like:
WITH
tbl_1 AS
(
Select 1 "ID", 10 "A", 100 "B", 1000 "C" From Dual Union All
Select 2 "ID", 11 "A", 101 "B", 1001 "C" From Dual Union All
Select 3 "ID", 12 "A", 102 "B", 1002 "C" From Dual Union All
Select 4 "ID", 13 "A", 103 "B", 1003 "C" From Dual Union All
Select 5 "ID", 14 "A", 104 "B", 1004 "C" From Dual
),
tbl_2 AS
(
Select 1 "ID", 10 "A", 100 "B", 1000 "C" From Dual Union All
Select 2 "ID", 11 "A", 201 "B", 2001 "C" From Dual Union All
Select 3 "ID", 12 "A", 102 "B", 1002 "C" From Dual Union All
Select 4 "ID", 23 "A", 103 "B", 1003 "C" From Dual Union All
Select 5 "ID", 14 "A", 104 "B", 1004 "C" From Dual
)
Here is the code:
SELECT
t1.ID,
CASE When t1.A = t2.A THEN 0 ELSE t1.A END "T1_A",
CASE When t1.A = t2.A THEN 0 ELSE t2.A END "T2_A",
CASE When t1.B = t2.B THEN 0 ELSE t1.B END "T1_B",
CASE When t1.B = t2.B THEN 0 ELSE t2.B END "T2_B",
CASE When t1.C = t2.C THEN 0 ELSE t1.C END "T1_C",
CASE When t1.C = t2.C THEN 0 ELSE t2.C END "T2_C"
FROM
tbl_1 t1
Inner Join
tbl_2 t2 ON(t2.ID = t1.ID)
The result shows just different values while those that are equal are set to 0. You can change it to Null or anything else you want including the actual values.
| ID | T1_A | T2_A | T1_B | T2_B | T1_C | T2_C |
|---|---|---|---|---|---|---|
| 1 | 0 | 0 | 0 | 0 | 0 | 0 |
| 2 | 0 | 0 | 101 | 201 | 1001 | 2001 |
| 3 | 0 | 0 | 0 | 0 | 0 | 0 |
| 4 | 13 | 23 | 0 | 0 | 0 | 0 |
| 5 | 0 | 0 | 0 | 0 | 0 | 0 |
Regards...
