Ihre zweite Abfrage hat folgende Form:
q1 -- PK user_id
LEFT JOIN (...
GROUP BY user_id, t.tag
) AS q2
ON q2.user_id = q1.user_id
LEFT JOIN (...
GROUP BY user_id, c.category
) AS q3
ON q3.user_id = q1.user_id
GROUP BY -- group_concats
Die inneren GROUP BYs ergeben (user_id, t.tag)
&(user_id, c.category)
Schlüssel/UNIQUES sein. Abgesehen davon werde ich diese GROUP BYs nicht ansprechen.
TL;DR Wenn Sie (q1 JOIN q2) mit q3 verbinden, ist es nicht auf einem Schlüssel/UNIQUE von einem von ihnen, also erhalten Sie für jede user_id eine Zeile für jede mögliche Kombination aus Tag und Kategorie. Die endgültigen GROUP BY-Eingaben duplizieren also pro (Benutzer-ID, Tag) und pro (Benutzer-ID, Kategorie) und in unangemessener Weise GROUP_CONCATs doppelte Tags und Kategorien pro Benutzer-ID. Richtig wäre (q1 JOIN q2 GROUP BY) JOIN (q1 JOIN q3 GROUP BY) wobei alle Joins auf gemeinsamen Schlüssel/UNIQUE (user_id)
sind &es gibt keine falsche Aggregation. Obwohl Sie manchmal eine solche falsche Aggregation rückgängig machen können.
Ein korrekter symmetrischer INNER JOIN-Ansatz:LEFT JOIN q1 &q2--1:many--dann GROUP BY &GROUP_CONCAT (was Ihre erste Abfrage getan hat); dann getrennt ähnlich LEFT JOIN q1 &q3--1:many--dann GROUP BY &GROUP_CONCAT; dann INNER JOIN die beiden Ergebnisse ON user_id--1:1.
Ein korrekter Ansatz für symmetrische skalare Unterabfragen:WÄHLEN Sie die GROUP_CONCATs aus q1 als skalare Unterabfragen aus jeweils mit einem GROUP BY.
Ein korrekter kumulativer LEFT JOIN-Ansatz:LEFT JOIN q1 &q2--1:many--then GROUP BY &GROUP_CONCAT; dann LEFT JOIN that &q3--1:many--dann GROUP BY &GROUP_CONCAT.
Ein korrekter Ansatz wie Ihre 2. Abfrage:Sie zuerst LEFT JOIN q1 &q2--1:many. Dann LINKS VERBINDEN Sie das &q3--viele:1:viele. Es gibt eine Zeile für jede mögliche Kombination aus einem Tag und einer Kategorie, die mit einer user_id erscheinen. Dann, nachdem Sie GROUP BY Sie GROUP_CONCAT--über doppelte (Benutzer-ID, Tag) Paare und doppelte (Benutzer-ID, Kategorie) Paare. Deshalb haben Sie doppelte Listenelemente. Das Hinzufügen von DISTINCT zu GROUP_CONCAT ergibt jedoch ein korrektes Ergebnis. (Gemäß wchiquito Kommentar von .)
Was Sie bevorzugen, ist wie üblich ein technischer Kompromiss, der durch Abfragepläne und -zeiten nach tatsächlichen Daten/Nutzung/Statistiken informiert wird. Input &Statistiken für die erwartete Menge an Duplikaten), Timing der tatsächlichen Abfragen usw. Ein Problem ist, ob die zusätzlichen Zeilen des Many:1:many JOIN-Ansatzes die Einsparung eines GROUP BY ausgleichen.
-- cumulative LEFT JOIN approach
SELECT
q1.user_id, q1.user_name, q1.score, q1.reputation,
top_two_tags,
substring_index(group_concat(q3.category ORDER BY q3.category_reputation DESC SEPARATOR ','), ',', 2) AS category
FROM
-- your 1st query (less ORDER BY) AS q1
(SELECT
q1.user_id, q1.user_name, q1.score, q1.reputation,
substring_index(group_concat(q2.tag ORDER BY q2.tag_reputation DESC SEPARATOR ','), ',', 2) AS top_two_tags
FROM
(SELECT
u.id AS user_Id,
u.user_name,
coalesce(sum(r.score), 0) as score,
coalesce(sum(r.reputation), 0) as reputation
FROM
users u
LEFT JOIN reputations r
ON r.user_id = u.id
AND r.date_time > 1500584821 /* unix_timestamp(DATE_SUB(now(), INTERVAL 1 WEEK)) */
GROUP BY
u.id, u.user_name
) AS q1
LEFT JOIN
(
SELECT
r.user_id AS user_id, t.tag, sum(r.reputation) AS tag_reputation
FROM
reputations r
JOIN post_tag pt ON pt.post_id = r.post_id
JOIN tags t ON t.id = pt.tag_id
WHERE
r.date_time > 1500584821 /* unix_timestamp(DATE_SUB(now(), INTERVAL 1 WEEK)) */
GROUP BY
user_id, t.tag
) AS q2
ON q2.user_id = q1.user_id
GROUP BY
q1.user_id, q1.user_name, q1.score, q1.reputation
) AS q1
-- finish like your 2nd query
LEFT JOIN
(
SELECT
r.user_id AS user_id, c.category, sum(r.reputation) AS category_reputation
FROM
reputations r
JOIN post_category ct ON ct.post_id = r.post_id
JOIN categories c ON c.id = ct.category_id
WHERE
r.date_time > 1500584821 /* unix_timestamp(DATE_SUB(now(), INTERVAL 1 WEEK)) */
GROUP BY
user_id, c.category
) AS q3
ON q3.user_id = q1.user_id
GROUP BY
q1.user_id, q1.user_name, q1.score, q1.reputation
ORDER BY
q1.reputation DESC, q1.score DESC ;