Aby uprościć logikę, najpierw zagreguj, dołącz później.
Zgadując brakujące szczegóły, to zapytanie podałoby dokładną liczbę, ile razy każdy użytkownik był odwoływany w table1
i table2
odpowiednio dla wszystkich użytkowników :
SELECT *
FROM users u
LEFT JOIN (
SELECT updated_by_id AS id, count(*) AS t1_ct
FROM table1
GROUP BY 1
) t1 USING (id)
LEFT JOIN (
SELECT updated_by_id AS id, count(*) AS t2_ct
FROM table2
GROUP BY 1
) t2 USING (id);
W szczególności unikaj wielu relacji 1-n mnożących się nawzajem po połączeniu:
Aby pobrać jednego lub kilku użytkowników tylko, LATERAL
dołączania będą szybsze (Postgres 9.3+):
SELECT *
FROM users u
LEFT JOIN LATERAL (
SELECT count(*) AS t1_ct
FROM table1
WHERE updated_by_id = u.id
) ON true
LEFT JOIN LATERAL (
SELECT count(*) AS t2_ct
FROM table2
WHERE updated_by_id = u.id
) ON true
WHERE u.id = 100;
Wyjaśnij dostrzeżoną różnicę
Zgłoszona przez Ciebie konkretna niezgodność wynika ze specyfiki FULL OUTER JOIN
:
Tak więc otrzymujesz wartości NULL dołączone po odpowiedniej drugiej stronie za brakujące dopasowania. count()
nie liczy wartości NULL. Możesz więc uzyskać inny wynik w zależności od tego, czy filtrujesz według u1.id=100
lub u2.id=100
.
To tylko wyjaśnienie, nie potrzebujesz FULL JOIN
tutaj. Zamiast tego użyj przedstawionych alternatyw.