Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

Problemas para obter a contagem correta com uma junção


Acho que a abordagem mais direta para o que você está tentando fazer é usar apenas subconsultas correlacionadas.

Então, o primeiro exemplo logo abaixo retorna os resultados que você está procurando . Você pode modificá-lo facilmente para excluir as linhas com zero gols e assistências.

Ele usa o valor team_id em cada subconsulta, mas você pode fornecer isso com uma variável ou parâmetro, conforme mostrado, para que você só precise especificar o valor uma vez:
set @team_id := 2;

select
    p.id as player_id
    , p.last_name
    , (
        select count(*)
        from goals
        where player_id = p.id
        and team_id = @team_id
    ) as goals
    , (
        select count(*)
        from assists
        inner join goals on assists.goal_id = goals.id
        where assists.player_id = p.id
        and goals.team_id = @team_id
    ) as assists
from players p

Para a equipe 1:
+----+-----------+-------+---------+
| id | last_name | Goals | Assists |
+----+-----------+-------+---------+
|  1 | Gretzky   |     2 |       1 |
|  2 | Lemieux   |     0 |       0 |
|  3 | Messier   |     1 |       1 |
+----+-----------+-------+---------+

Para a equipe 2:
+----+-----------+-------+---------+
| id | last_name | Goals | Assists |
+----+-----------+-------+---------+
|  1 | Gretzky   |     0 |       0 |
|  2 | Lemieux   |     1 |       0 |
|  3 | Messier   |     0 |       0 |
+----+-----------+-------+---------+

Para a equipe 3:
+----+-----------+-------+---------+
| id | last_name | Goals | Assists |
+----+-----------+-------+---------+
|  1 | Gretzky   |     0 |       1 |
|  2 | Lemieux   |     0 |       0 |
|  3 | Messier   |     1 |       0 |
+----+-----------+-------+---------+

Epílogo

Da perspectiva de tentar fazer isso com menos subconsultas e/ou com consultas agregadas, você tem alguns problemas em sua primeira tentativa.

Um problema é que sua consulta provavelmente não funcionará corretamente se você não incluir todos os campos em seu group by cláusula mesmo que o MySQL não irá reclamar com você sobre isso como (a maioria?) outros bancos de dados irão.

Além disso, como os registros em suas tabelas de assistências e de jogadores estão apenas indiretamente relacionados às equipes por meio da tabela de gols, é muito difícil obter um acúmulo independente de gols e assistências com apenas uma consulta.

Como uma espécie de ilustração, outras respostas iniciais para isso, incluindo minha primeira tentativa rápida, tiveram alguns problemas:

  • Se um jogador teve assistências para uma equipe, mas não teve nenhum objetivo para essa equipe, as consultas não poderiam retornar nenhum resultado para essa combinação de jogador e equipe. Os resultados foram incompletos.

  • Se um jogador tivesse gols para um time, mas não tivesse assistências para aquele time, as consultas ainda retornariam um número positivo de assistências quando deveriam ter retornado zero. Os resultados estavam realmente errados, não apenas incompletos .

Logo abaixo está uma solução um pouco mais correta, mas ainda incompleta. Indica corretamente se um jogador não tem assistências, embora retornando nulo em vez de 0, o que é lamentável.

Mas ainda é uma solução parcial, porque se um jogador não tiver nenhum objetivo para um time, você ainda não verá nenhuma assistência para essa combinação de jogador e time.

Isso usa uma subconsulta como uma tabela virtual que agrega assistências por jogador e equipe, e a junção externa esquerda à subconsulta é o que faz com que ela retorne um resultado se houver gols, mas nenhuma assistência.
select
    p.id as player_id
    , p.last_name
    , count(g.game_id) as goals
    , a.assists
from players p
inner join goals g on p.id = g.player_id
left join (
    select
        assists.player_id
        , goals.team_id
        , count(assists.id) as assists
    from assists
    inner join goals on assists.goal_id = goals.id
    group by player_id, team_id, assists.id
) a
on g.player_id = a.player_id and g.team_id = a.team_id
where g.team_id = 1
group by player_id, last_name, g.team_id

Essa consulta retorna estes resultados:
+----+-----------+-------+---------+
| id | last_name | Goals | Assists |
+----+-----------+-------+---------+
|  1 | Gretzky   |     2 |       1 |
|  3 | Messier   |     1 |       1 |
+----+-----------+-------+---------+

Execute isso para o time 2 e você obterá os próximos resultados, indicando que Lemieux não tem assistências para o time 2, mas não retorna nenhum resultado para os outros dois jogadores, que não têm assistências nem gols para o time 2:
+----+-----------+-------+---------+
| id | last_name | Goals | Assists |
+----+-----------+-------+---------+
|  2 | Lemieux   |     1 |    null |
+----+-----------+-------+---------+

Por fim, execute-o para o time 3 e você obterá os próximos resultados, indicando que Messier não tem assistências para o time 3. Mas Gretzky está ausente, embora tenha uma assistência para o time 3, porque ele não tem quaisquer metas para a equipe 3. Portanto, a solução não está completa:
+----+-----------+-------+---------+
| id | last_name | Goals | Assists |
+----+-----------+-------+---------+
|  3 | Messier   |     1 |    null |
+----+-----------+-------+---------+