Mysql
 sql >> Baza danych >  >> RDS >> Mysql

Problemy z uzyskaniem prawidłowej liczby przy łączeniu

Myślę, że najprostszym podejściem do tego, co próbujesz zrobić, jest użycie skorelowanych podzapytań.

Tak więc pierwszy przykład tuż poniżej zwraca wyniki, których szukasz . Możesz go łatwo zmodyfikować, aby wykluczyć wiersze z zerowymi golami i asystami.

Używa wartości team_id w każdym podzapytaniu, ale możesz podać ją ze zmienną lub parametrem, jak pokazano, więc wystarczy określić wartość tylko raz:

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

Dla zespołu 1:

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

Dla zespołu 2:

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

Dla zespołu 3:

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

Epilog

Z perspektywy próby zrobienia tego za pomocą mniejszej liczby podzapytań i/lub zapytań agregujących, przy pierwszej próbie pojawia się kilka problemów.

Jednym z problemów jest to, że zapytanie prawdopodobnie nie będzie działać poprawnie, jeśli nie uwzględnisz wszystkich pól w group by nawet jeśli MySQL nie będzie na ciebie narzekał, tak jak (większość?) innych baz danych.

Ponadto, ponieważ rekordy zarówno w tabelach asyst, jak i graczy są tylko pośrednio powiązane z drużynami w tabeli bramek, trudno jest uzyskać niezależne zestawienie obu bramek i asyst za pomocą tylko jednego zapytania.

Jako ilustracja, inne wczesne odpowiedzi na to, w tym moje pierwsze szybkie ujęcie, miały kilka problemów:

  • Jeśli zawodnik miał asysty dla drużyny, ale nie miał żadnych bramek dla tej drużyny, zapytania nie mogły zwrócić żadnych wyników dla tej kombinacji zawodnika i drużyny. Wyniki były niekompletne.

  • Jeśli gracz miał cele dla drużyny, ale nie miał asyst dla tej drużyny, zapytania nadal zwracałyby dodatnią liczbę dla asyst, podczas gdy powinien był zwrócić zero. Wyniki były w rzeczywistości błędne, a nie tylko niekompletne .

Tuż poniżej znajduje się nieco bardziej poprawne, ale wciąż niekompletne rozwiązanie. Prawidłowo wskazuje, czy gracz nie ma asyst, chociaż zwraca null zamiast 0, co jest niefortunne.

Ale nadal jest to częściowe rozwiązanie, ponieważ jeśli zawodnik nie ma żadnych celów dla drużyny, nadal nie zobaczysz żadnych asyst dla tej kombinacji zawodnika i drużyny.

Wykorzystuje to podzapytanie jako wirtualną tabelę, która agreguje asysty na gracza i drużynę, a lewe sprzężenie zewnętrzne do podzapytania sprawia, że ​​zwraca on wynik, jeśli są gole, ale nie ma asyst.

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

To zapytanie zwraca te wyniki:

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

Uruchom to dla drużyny 2, a otrzymasz kolejne wyniki, wskazujące, że Lemieux nie ma żadnych asyst dla drużyny 2, ale nie zwraca żadnych wyników dla pozostałych dwóch graczy, którzy nie mają asyst i bramek dla drużyny 2:

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

Na koniec uruchom go dla zespołu 3, a otrzymasz kolejne wyniki, wskazujące, że Messier nie ma żadnych asyst dla zespołu 3. Ale Gretzky'ego brakuje, mimo że ma asystę dla zespołu 3, ponieważ nie ma dowolne cele dla zespołu 3. Rozwiązanie nie jest więc kompletne:

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



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. MySQL wybierz dane rozdzielane

  2. Łącznik MySQL w języku Python — znaleziono nieprzeczytane wyniki podczas używania fetchone

  3. MySQL Update pierwsze wystąpienie rekordu

  4. Jak udostępnić jedno połączenie mysql między wieloma wątkami?

  5. Nie mogę zalogować się do lokalnej kopii Magento - jak użyć utraconego hasła z lokalną kopią oprogramowania?