Mysql
 sql >> डेटाबेस >  >> RDS >> Mysql

GROUP_BYs के दो बाएं जॉइन में से GROUP_CONCAT से अजीब डुप्लिकेट व्यवहार

आपकी दूसरी क्वेरी फ़ॉर्म की है:

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

आंतरिक GROUP BY का परिणाम (user_id, t.tag) होता है &(user_id, c.category) कुंजी/अद्वितीय होने के नाते। इसके अलावा मैं उन ग्रुप बाय को संबोधित नहीं करूंगा।

TL;DR जब आप (q1 JOIN q2) से q3 में शामिल होते हैं तो यह उनमें से किसी एक की कुंजी/अद्वितीय पर नहीं होता है, इसलिए प्रत्येक user_id के लिए आपको टैग और श्रेणी के हर संभावित संयोजन के लिए एक पंक्ति मिलती है। तो अंतिम ग्रुप बाय इनपुट डुप्लिकेट प्रति (user_id, टैग) और प्रति (user_id, श्रेणी) और अनुपयुक्त रूप से GROUP_CONCATs डुप्लिकेट टैग और श्रेणियां प्रति user_id। सही होगा (क्यू1 क्यू2 ग्रुप बाय से जुड़ें) जॉइन करें (क्यू1 क्यू3 ग्रुप बाय में शामिल हों) जिसमें सभी जॉइन कॉमन की/यूनिक (user_id) पर हों। और कोई नकली एकत्रीकरण नहीं है। हालांकि कभी-कभी आप ऐसे नकली एकत्रीकरण को पूर्ववत कर सकते हैं।

एक सही सममित INNER JOIN दृष्टिकोण:LEFT JOIN q1 और q2--1:कई - फिर GROUP BY और GROUP_CONCAT (जो आपकी पहली क्वेरी है); फिर अलग से इसी तरह LEFT JOIN q1 &q3--1:कई--फिर GROUP BY &GROUP_CONCAT; फिर user_id--1:1 पर दो परिणामों में शामिल हों।

एक सही सममित स्केलर सबक्वेरी दृष्टिकोण:q1 से GROUP_CONCATs को स्केलर सबक्वेरी के रूप में चुनें। प्रत्येक समूह के साथ।

एक सही संचयी LEFT JOIN दृष्टिकोण:LEFT JOIN q1 &q2--1:कई--फिर GROUP BY &GROUP_CONCAT; फिर बाएँ उसमें शामिल हों और q3--1:कई--फिर GROUP BY और GROUP_CONCAT।

आपकी दूसरी क्वेरी की तरह एक सही दृष्टिकोण:आप पहले q1 और q2--1:कई में शामिल हों। फिर आप उस और q3 में शामिल हों - कई:1:कई। यह एक टैग और एक श्रेणी के हर संभव संयोजन के लिए एक पंक्ति देता है जो एक user_id के साथ दिखाई देता है। फिर आपके द्वारा GROUP BY GROUP_CONCAT के बाद - डुप्लिकेट (user_id, टैग) जोड़े और डुप्लिकेट (user_id, श्रेणी) जोड़े पर। यही कारण है कि आपके पास डुप्लिकेट सूची तत्व हैं। लेकिन DISTINCT को GROUP_CONCAT में जोड़ने से सही परिणाम मिलता है। (प्रति wchiquito की टिप्पणी।)

जो आप पसंद करते हैं वह सामान्य रूप से एक इंजीनियरिंग ट्रेडऑफ़ है जिसे वास्तविक डेटा/उपयोग/सांख्यिकी के अनुसार क्वेरी योजनाओं और समय द्वारा सूचित किया जाना है। दोहराव की अपेक्षित मात्रा के लिए इनपुट और आंकड़े), वास्तविक प्रश्नों का समय, आदि। एक मुद्दा यह है कि क्या कई की अतिरिक्त पंक्तियां:1:कई जॉइन दृष्टिकोण ग्रुप बाय की बचत को ऑफसेट करते हैं।

-- 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. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. MySQL - कॉलम को पंक्तियों में अनपिवट कैसे करें?

  2. समय () उदाहरण – MySQL

  3. उपयोगकर्ता खाता प्रबंधन, भूमिकाएं, अनुमतियां, प्रमाणीकरण PHP और MySQL - भाग 6

  4. MySQL डेटाबेस में लिंक की गई सूची लाई जा रही है

  5. टेबल्स को लॉक किए बिना MySQLDump चलाएँ