Mysql
 sql >> Database >  >> RDS >> Mysql

Difficoltà a ottenere il conteggio corretto con un join

Penso che l'approccio più diretto a ciò che stai tentando di fare sia utilizzare solo sottoquery correlate.

Quindi, il primo esempio appena sotto restituisce i risultati che stai cercando . Potresti facilmente modificarlo per escludere le file con zero goal e assist.

Utilizza il valore team_id in ogni sottoquery, ma puoi fornirlo con una variabile o un parametro, come mostrato, in modo che tu debba specificare il valore solo una volta:

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

Per la squadra 1:

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

Per la squadra 2:

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

Per la squadra 3:

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

Epilogo

Dal punto di vista del tentativo di eseguire questa operazione con meno sottoquery e/o con query aggregate, si verificano un paio di problemi con il primo tentativo.

Un problema è che la tua query probabilmente non funzionerà correttamente se non includi tutti i campi nel tuo group by clausola anche se MySQL non si lamenterà di questo come (la maggior parte?) di altri database.

Inoltre, poiché i record nelle tabelle degli assist e dei giocatori sono solo indirettamente correlati alle squadre tramite la tabella dei goal, è piuttosto difficile ottenere un rollup indipendente su entrambi i goal e sugli assist con una sola query.

A titolo di esempio, altre prime risposte a questo, incluso il mio primo colpo veloce, hanno avuto un paio di problemi:

  • Se un giocatore aveva assist per una squadra, ma non aveva obiettivi per quella squadra, le query non potevano restituire alcun risultato per quella combinazione di giocatore e squadra. I risultati erano incompleti.

  • Se un giocatore aveva gol per una squadra, ma non aveva assist per quella squadra, le query avrebbero comunque restituito un numero positivo per gli assist quando avrebbero dovuto restituire zero. I risultati erano effettivamente errati, non solo incompleti .

Appena sotto c'è una soluzione leggermente più corretta, ma ancora incompleta. Indica correttamente se un giocatore non ha assist, anche se restituendo null anziché 0, il che è sfortunato.

Ma è ancora una soluzione parziale perché se un giocatore non ha obiettivi per una squadra, non vedrai comunque alcun assist per quel giocatore e la combinazione di squadra.

Questo utilizza una sottoquery come tabella virtuale che aggrega gli assist per giocatore e squadra, e l'outer join sinistro alla sottoquery è ciò che fa restituire un risultato se ci sono goal, ma nessun assist.

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

Quella query restituisce questi risultati:

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

Esegui questo per la squadra 2 e otterrai questi risultati successivi, indicando che Lemieux non ha assist per la squadra 2, ma non restituisce alcun risultato per gli altri due giocatori, che non hanno assist né gol per la squadra 2:

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

Infine, eseguilo per la squadra 3 e otterrai questi risultati successivi, indicando che Messier non ha assist per la squadra 3. Ma manca Gretzky, anche se ha un assist per la squadra 3, perché non ha qualsiasi obiettivo per il team 3. Quindi la soluzione non è completa:

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