MySQL LEFT JOIN 导致 "duplicate" 行

MySQL LEFT JOIN is causing "duplicate" rows

我有表 "customers" 和 "plans",我想列出所有客户,无论他们是否有计划。我正在使用查询来做到这一点

SELECT customer.name, plan.goal
FROM customer
LEFT JOIN plan ON plan.customerid=customer.customerid
ORDER BY customer.name

我也想看看有客户名字的目标(plan.goal)。只要客户没有计划或只有一个计划,这就有效。如果客户有两个或更多计划,那么我会得到与计划一样多的客户名称行。

我要的是最新计划的customer.name和plan.goal。我们可以假设 plan.planid 中的较高值是最新计划。

我想我应该使用子查询和 INNER JOINS 一些方式,但我现在不明白...

我认为这样的方法可行:

SELECT customer.name, plan.goal
FROM customer c
inner join plan p on c.customerId = p.customerId
inner JOIN (
    -- grabs the most recent plan per customer
    select max(planId) as planId, customerId
    from plan
    group by customerId
) maxPlan on p.planId = maxPlan.planId
UNION
-- handles customers w/o a plan
select customer.name, null
from customer c
left join plan p on c.customerId = p.customerId
where p.customerId is null
ORDER BY customer.name
SELECT c.name, 
( SELECT p.goal
  FROM plan p
  WHERE p.customerid=c.customerid
  AND NOT EXISTS (  SELECT 'a'
                    FROM plan p2
                    WHERE p2.customerid = p.customerid
                    AND p2.planid > p.planId
                  )
)
FROM customer c

我认为您应该在计划 table 中添加一个 boolean/tinyint 列,上面写着 IsLatest 或类似的内容。那么你可以这样做:

SELECT customer.name, plan.goal
FROM customer
LEFT JOIN plan ON plan.customerid=customer.customerid
where testplan.islatest = 1 or testplan.islatest is null
ORDER BY customer.name

此外,我会远离子查询答案,例如

select a from (select b from c where e=f) where g=h

因为它们通常表现不佳,而且阅读起来很混乱。