3

我有以下表格(球员、赛事、分数)

在此处输入图像描述

我想要一份每个球员在 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

4 回答 4

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中使用它。

于 2012-06-14T21:23:25.593 回答
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

我想它应该比子查询执行得更好......但便携性会降低。试试看!

这是小提琴

于 2012-06-14T21:03:56.827 回答
1

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

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”,并且不能不一致。

于 2012-06-14T20:42:16.200 回答
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 JOINbetween events 和 Scores 来强制 2012 的积分总和以及LEFT OUTER JOIN带有此子结果的 a,因为您希望所有球员 + 他们在 2012 年的积分。

于 2012-06-14T20:46:27.303 回答