sql >> データベース >  >> RDS >> Mysql

GROUP_BYの2つのLEFTJOINのGROUP_CONCATからの奇妙な重複動作

    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をスカラーサブクエリ として選択します それぞれにGROUPBYがあります。

    正しい累積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 ;
    



    1. T-SQLで文字列の先頭または末尾のスペースを削除する方法

    2. 列のコンマ区切り値をSQLServerの複数の行に分割する

    3. PythonMySQLコネクタ-fetchoneの使用時に未読の結果が見つかりました

    4. ORA-00936:式oracleがありません