Sua segunda consulta é da 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
Os GROUP BYs internos resultam em
(user_id, t.tag)
&(user_id, c.category)
sendo chaves/UNIQUEs. Fora isso, não vou abordar esses GROUP BYs. TL;DR Quando você junta (q1 JOIN q2) a q3 não está em uma chave/UNIQUE de um deles, então para cada user_id você obtém uma linha para cada combinação possível de tag e categoria. Portanto, o GROUP BY final insere duplicatas por (user_id, tag) e por (user_id, category) e GROUP_CONCATs duplicam inadequadamente tags e categorias por user_id. Correto seria (q1 JOIN q2 GROUP BY) JOIN (q1 JOIN q3 GROUP BY) em que todas as junções estão na chave comum/UNIQUE
(user_id)
&não há agregação espúria. Embora às vezes você possa desfazer essa agregação espúria. Uma abordagem INNER JOIN simétrica correta:LEFT JOIN q1 &q2--1:many--então GROUP BY &GROUP_CONCAT (que é o que sua primeira consulta fez); então separadamente da mesma forma LEFT JOIN q1 &q3--1:many--então GROUP BY &GROUP_CONCAT; então INNER JOIN os dois resultados ON user_id--1:1.
Uma abordagem de subconsulta escalar simétrica correta:SELECIONE os GROUP_CONCATs de q1 como subconsultas escalares cada um com um GROUP BY.
Uma abordagem LEFT JOIN cumulativa correta:LEFT JOIN q1 &q2--1:muitos--então GROUP BY &GROUP_CONCAT; então LEFT JOIN que &q3--1:many--então GROUP BY &GROUP_CONCAT.
Uma abordagem correta como sua segunda consulta:você primeiro LEFT JOIN q1 &q2--1:many. Então você LEFT JOIN que &q3--many:1:many. Ele fornece uma linha para cada combinação possível de uma tag e uma categoria que aparecem com um user_id. Então, depois de GROUP BY, você GROUP_CONCAT - sobre pares duplicados (user_id, tag) e pares duplicados (user_id, category). É por isso que você tem elementos de lista duplicados. Mas adicionar DISTINCT a GROUP_CONCAT fornece um resultado correto. (Por wchiquito comentário de.)
O que você prefere é, como de costume, uma compensação de engenharia para ser informado por planos e horários de consulta, por dados/uso/estatísticas reais. entrada e estatísticas para quantidade esperada de duplicação), tempo de consultas reais, etc. Um problema é se as linhas extras da abordagem muitos:1:muitos JOIN compensam o salvamento de um 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 ;