Technology: SQL Server.
I have two tables similar to following construct. Column name are same in both the tables.
I need to compare both tables and get the output (table) as shown in results. Preform this operation dynamically, Table name and column name will be provided on the fly.
Table1:
Key | column1 | column2 | column3 |
---|---|---|---|
1 | 4 | 5 | 6 |
2 | 2 | 5 | 8 |
3 | 4 | 5 | 10 |
4 | 4 | 6 | 10 |
Table2:
Key | column1 | column2 | column3 |
---|---|---|---|
1 | 6 | 5 | 6 |
2 | 2 | 5 | 8 |
3 | 4 | 5 | 10 |
4 | 4 | 8 | 10 |
Output:
TableName | keyColumnName | KeyColumnValue | ColumnName | Table1ColumnValue | Table2ColumnValue |
---|---|---|---|---|---|
Table1 | key | 1 | column1 | 4 | 6 |
Table1 | key | 4 | column2 | 6 | 8 |
For each pair of rows (from TABLE1 and TABLE2 with the same KEY) this query only detect de first columns mismatch (when two or three columns mismatch only return de values from the first columns mismatch).
TableName ever refer to table1, I have to put a subquery to get it (ORDER BY key, t), without this subquery it returns table1 or table2 arbitrarily but with the Table1ColumnValue and Table2ColumnValue correctly set (changed).
I try it in Postgresql, you have to change some functions to try it in sqlServer like ARRAY_LENGTH() (in the second query) OR ARRAY_AGG().
SELECT
t[1] AS TableName,
keyColumnName,
k AS KeyColumnValue,
CASE WHEN a1[1] != a1[2] THEN ColumnNames[1]
WHEN a2[1] != a2[2] THEN ColumnNames[2]
WHEN a3[1] != a3[2] THEN ColumnNames[3]
END AS ColumnName,
CASE WHEN a1[1] != a1[2] THEN a1[1]
WHEN a2[1] != a2[2] THEN a2[1]
WHEN a3[1] != a3[2] THEN a3[1]
END AS Table1ColumnValue,
CASE WHEN a1[1] != a1[2] THEN a1[2]
WHEN a2[1] != a2[2] THEN a2[2]
WHEN a3[1] != a3[2] THEN a3[2]
END AS Table2ColumnValue
FROM
(SELECT key, array_agg(column1) AS a1, array_agg(column2) AS a2, array_agg(column3) AS a3, keyColumnName, ColumnNames, array_agg(t) AS t
FROM
(SELECT *
FROM
(SELECT *, 'key' AS keyColumnName, ARRAY['column1', 'column2', 'column3'] AS ColumnNames, 'table1' AS t
FROM t1
UNION
SELECT *, 'key' AS keyColumnName, ARRAY['column1', 'column2', 'column3'] AS ColumnNames, 'table2' AS t
FROM t2) AS u
ORDER BY key, t
) AS aux1
GROUP BY key, keyColumnName, ColumnNames
ORDER BY key, t
) AS aux2
WHERE a1[1] != a1[2] OR a2[1] != a2[2] OR a3[1] != a3[2]
If you have rows with a key in a table that not exist in the other table, you can use this other query (it is similar than the above with a few modifications).
SELECT
t[1] AS TableName,
keyColumnName,
k AS KeyColumnValue,
CASE WHEN a1[1] != a1[2] OR ARRAY_LENGTH(a1, 1) = 1 THEN ColumnNames[1]
WHEN a2[1] != a2[2] THEN ColumnNames[2]
WHEN a3[1] != a3[2] THEN ColumnNames[3]
END AS ColumnName,
CASE WHEN a1[1] != a1[2] OR ARRAY_LENGTH(a1, 1) = 1 THEN a1[1]
WHEN a2[1] != a2[2] THEN a2[1]
WHEN a3[1] != a3[2] THEN a3[1]
END AS Table1ColumnValue,
CASE WHEN a1[1] != a1[2] THEN a1[2]
WHEN a2[1] != a2[2] THEN a2[2]
WHEN a3[1] != a3[2] THEN a3[2]
END AS Table2ColumnValue
FROM
(SELECT key, array_agg(column1) AS a1, array_agg(column2) AS a2, array_agg(column3) AS a3, keyColumnName, ColumnNames, array_agg(t) AS t
FROM
(SELECT *
FROM
(SELECT *, 'key' AS keyColumnName, ARRAY['column1', 'column2', 'column3'] AS ColumnNames, 'table1' AS t
FROM t1
UNION
SELECT *, 'key' AS keyColumnName, ARRAY['column1', 'column2', 'column3'] AS ColumnNames, 'table2' AS t
FROM t2) AS u
ORDER BY key, t
) AS aux1
GROUP BY key, keyColumnName, ColumnNames
ORDER BY key, t
) AS aux2
WHERE a1[1] != a1[2] OR a2[1] != a2[2] OR a3[1] != a3[2] OR ARRAY_LENGTH(a1, 1) = 1
You can unpivot the data and then use join
:
with t1 as (
select t1.key, v.*
from table1 t1
(values ('column1', t1.column1), ('column2', t1.column2), ('column3', t1.column3)
) v(name, val)
),
t2 as (
select t2.key, v.*
from table1 t2
(values ('column1', t2.column1), ('column2', t2.column2), ('column3', t2.column3)
) v(name, val)
)
select t1.*, t2.*
from t1 join
t2
on t1.key = t2.key and
t1.name = t2.name
where t1.val <> t2.val;
Some important notes:
NULL
values into account.All three of these are consistent with the sample data you have presented -- and they are reasonable assumptions. All can be handled by modifying the query, but that makes the query more complicated -- and tends to hide the important idea behind the query (unpivot --> join --> filter).
If you need a more general query, I would request that you ask a new question, with more explicit standard data and desired results.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.