MySQL加入SUM和3个表

时间:2012-06-14 20:33:36

标签: mysql join sum

我有以下表格(玩家,事件,分数)

enter image description here

我想列出2012年每位玩家获得多少积分。 我希望列表能够包含所有玩家,尽管有些玩家还没有在2012年玩过。

所以理论上它应该打印出来:

Ola Hansen     6  
Tove Svendson  0  
Kari Pettersen 0

我试过了:

SELECT *, sum(Points) as Points FROM Players
LEFT OUTER JOIN Scores ON P_Id=Player
LEFT OUTER JOIN Events ON Event=E_Id AND Year='2012' 
GROUP by P_Id ORDER by Points DESC

但是,这些都是这些年来的所有要点。

4 个答案:

答案 0 :(得分:3)

分数和事件需要在外部加入,然后将其加入玩家。

我们可以使用子查询或括号来强制这个特定的连接“优先”,但是在SQL文本中使用JOIN的顺序更好,然后小心地“定位”最后一个JOIN给玩家(在这种情况下是正确的) )。

COALESCE仅用于将NULL转换为0。

SELECT
    P_Id, LastName, FirstName, COALESCE(SUM(Points), 0) TotalPoints
FROM
    Scores
    JOIN Events
        ON Event = E_Id AND Year = 2012
    RIGHT JOIN Players
        ON P_Id = Player
GROUP BY
    P_Id, LastName, FirstName
ORDER BY
    TotalPoints DESC;

这会产生:

P_ID    LASTNAME    FIRSTNAME   TOTALPOINTS
1       Hansen      Ola         6
2       Svendson    Tove        0
3       Pettersen   Kari        0

您可以在此SQL Fiddle中使用它。

答案 1 :(得分:1)

由于人们(包括我自己)喜欢将“最重要”或“主题”表放在首位,因此您可以通过首先发生事件和分数之间的联接以及作为内部联接来完成您正在寻找的内容: / p>

SELECT
   P.P_Id,
   P.LastName,
   P.FirstName,
   IsNull(Sum(P.Points), 0) TotalPoints
FROM
   Players P
   LEFT JOIN (
      Events E
      INNER JOIN Scores S
         ON E.Event = S.E_Id
         AND E.Year = '2012'
   ) ON P.P_Id = S.Player
GROUP BY P.P_Id, P.LastName, P.FirstName -- no silly MYSQL implicit grouping for me!
ORDER BY TotalPoints DESC

关于强制实施连接顺序的诀窍在于它实际上是ON子句的位置 - 你可以删除括号并且它仍然可以工作。但我更喜欢使用它们,因为我认为额外的清晰度是必须的。

这也是一种非常有效的方法来强制执行连接顺序,方法是先将INNER JOIN放在第一位,然后再输出OUTER。只是,您希望最后一个表成为决定最终集合成员资格的表。所以将它切换到RIGHT JOIN就可以了:

SELECT
   P.P_Id,
   P.LastName,
   P.FirstName,
   IsNull(Sum(P.Points), 0) TotalPoints
FROM
   Events E
   INNER JOIN Scores S
      ON E.Event = S.E_Id
      AND E.Year = '2012'
   RIGHT JOIN Players P
      ON S.Player = P.P_Id
GROUP BY P.P_Id, P.LastName, P.FirstName
ORDER BY TotalPoints DESC

我觉得有必要补充一点,当不同表中的PK与FK相比时,使用不同的名称列在我看来是对最佳实践的违反。它应该是所有表中的“P_Id”,或者所有表中的“Player”,并且不一致。

答案 2 :(得分:1)

试试这个:

select firstName, lastName, sum(if(year is null, 0, points)) points from p
left join s on p_id = player
left join e on e_id = event and year = 2012
group by p_id, lastName, firstName
order by points desc

我猜它应该比子查询表现更好......但是便携性会降低。试一试!

这是fiddle

答案 3 :(得分:0)

SELECT P.FIRSTNAME, P.LASTNAME,  A.Points as Points 
FROM Players P
LEFT OUTER JOIN 
(
   SELECT S.Player, sum(Points) 
   FROM Scores S, Events E 
   WHERE S.Event=E.E_Id 
   AND E.Year='2012' 
   GROUP BY S.Player
) A 
ON A.PLAYER = P.P_ID
ORDER by Points DESC

基本上你需要事件和分数之间的INNER JOIN来强制2012和LEFT OUTER JOIN的点数之和与这个子结果,因为你想要所有的球员+他们在2012年的积分。