如何在oracle中找到不匹配的行而不使用set运算符和join&还查询特定行的不匹配列名称

时间:2017-08-29 15:23:04

标签: sql oracle

我正在研究两个表test1和test2 我必须在表test1中找到匹配的,不匹配的值,而不是在test2中...反之亦然

然后我必须联合所有查询以获得最终结果。

但是我遇到了无与伦比的问题。使用set运算符,当我将它与excel表数据进行比较时,我得到了错误的结果集,那么我将获得15个额外的行

注意:两个表中都没有公共列

表格:TEST1

a     b        c
2001  abc    john
2008  cab    sam
2002  qwe    mike
2002  asd    samuel
2012  ddd    sammy

表格:TEST2

a      b      c
2001  abc    john
2008  c@b    saam
2009  qwe    mike
2002  asd    samuel
2001  a bc   john

输出:

来自表test1或test2 的不匹配行我在这里假设test2

a        b      c      column_name
2008    c@b    saam      a,b
2009    qwe    mike    null
2001    a bc   john      b

我希望上面的输出与table和column_names中的不匹配的行

Column_names 包含特定行中不匹配的列的名称。

我的查询(使用减号)

Select t2.a, t2.b, t2.c from
(Select a,b,c  from test1 t1
 Minus  
Select  a,b,c  from test2 t2)

对于column_name,我的逻辑是

Case when t1.a !=  t2.a then 'column a name' 
When t1.b 1= t2.b then 'column b name' 

 *....And so on .....*

但我认为可以在加入的帮助下完成我不想要

我正在使用Oracle 12c。

1 个答案:

答案 0 :(得分:1)

你只需要使用一个union和minus两次。减号只查看第一个表中的记录而不是秒。使用减号时,要查看那些不反转表格顺序的那些,请使用联合。

With test1 (A,b,c) as (
SELECT 2001,  'abc',    'john' from dual union all
SELECT 2008,  'cab',    'sam' from dual union all
SELECT 2002,  'qwe',    'mike' from dual union all
SELECT 2002,  'asd',    'samuel' from dual union all
SELECT 2012,  'ddd',    'sammy' from dual),
test2 (a,b,c) as (
SELECT 2001, 'abc',    'john' from dual union all
SELECT 2008, 'c@b',    'saam' from dual union all
SELECT 2009, 'qwe',    'mike' from dual union all
SELECT 2002, 'asd',    'samuel' from dual union all
SELECT 2001, 'a bc',   'john' from dual )
-- ()'s matter here as UNION minus and select all occur at the same level of precedence.  
-- so test1-test2 union test2 minus test1 w/o them!
(Select * from test1 minus Select * from test2)
UNION ALL
(Select * from test2 minus Select * from test1)

--but if you use a cte it works...
With test1 (A,b,c) as (
SELECT 2001,  'abc',    'john' from dual union all--
SELECT 2008,  'cab',    'sam' from dual union all--x
SELECT 2002,  'qwe',    'mike' from dual union all--x
SELECT 2002,  'asd',    'samuel' from dual union all--
SELECT 2012,  'ddd',    'sammy' from dual),--x
test2 (a,b,c) as (
SELECT 2001, 'abc',    'john' from dual union all--
SELECT 2008, 'c@b',    'saam' from dual union all--x
SELECT 2009, 'qwe',    'mike' from dual union all--x
SELECT 2002, 'asd',    'samuel' from dual union all--
SELECT 2001, 'a bc',   'john' from dual ),
cte as (Select * from test1 minus Select * from test2),  --NEEDED
cte2 as (Select * from test2 minus Select * from test1)  --NEEDED
Select * from cte
union 
Select * from cte2;

或者这也有效:

Select * from (
Select Distinct * from test1
UNION ALL
SELECT Distinct * From test2)
Group by A,B,C
having count(*) = 1

使用完整的外连接,我们可以得到列名...排序。

SELECT A.*, B.*, case when coalesce(A.A,0)<>coalesce(B.A,-1) then 'A' end ||','||
                case when coalesce(A.B,'0')<>coalesce(B.B,'-0') then 'B' end ||','||
                case when coalesce(A.C,'0')<>coalesce(B.C,'-0') then 'C' end  as MisMatchOn
FROM test1 A
FULL OUTER JOIN Test2 B
on 1=1 
where length(case when coalesce(A.A,0)<>coalesce(B.A,-1) then 'A' end ||','||
                case when coalesce(A.B,'0')<>coalesce(B.B,'-0') then 'B' end ||','||
                case when coalesce(A.C,'0')<>coalesce(B.C,'-0') then 'C' end)<5
and replace(case when coalesce(A.A,0)<>coalesce(B.A,-1) then 'A' end ||','||
                case when coalesce(A.B,'0')<>coalesce(B.B,'-0') then 'B' end ||','||
                case when coalesce(A.C,'0')<>coalesce(B.C,'-0') then 'C' end,',','') is not null;