选择忠诚于一家公司的所有客户?

时间:2015-01-19 13:17:30

标签: sql select join

我有桌子:

TABLE     | COLUMNS
----------+----------------------------------
CUSTOMER  |  C_ID, C_NAME, C_ADDRESS
SHOP      |  S_ID, S_NAME, S_ADDRESS, S_COMPANY
ORDER     |  S_ID, C_ID, O_DATE

我想选择只从一家公司的商店订购的所有客户的ID - '三星'('LG','HP',......并不重要,它是动态的。)

我只有一个解决方案,但我觉得它很难看:

( SELECT DISTINCT c_id FROM order JOIN shop USING(s_id) WHERE s_company = "Samsung" )
EXCEPT 
( SELECT DISTINCT c_id FROM order JOIN shop USING(s_id) WHERE s_company != "Samsung" );

相同的SQL查询,但反向运算符。是否有更好的解决此类查询的聚合方法?

我的意思是,可能有数百万的订单(我真的没有订单,我有更多经常发生的事情)。

选择数千个订单然后将它们与成千上万个订单进行比较是否有效?我知道,它比较了排序的东西,所以它是O( m + n + sort(n) + sort(m) )。但对于数百万条记录而言,这仍然很大,或者不是?

还有一个问题。如何选择所有客户值(名称,地址)。我怎样才能加入他们,我能做到吗

SELECT CUSTOMER.* FROM CUSTOMER JOIN ( (SELECT...) EXCEPT (SELECT...) ) USING (C_ID);

免责声明:这个问题不是作业。它为考试做准备,并希望事情更有效。我的解决方案将在考试中被接受,但我喜欢有效的编程。

2 个答案:

答案 0 :(得分:4)

我喜欢使用group byhaving子句来处理此类问题。您可以使用以下方式获取客户列表:

select o.c_id
from orders o join
     shops s
     on o.s_id = o.s_id
group by c_id
having min(s.s_company) = max(s.s_company);

如果您关心特定公司,那么:

having min(s.s_company) = max(s.s_company) and
       max(s.s_company) = 'Samsung'

如果您需要完整的客户信息,可以重新加入客户表。

这是否比except版本效果更好,必须在您的系统上进行测试。

答案 1 :(得分:1)

不使用像Min和Max这样的聚合函数的查询怎么样?

select  C_ID, S_ID
from    shop
group by C_ID, S_ID;

现在我们有一份明确的客户名单以及他们所购买的所有公司。忠诚的客户将是那些只出现在列表中的客户。

select  C_ID
from    Q1
group by C_ID
having count(*) = 1;

加入第一个查询以获取公司ID:

with
Q1 as(
  select  C_ID, S_ID
  from    shop
  group by C_ID, S_ID
),
Q2 as(
  select  C_ID
  from    Q1
  group by C_ID
  having count(*) = 1
)
select  Q1.C_ID, Q1.S_ID
from    Q1
join    Q2
    on  Q2.C_ID = Q1.C_ID;

现在您有一份忠诚的客户名单,以及每个忠诚的公司。