2番目のクエリの形式は次のとおりです:
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
内部のGROUPBYは、(user_id, t.tag)
になります。 &(user_id, c.category)
キー/ユニークであること。それ以外は、それらのGROUPBYについては取り上げません。
TL; DR (q1 JOIN q2)をq3に結合すると、それらの1つのキー/ UNIQUEにないため、user_idごとに、タグとカテゴリの可能なすべての組み合わせの行を取得します。したがって、最後のGROUP BY入力は、(user_id、tag)ごとおよび(user_id、category)ごとに重複し、不適切にGROUP_CONCATはuser_idごとにタグおよびカテゴリを複製します。正しいのは、(q1 JOIN q2 GROUP BY)JOIN(q1 JOIN q3 GROUP BY)で、すべての結合が共通キー/ UNIQUE (user_id)
上にあります。 &偽の集計はありません。ただし、このような偽の集計を元に戻すことができる場合もあります。
正しい対称的なINNERJOINアプローチ:LEFT JOIN q1&q2--1:many--次に、GROUP BY&GROUP_CONCAT(これは最初のクエリが行ったことです)。次に、別々に同様にLEFT JOIN q1&q3--1:many--then GROUP BY&GROUP_CONCAT;次に、user_id--1:1で2つの結果を内部結合します。
正しい対称スカラーサブクエリアプローチ:q1からGROUP_CONCATを
正しい累積LEFTJOINアプローチ:LEFT JOIN q1&q2--1:many--then GROUP BY&GROUP_CONCAT;次に、LEFT JOIN that&q3--1:many--then GROUP BY&GROUP_CONCAT。
2番目のクエリのような正しいアプローチ:最初にq1とq2--1:manyに参加します。次に、その&q3--many:1:manyに参加します。これは、user_idとともに表示されるタグとカテゴリのすべての可能な組み合わせの行を提供します。次に、GROUP BYを実行した後、GROUP_CONCAT--重複(user_id、tag)ペアと重複(user_id、category)ペアを超えます。これが、リスト要素が重複している理由です。ただし、DISTINCTをGROUP_CONCATに追加すると、正しい結果が得られます。 (wchiquito ごと のコメント。)
どちらを選択するかは、通常どおり、実際のデータ/使用法/統計ごとに、クエリプランとタイミングによって通知されるエンジニアリングのトレードオフです。予想される重複量の入力と統計)、実際のクエリのタイミングなど。1つの問題は、many:1:manyJOINアプローチの余分な行がGROUPBYの節約を相殺するかどうかです。
-- 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 ;