La tua seconda domanda è della forma:
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
I GROUP BY interni risultano in (user_id, t.tag)
&(user_id, c.category)
essere chiavi/UNICI. A parte questo, non affronterò quei GROUP BY.
TL;DR Quando ti unisci (q1 JOIN q2) a q3 non è su una chiave/UNIQUE di uno di essi, quindi per ogni user_id ottieni una riga per ogni possibile combinazione di tag e categoria. Quindi l'ultimo GROUP BY immette duplicati per (user_id, tag) e per (user_id, categoria) e in modo inappropriato GROUP_CONCAT duplicano tag e categorie per user_id. Corretto sarebbe (q1 JOIN q2 GROUP BY) JOIN (q1 JOIN q3 GROUP BY) in cui tutti i join sono su chiave comune/UNIQUE (user_id)
&non c'è aggregazione spuria. Anche se a volte puoi annullare tale aggregazione spuria.
Un corretto approccio simmetrico INNER JOIN:LEFT JOIN q1 e q2--1:molti--quindi GROUP BY &GROUP_CONCAT (che è ciò che ha fatto la tua prima query); quindi separatamente allo stesso modo LEFT JOIN q1 &q3--1:molti--quindi GROUP BY &GROUP_CONCAT; quindi INNER UNISCI i due risultati su user_id--1:1.
Un approccio di sottoquery scalare simmetrico corretto:SELEZIONA i GROUP_CONCAT da q1 come sottoquery scalari ognuno con un GROUP BY.
Un corretto approccio cumulativo LEFT JOIN:LEFT JOIN q1 e q2--1:molti--quindi GROUP BY &GROUP_CONCAT; quindi SINISTRA UNISCITI a quello &q3--1:molti--quindi GROUP BY &GROUP_CONCAT.
Un approccio corretto come la tua seconda query:prima LEFT JOIN q1 &q2--1:many. Quindi HAI LASCIATO UNISCITI a quello &q3--many:1:many. Fornisce una riga per ogni possibile combinazione di un tag e una categoria che appare con un user_id. Quindi, dopo aver GROUP BY, GROUP_CONCAT - su coppie duplicate (id_utente, tag) e coppie duplicate (id_utente, categoria). Ecco perché hai elementi di elenco duplicati. Ma l'aggiunta di DISTINCT a GROUP_CONCAT fornisce un risultato corretto. (Per wchiquito commento di.)
Quello che preferisci è come al solito un compromesso ingegneristico per essere informato da piani e tempi di query, per dati/utilizzo/statistiche effettivi. input e statistiche per la quantità prevista di duplicazione), tempi delle query effettive, ecc. Un problema è se le righe extra dell'approccio many:1:many JOIN compensano il salvataggio di un GROUP BY.
-- 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 ;