SQL查询,仅查找具有2个源值的客户ID

SQL查询,仅查找具有2个源值的客户ID,sql,oracle,join,count,Sql,Oracle,Join,Count,我有两个表,一个存储客户id,另一个存储客户id以及使用该客户信息的不同来源的信息。例子: 表A 表B Customer Id Source 1 'AA' 2 'AA' 1 'AB' 2 'AB' 2 'AC' 3 'AA' 3 'AB' 3 'AE' 4 'AA' 4 'AB'

我有两个表,一个存储客户id,另一个存储客户id以及使用该客户信息的不同来源的信息。例子: 表A

表B

Customer Id Source
1            'AA'
2            'AA'
1            'AB'
2            'AB'
2            'AC'
3            'AA'
3            'AB'
3            'AE'
4            'AA'
4            'AB'
我想编写一个SQL查询,返回只有AA和AB作为源的记录(没有其他源)

我已编写了以下查询,但无法正常工作:

select a.customer_id
  from A a, B b
 where a.customer_id = b.customer_id
   and b.source IN ('AA','AB')
 group by a.customer_id
having count(*) = 2;

您可以使用聚合:

select b.customer_id
from b
where b.source in ('AA', 'AB')
group by b.customer_id
having count(distinct b.source) = 2;
也就是说,您的版本应该可以工作。但是,您应该学会使用正确、明确、标准、可读的
JOIN
语法。但是,在这种情况下不需要联接

如果只需要这两个源,则需要调整逻辑:

select b.customer_id
from b
group by b.customer_id
having sum(case when b.source = 'AA' then 1 else 0 end) > 0 and  -- has AA
       sum(case when b.source = 'AB' then 1 else 0 end) > 0 and  -- has AB
       count(distinct b.source) = 2;

您可以使用聚合:

select b.customer_id
from b
where b.source in ('AA', 'AB')
group by b.customer_id
having count(distinct b.source) = 2;
也就是说,您的版本应该可以工作。但是,您应该学会使用正确、明确、标准、可读的
JOIN
语法。但是,在这种情况下不需要联接

如果只需要这两个源,则需要调整逻辑:

select b.customer_id
from b
group by b.customer_id
having sum(case when b.source = 'AA' then 1 else 0 end) > 0 and  -- has AA
       sum(case when b.source = 'AB' then 1 else 0 end) > 0 and  -- has AB
       count(distinct b.source) = 2;

一个相当有效的解决方案是两个
exists
子查询:

select a.*
from a
where
    exists(select 1 from b where b.customer_id = a.customer_id and b.source = 'AA')
    and exists(select 1 from b where b.customer_id = a.customer_id and b.source = 'AB')
    and not exists(select 1 from b where b.customer_id = a.customer_id and b.source not in ('AA', 'AB'))
如果索引位于
b(客户id,源代码)
,则应该可以快速运行

另一种选择是侵害:

select customer_id
from b
group by customer_id
having
    max(case when source = 'AA' then 1 else 0 end) = 1
    and max(case when source = 'AB' then 1 else 0 end) = 1
    and max(case when source not in ('AA', 'AB') then 1 else 0 end) = 0

一个相当有效的解决方案是两个
exists
子查询:

select a.*
from a
where
    exists(select 1 from b where b.customer_id = a.customer_id and b.source = 'AA')
    and exists(select 1 from b where b.customer_id = a.customer_id and b.source = 'AB')
    and not exists(select 1 from b where b.customer_id = a.customer_id and b.source not in ('AA', 'AB'))
如果索引位于
b(客户id,源代码)
,则应该可以快速运行

另一种选择是侵害:

select customer_id
from b
group by customer_id
having
    max(case when source = 'AA' then 1 else 0 end) = 1
    and max(case when source = 'AB' then 1 else 0 end) = 1
    and max(case when source not in ('AA', 'AB') then 1 else 0 end) = 0

这假设客户id/源组合没有重复项

select a.customer_id
  from A a join B b
    on a.customer_id = b.customer_id
 group by a.customer_id
-- both 'AA' and 'AB', but no other
having sum(case when b.source IN ('AA','AB') then 1 else -1 end) = 2
在联接之前进行聚合可能更有效:

select a.customer_id
from A a join 
  ( select customer_id
    from B b
    group by customer_id
    -- both 'AA' and 'AB', but no other
    having sum(case when source IN ('AA','AB') then 1 else -1 end) = 2
  ) b
on a.customer_id = b.customer_id

这假设客户id/源组合没有重复项

select a.customer_id
  from A a join B b
    on a.customer_id = b.customer_id
 group by a.customer_id
-- both 'AA' and 'AB', but no other
having sum(case when b.source IN ('AA','AB') then 1 else -1 end) = 2
在联接之前进行聚合可能更有效:

select a.customer_id
from A a join 
  ( select customer_id
    from B b
    group by customer_id
    -- both 'AA' and 'AB', but no other
    having sum(case when source IN ('AA','AB') then 1 else -1 end) = 2
  ) b
on a.customer_id = b.customer_id

此解决方案是否确保除“AA”和“AB”之外不存在其他源?第一个源为AA,第二个源为AC的记录也不会返回任何其他源。@AlokMathur。我错过了要求的这一部分,但更新了答案。此解决方案是否确保除“AA”和“AB”之外不存在其他来源?第一个来源为AA,第二个来源为AC的记录,也不会返回任何其他来源。@AlokMathur。我错过了这部分的要求,但更新了答案。谢谢,这应该有效,存在和不存在的组合。我将学习更多关于这方面的知识。谢谢,这应该是有效的,存在和不存在的组合。我将在这方面了解更多。