在Oracle中查找两个表之间的奇数行

时间:2018-10-13 14:11:21

标签: sql oracle

我有两个具有以下模式的表

id, fruit

在TableA中,值如下:

A01, Apple
A02, Orange
A03, Pineapple
A03, Pineapple
A05, Banana

在TableB中,值如下:

A01, Apple
A02, Orange
A03, Pineapple
A04, Pineapple
A05, Banana

如何协调这两个表以仅返回TableA中的重复行A03?就像一对一比较元组并返回奇数元组。

我尝试了如下的减号查询

Select * from TableA
minus
Select * from TableB

但这并没有返回我期望的结果集。

3 个答案:

答案 0 :(得分:2)

好像您想从B中排除A中存在的行,而只排除确切的行。我猜你可以简单地给他们分配一个行号:

SELECT "id", "fruit", ROW_NUMBER() OVER (PARTITION BY "id", "fruit" ORDER BY NULL) AS rn
FROM TableA
MINUS
SELECT "id", "fruit", ROW_NUMBER() OVER (PARTITION BY "id", "fruit" ORDER BY NULL) AS rn
FROM TableB

SQL Fiddle

答案 1 :(得分:1)

许多年前,Marco Stefanetti在AskTom上提出了以下出色的方法。它只要求每个表读取一次,并且只执行一种排序。

上下文是最通用的:查询将查找一个表中存在的行,而不是另一表中的行,但是-允许重复时-还将查找两个表中都存在的行,但行号不同重复项。

我在WITH子句中创建测试数据;在测试解决方案时,可以将其删除并从最后一条SELECT语句开始。

with
  tablea (id, fruit) as (
    select 'A01', 'Apple'     from dual union all
    select 'A02', 'Orange'    from dual union all
    select 'A03', 'Pineapple' from dual union all
    select 'A03', 'Pineapple' from dual union all
    select 'A05', 'Banana'    from dual
  )
, tableb (id, fruit) as (
    select 'A01', 'Apple'     from dual union all
    select 'A02', 'Orange'    from dual union all
    select 'A03', 'Pineapple' from dual union all
    select 'A04', 'Pineapple' from dual union all
    select 'A05', 'Banana'    from dual
  )
select   id, fruit, count(case source when 'tablea' then 1 end) as count_in_a,
                    count(case source when 'tableb' then 1 end) as count_in_b
from     (
           select id, fruit, 'tablea' as source from tablea
           union all
           select id, fruit, 'tableb' as source from tableb
         )
group by id, fruit
having   count(case source when 'tablea' then 1 end) !=
         count(case source when 'tableb' then 1 end)
;

ID  FRUIT     COUNT_IN_A COUNT_IN_B
--- --------- ---------- ----------
A03 Pineapple          2          1
A04 Pineapple          0          1

答案 2 :(得分:-1)

这是您想要的吗?

Select id, fruit
from TableA
group by id, fruit
having count(*) > 1
minus
Select id, fruit
from TableB;

尚不清楚是否确实需要tableB。如果您还需要其他列,则可以使用exists来表示:

Select id, fruit
from (select a.*, count(*) over (partition by id, fruit) as cnt
      from TableA a
     ) a
where cnt > 1 and
      exists (select 1 from tableB b where b.id = a.id and b.fruit = a.fruit);

或使用in

Select id, fruit
from (select a.*, count(*) over (partition by id, fruit) as cnt
      from TableA a
     ) a
where cnt > 1 and
      (a.id, a.fruit) in (select b.id, b.fruit) from tableB);