Mysql
 sql >> Base de données >  >> RDS >> Mysql

Problème pour obtenir un décompte correct avec une jointure

Je pense que l'approche la plus simple de ce que vous essayez de faire est d'utiliser simplement des sous-requêtes corrélées.

Ainsi, le premier exemple ci-dessous renvoie les résultats que vous recherchez . Vous pouvez facilement le modifier pour exclure les lignes avec zéro but et assistance.

Il utilise la valeur team_id dans chaque sous-requête, mais vous pouvez la fournir avec une variable ou un paramètre, comme indiqué, de sorte que vous n'ayez à spécifier la valeur qu'une seule fois :

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

Pour l'équipe 1 :

+----+-----------+-------+---------+
| id | last_name | Goals | Assists |
+----+-----------+-------+---------+
|  1 | Gretzky   |     2 |       1 |
|  2 | Lemieux   |     0 |       0 |
|  3 | Messier   |     1 |       1 |
+----+-----------+-------+---------+

Pour l'équipe 2 :

+----+-----------+-------+---------+
| id | last_name | Goals | Assists |
+----+-----------+-------+---------+
|  1 | Gretzky   |     0 |       0 |
|  2 | Lemieux   |     1 |       0 |
|  3 | Messier   |     0 |       0 |
+----+-----------+-------+---------+

Pour l'équipe 3 :

+----+-----------+-------+---------+
| id | last_name | Goals | Assists |
+----+-----------+-------+---------+
|  1 | Gretzky   |     0 |       1 |
|  2 | Lemieux   |     0 |       0 |
|  3 | Messier   |     1 |       0 |
+----+-----------+-------+---------+

Épilogue

Du point de vue d'essayer de le faire avec moins de sous-requêtes et/ou avec des requêtes agrégées, vous rencontrez quelques problèmes lors de votre première tentative.

Un problème est que votre requête ne fonctionnera probablement pas correctement si vous n'incluez pas tous les champs dans votre group by clause même si MySQL ne vous en voudra pas comme (la plupart?) D'autres bases de données le feront.

De plus, étant donné que les enregistrements de vos tableaux de passes décisives et de joueurs ne sont qu'indirectement liés aux équipes via le tableau des objectifs, il est assez difficile d'obtenir un cumul indépendant des buts et des passes décisives avec une seule requête.

À titre d'exemple, d'autres premières réponses à cela, y compris ma première tentative rapide, présentaient quelques problèmes :

  • Si un joueur avait des passes décisives pour une équipe, mais n'avait aucun but pour cette équipe, les requêtes ne pouvaient renvoyer aucun résultat pour cette combinaison de joueur et d'équipe. Les résultats étaient incomplets.

  • Si un joueur avait des buts pour une équipe, mais n'avait pas de passes décisives pour cette équipe, les requêtes renverraient toujours un nombre positif pour les passes décisives alors qu'elles auraient dû renvoyer zéro. Les résultats étaient en fait erronés, pas seulement incomplets .

Juste en dessous se trouve une solution un peu plus correcte, mais encore incomplète. Il indique correctement si un joueur n'a pas de passes décisives, mais en retournant null au lieu de 0, ce qui est malheureux.

Mais c'est toujours une solution partielle car si un joueur n'a pas d'objectifs pour une équipe, vous ne verrez toujours aucune aide pour cette combinaison de joueur et d'équipe.

Cela utilise une sous-requête comme table virtuelle qui regroupe les passes décisives par joueur et par équipe, et la jointure externe gauche à la sous-requête est ce qui lui permet de renvoyer un résultat s'il y a des buts, mais pas de passes décisives.

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

Cette requête renvoie ces résultats :

+----+-----------+-------+---------+
| id | last_name | Goals | Assists |
+----+-----------+-------+---------+
|  1 | Gretzky   |     2 |       1 |
|  3 | Messier   |     1 |       1 |
+----+-----------+-------+---------+

Exécutez ceci pour l'équipe 2, et vous obtenez ces résultats suivants, indiquant que Lemieux n'a aucune aide pour l'équipe 2, mais ne renvoyant aucun résultat pour les deux autres joueurs, qui n'ont aucune aide et aucun but pour l'équipe 2 :

+----+-----------+-------+---------+
| id | last_name | Goals | Assists |
+----+-----------+-------+---------+
|  2 | Lemieux   |     1 |    null |
+----+-----------+-------+---------+

Enfin, exécutez-le pour l'équipe 3, et vous obtenez ces résultats suivants, indiquant que Messier n'a pas de passes décisives pour l'équipe 3. Mais Gretzky est absent, même s'il a une passe décisive pour l'équipe 3, car il n'a pas tous les objectifs pour l'équipe 3. La solution n'est donc pas complète :

+----+-----------+-------+---------+
| id | last_name | Goals | Assists |
+----+-----------+-------+---------+
|  3 | Messier   |     1 |    null |
+----+-----------+-------+---------+