2015-04-17 6 views
3

Я следующую структуру на моих таблицах MySQL:подсчета MySQL строк на нескольких сгруппированных столбцов

------------------------------------------- 
       Goal 
------------------------------------------- 
GoalID | GameID | ScorerID | AssistID 
------------------------------------------- 
    1   1   1   2 
    2   1   2   3 
    3   1   2   null 
    4   1   3   2 
    5   2   1   3 
    6   2   1   null 


---------------------- 
     Player 
---------------------- 
PlayerID | LastName 
---------------------- 
    1   AB  
    2   CD 
    3   EF 

теперь, что я хочу, чтобы достичь является следующее:

------------------------------------------- 
GameID | Player | Goals | Assists 
------------------------------------------- 
    1   AB   1   0 
    1   CD   2   2 
    1   EF   1   1 
    2   AB   2   0 
    2   EF   0   1 

Это то, что у меня есть пытался, но это дает мне неправильные результаты:

SELECT Goal.GoalID, 
    Goal.GameID, 
    COUNT(Scorer.PlayerID) AS Goals, 
    COUNT(Assist.PlayerID) AS Assists, 
    Player.LastName AS Player 
FROM Goal 
LEFT JOIN Player Player 
     ON Player.PlayerID = Goal.ScorerID 
     OR Player.PlayerID = Goal.AssistID 
LEFT JOIN Player Scorer 
     ON Scorer.PlayerID = Goal.ScorerID 
LEFT JOIN Player Assist 
     ON Assist.PlayerID = Goal.AssistID 
GROUP BY Player, 
     Goal.GameID 
ORDER BY Goal.GameID, 
     Goal.GoalID 

Я довольно уверен, что есть простой способ, чтобы получить результат, но я просто не могу обними мою голову.

ответ

3

Вы можете сделать это с помощью условной агрегации. Для этого вы присоединяетесь к таблицам игроков и целей при условии, что идентификатор игрока совпадает с scorerid или вспомогательным id, а затем получает SUM() ситуаций, когда идентификатор игрока находится в столбце оценки или помощи, и в конечном итоге группируется gameID и playerID. Например:

SELECT g.gameID, p.lastName AS Player, SUM(g.scorerID = p.playerID) AS goals, SUM(g.assistID = p.playerID) AS assists 
FROM goal g 
JOIN player p ON p.playerID = g.scorerID OR p.playerID = g.assistID 
GROUP BY g.gameID, p.playerID; 

Пример: SQL Fiddle.

Важно отметить, что в этом примере игрок имеет хотя бы одну цель или хотя бы одну помощь. Если вам нужны игроки, у которых их нет, вы можете использовать внешнее соединение.

+1

@StuartLC спасибо, я не знаю, что! К счастью, у ОП было только восемь строк, поэтому я надеюсь, что смогу набрать их вовремя, чтобы получить ответ:) – AdamMc331

+0

Выглядит хорошо ... что вы подразумеваете под «предполагает, что у игрока есть хотя бы одна цель или хотя бы одна помощь « – micadelli

+0

Если у вас есть игрок в таблице игроков, который вообще не отображается в таблице целей, они не будут возвращены моим запросом. Для этого вы можете просто изменить его из JOIN в RIGHT JOIN. – AdamMc331

0

Существует несколько способов решить эту проблему. Я считаю, что что-то подобное будет работать нормально:

SELECT 
    GameId, 
    Lastname, 
    Sum(Goals) as Goals, 
    Sum(Assists) as Assists 
FROM 
    (
     SELECT GameID, Player.Lastname, 1 as Goals, 0 as Assists 
     FROM Goal 
      INNER JOIN Player ON goal.scorerID = Player.PlayerID 

     UNION 

     SELECT GameID, Player.Lastname, 0 as Goals, 1 as Assists 
     FROM Goal 
      INNER JOIN Player ON goal.AssistID = Player.PlayerID 

    ) Games 
GROUP BY GameID, LastName 
0

Вот довольно простой способ для достижения этой цели:

select GameId, LastName, goals, assist 
from 
(
    select GameId, player, sum(goals) as goals, sum(assist) as assist 
    from 
    (
     select GameId, ScorerId as player, count(*) as goals, 0 as assist 
     from Goal 
     group by GameId, ScorerId 
     union all 
     select GameId, AssistId, 0 as goals, count(*) as assist 
     from Goal 
     where AssistId is not null 
     group by GameId, AssistId 
    ) as q 
    group by GameId, player 
) as q2 
inner join 
Player as t 
on (q2.player=t.PlayerId) 
order by GameId, LastName 

http://sqlfiddle.com/#!9/7b135a/5

1

Другим способом решения этой проблемы является CROSS JOIN игроков и целями, а также затем подсчитайте количество пересечений на Scorers и Assists с использованием карты CASE..WHEN. HAVING используется для устранения игроков, которые не внесли вклад в счет.

SELECT 
    Goal.GameID, 
    Player.LastName AS Player, 
    SUM(CASE WHEN Goal.ScorerId = Player.PlayerID THEN 1 ELSE 0 END) AS Goals, 
    SUM(CASE WHEN Goal.AssistId = Player.PlayerID THEN 1 ELSE 0 END) AS Assists 
FROM Goal 
CROSS JOIN Player 
GROUP BY Player.LastName, 
     Goal.GameID 
HAVING Goals > 0 OR Assists > 0 
ORDER BY Goal.GameID, 
     Player.LastName; 

SqlFiddle here

2

http://sqlfiddle.com/#!9/88479/7

SELECT g.GameID, 
    p.LastName, 
    SUM(IF(p.id=g.ScorerID,1,0)) as Goals, 
    SUM(IF(p.id=g.AssistID,1,0)) as Assists 
FROM goal g 
LEFT JOIN player p 
ON p.id = g.ScorerID 
    OR p.id = g.AssistID 
GROUP BY g.GameID,p.id 
+0

Хороший ответ, намного более чистый, чем наличие нескольких подзапросов и соединений. Просто комментарий, MySQL позволит вам выполнить 'SUM (условие)', чтобы получить подсчеты. Поэтому, если вы сказали 'SUM (p.id = g.scorerID)', он вернется так же, как 'SUM (IF (p.id = g.scorerID, 1,0))' – AdamMc331

+1

Согласен с вами. Это просто мой способ логики «a = b» return boolean в моем сознании, поэтому я просто делаю это, чтобы быть уверенным, какой тип «SUM» – Alex

+0

Конечно, я просто подумал, что упомянул об этом на случай, если вы не были знакомы с ним.В любое время, когда вы можете сохранить несколько ключевых штрихов для достижения того же результата, это хорошо для меня, ха-ха! – AdamMc331

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