MySQL - 如何在不产生重复数据的情况下连接两个表?

9
我有两个表需要连接。一个包含客户列表,另一个包含订单列表。我正在尝试构建一个查询,以便选择在订单表中至少有一个订单的所有客户在客户表中列出。但是,我不想获取那些有多个订单的客户的重复记录。您有什么建议吗?
我知道这可能是一个常见的问题,但我不知道这种类型的查询应该被称为什么,因此无法搜索答案。非常感谢您的建议。谢谢。

你试过用 DISTINCT 吗? - FeRtoll
4个回答

11

这比您想象的要简单得多:

select distinct(customer_id) from orders;

编辑:如果您确实想获得客户的完整信息,

select * from customers where customer_id in (select distinct(customer_id) from orders);


谢谢,这看起来是最成功的机会。由于客户和订单表非常庞大(客户有1.8亿条记录,订单有7000万条记录),特别是在客户表上使用distinct存在问题。 - Wige
1
我认为子查询中的DISTINCT是不必要的 - 可以在有和没有它的情况下检查EXPLAIN PLAN,看看是否有区别。 - OMG Ponies

7

使用:

SELECT c.*
  FROM CUSTOMERS c
 WHERE EXISTS (SELECT NULL
                 FROM ORDERS o
                WHERE o.custeromid = c.id)

IN子句是一个替代方案,但是EXISTS更适用于重复项,因为它在第一个重复项上返回true,所以它不会处理整个表。


如果在 o.customerid 上建立索引,它不仅会表现得更好(很多)吗? - Klaus Byskov Pedersen
@Klaus Byskov Hoffmann:你需要测试并查看,但是对我来说,在第一次匹配时退出比全部比较更好。数据类型在其中也可能发挥作用。 - OMG Ponies
是的,我同意第一个匹配就退出通常几乎总是更好。我只是考虑最坏情况,出于理论兴趣而问的 :-) - Klaus Byskov Pedersen
谢谢指出EXISTS在去重方面更好用!非常有帮助。 - cwhsu
但它只会返回客户记录,如果我想在其中获取订单表记录怎么办? - Tirth Timaniya

2
select customers.id, customers.name, count(orders.id)
from customers 
   inner join orders on orders.customer_id = customers.Id
group by customers.id, customers.name
having count(orders.id) > 0

如果你只需要返回customer_id和订单数量,那么就不需要进行连接操作。使用select customer_id, count(*) from orders group by customer_id即可完成任务。 - Michael Kopinsky
我的一般规则是,如果表格不在结果集中,我就不会连接它,这样我就不必构建GROUP BY / etc来过滤重复项。 - OMG Ponies
@OMG:嗯,有趣的规则。很有道理。 - Klaus Byskov Pedersen

1
SELECT
  c.id, 
  c.name
FROM
  customer c
    INNER JOIN order o ON o.customer_id = c.id
GROUP BY 
  c.id,
  c.name
HAVING
  COUNT(o.id) >= 1

记不清HAVING和GROUP BY哪个先出现了。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接