如何使用带有JOINS的Distinct / group过滤行内的重复项

时间:2011-01-11 20:54:35

标签: mysql sql distinct-values

为简单起见,我将简要介绍一下我想要实现的目标:

表1 - 成员

  ID    |   Name
--------------------
  1     |   John    
  2     |   Mike    
  3     |   Sam  


表1 - Member_Selections

  ID    |   planID
--------------------
  1     |   1    
  1     |   2    
  1     |   1    
  2     |   2    
  2     |   3    
  3     |   2    
  3     |   1    


表3 - Selection_Details

planID  |   Cost
--------------------
  1     |   5    
  2     |   10    
  3     |   12  

当我运行查询时,我想返回按成员分组的所有成员选择的总和。然而,我面临的问题(例如表2数据)是某些成员可能在系统内错误地重复信息。虽然我们尽最大努力预先过滤这些数据,但有时它会滑过裂缝,所以当我对系统进行必要的调用以获取信息时,我也想过滤这些数据。

结果应该显示:

结果表

ID  |    Name    | Total_Cost
-----------------------------
1   |    John    |   15
2   |    Mike    |   22
3   |    Sam     |   15

但是将约翰作为20美元,因为他错误地插入了两次计划ID#1。

我的查询目前是:

SELECT
    sq.ID, sq.name, SUM(sq.premium) AS total_cost
FROM
(
    SELECT
    m.id, m.name, g.premium
    FROM members m
    INNER JOIN member_selections s USING(ID)
    INNER JOIN selection_details g USING(planid)
) sq group by sq.agent

添加DISTINCT s.planID会错误地过滤结果,因为它只显示出售的单个PlanID 1(即使成员1和3购买了它)。

感谢任何帮助。

修改

我还忘了提到另一张表,即代​​理人表(将计划卖给会员的代理人)。

最后一组by语句分组代理ID销售的所有项目(将最终结果转换为单行)。

4 个答案:

答案 0 :(得分:2)

也许最简单的解决方案是在member_selections表上放置一个唯一的复合键:

 alter table member_selections add unique key ms_key (ID, planID);

这将阻止添加任何记录,其中ID / planID的唯一组合已存在于表中的其他位置。那只允许一个(1,1)

评论后续:

刚刚看到你对'alter ignore ...'的评论。这工作正常,但你仍然会留下表中的重复副本。我建议做一个唯一的密钥,然后手动清理表。我在评论中提出的查询应该找到所有重复项,然后您可以手动清除。一旦表格干净,就不需要复制处理版本的查询。

答案 1 :(得分:0)

使用UNIQUE键防止意外重复输入。这将消除源头的问题,而不是在它开始出现症状时。它还使后续查询更容易,因为您可以依赖于拥有一致的数据库。

答案 2 :(得分:0)

怎么样:

SELECT
    sq.ID, sq.name, SUM(sq.premium) AS total_cost
FROM
(
    SELECT
    m.id, m.name, g.premium
    FROM members m
    INNER JOIN 
         (select distinct ID, PlanID from member_selections) s
    USING(ID)
    INNER JOIN selection_details g USING(planid)
) sq group by sq.agent

顺便说一下,有没有理由你在member_selections上没有主键,这会阻止这些副本首先发生?

答案 3 :(得分:0)

您可以将group by子句添加到内部查询中,该查询按所有三列进行分组,基本上只返回唯一的行。 (我还将'premium'更改为'cost'以匹配您的示例表,并删除了代理程序部分)

SELECT
    sq.ID, 
    sq.name, 
    SUM(sq.Cost) AS total_cost
FROM
(
    SELECT
            m.id, 
            m.name, 
            g.Cost
    FROM 
            members m
            INNER JOIN member_selections s USING(ID) 
            INNER JOIN selection_details g USING(planid)

        GROUP BY
            m.ID,
            m.NAME,
            g.Cost
) sq 
group by 
    sq.ID,
    sq.NAME