2012-06-14 2 views
3

я следующие таблицы (Игроки, события, Партитуры)MySQL JOIN с SUM и 3 таблицы

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 

Но это все точки со всех лет.

+2

Я предполагаю, что это MySQL, поскольку никакая другая СУБД не позволит этой ужасной «GROUP BY» и агрегации? – JNK

+0

Мои плохие, исправленные :-) –

ответ

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 

хитрость о обеспечении порядка соединения является то, что на самом деле это расположение пункта о том, что это делает, вы можете удалить скобки, и он должен работать. Но я предпочитаю использовать их, потому что я думаю, что дополнительная ясность - это необходимость.

Это также вполне эффективный способ принудительного исполнения заявки на вступление, сначала вставляя ваши ВХОДНЫЕ ПРИСОЕДИНЯЯ, а ВЕРСИЯ - последним. Только, вы хотите, чтобы последняя таблица была той, которая диктует членство в конечном наборе. Так переключая его 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» во всех таблицах и не быть непоследовательным.

+0

Нет ничего глупого в группировке с помощью Первичного ключа. –

+0

Он не говорил о глупости в группировке первичного ключевого стола, он говорил, что ему не нравятся разные имена столбцов в ссылочных таблицах, которые находятся в таблице первичных ключей, в этом случае, если Players.P_Id является Pk, в Оценка должна быть Scores.P_Id not Scores.Player, я согласен с erike. preserver the standard –

+0

О, LOL, вы говорили о группе, в MysQl вы можете сделать группу с помощью «*», что действительно глупо, это должно быть со столбцами –

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 с этим subresult, потому что вы хотите, чтобы все игрок + свои точки в 2012

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

Счета и события должны быть соединены между собой до Внешние соединения с ними.

Мы могли бы использовать подзапрос или круглые скобки, чтобы заставить это конкретное объединение «приоритет», но лучше всего использовать порядок JOINs в тексте SQL, а затем тщательно «ориентировать» последний JOIN на игроков (RIGHT в этом дело).

COALESCE предназначен для преобразования NULL в 0s.

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.

Смежные вопросы