Select 所有客户都忠于一家公司?

Select all customers loyal to one company?

我有桌子:

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

我想 select 所有只从一家公司的商店下订单的客户的 ID - 'Samsung'('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 查询,但运算符相反。有没有什么聚合方法可以更好的解决这样的查询?

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

select 数千个订单,然后将它们与不同公司的数十万个订单进行比较是否有效?我知道,它比较排序的东西,所以它是 O( m + n + sort(n) + sort(m) )。但这对于数百万条记录来说仍然很大,是不是?

还有一个问题。我怎么能 select 所有客户值(姓名、地址)。我怎样才能加入他们,我可以

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

免责声明:此问题不是家庭作业。它对准备考试和渴望事情更有效。我的解决方案会在考试中被接受,但我喜欢有效的编程。

我喜欢使用 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'

如果您想要完整的客户信息,可以加入客户 table 回来。

这是否比 except 版本更好,需要在您的系统上进行测试。

不使用 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;

现在您有了一份忠实客户列表,每个客户都忠诚于一家公司。