MySQL "ग्रुप बाय" और "ऑर्डर बाय"


97

मैं ई-मेल की तालिका से पंक्तियों के एक समूह का चयन करने में सक्षम होना चाहता हूं और प्रेषक से उन्हें समूहित कर सकता हूं। मेरी क्वेरी इस तरह दिखती है:

SELECT 
    `timestamp`, `fromEmail`, `subject`
FROM `incomingEmails` 
GROUP BY LOWER(`fromEmail`) 
ORDER BY `timestamp` DESC

क्वेरी लगभग काम करती है जैसा मैं चाहता हूं - यह ई-मेल द्वारा वर्गीकृत रिकॉर्ड का चयन करता है। समस्या यह है कि विषय और टाइमस्टैम्प किसी विशेष ई-मेल पते के लिए सबसे हाल के रिकॉर्ड के अनुरूप नहीं हैं।

उदाहरण के लिए, यह वापस आ सकता है:

fromEmail: john@example.com, subject: hello
fromEmail: mark@example.com, subject: welcome

जब डेटाबेस में रिकॉर्ड हैं:

fromEmail: john@example.com, subject: hello
fromEmail: john@example.com, subject: programming question
fromEmail: mark@example.com, subject: welcome

यदि "प्रोग्रामिंग प्रश्न" विषय सबसे हाल ही में है, तो ई-मेल को समूहीकृत करते समय मैं उस रिकॉर्ड का चयन करने के लिए MySQL कैसे प्राप्त कर सकता हूं?

जवाबों:


140

एक सरल उपाय यह है कि क्वेरी को पहले आदेश में विवरण के साथ लपेटें और बाद में ग्रुप को लागू करें :

SELECT * FROM ( 
    SELECT `timestamp`, `fromEmail`, `subject`
    FROM `incomingEmails` 
    ORDER BY `timestamp` DESC
) AS tmp_table GROUP BY LOWER(`fromEmail`)

यह ज्वाइन का उपयोग करने के समान है लेकिन बहुत अच्छा लगता है।

किसी समूह द्वारा खंड के साथ चयन में गैर-कुल कॉलम का उपयोग करना गैर-मानक है। MySQL आम तौर पर पहली पंक्ति के मूल्यों को वापस लौटाता है जो इसे पाता है और बाकी को छोड़ देता है। किसी भी आदेश द्वारा खंड केवल लौटाए गए स्तंभ मान पर लागू होगा, त्यागने वालों के लिए नहीं।

महत्वपूर्ण अद्यतन अभ्यास में काम करने के लिए उपयोग किए जाने वाले गैर-कुल स्तंभों का चयन करना, लेकिन उन पर भरोसा नहीं किया जाना चाहिए। प्रति MySQL प्रलेखन "इस उपयोगी है। मुख्य रूप से जब ग्रुप द्वारा में नामित नहीं प्रत्येक nonaggregated स्तंभ में सभी मान प्रत्येक समूह के लिए ही कर रहे हैं सर्वर है किसी भी मूल्य चुनने के लिए स्वतंत्र प्रत्येक समूह से है, इसलिए जब तक वे एक ही हैं, मूल्यों चुने गए अनिश्चित हैं । "

के रूप में 5.7.5 ONLY_FULL_GROUP_BY डिफ़ॉल्ट तो गैर कुल कॉलम क्वेरी त्रुटियाँ कारण (ER_WRONG_FIELD_WITH_GROUP) से सक्षम है

जैसा कि समाधान के नीचे @mikep इंगित करता है कि 5.7 और ऊपर से Any_VALUE () का उपयोग करना है

Http://www.cafewebmaster.com/mysql-order-sort-group https://dev.mysql.com/doc/refman/5.6/en/group-by-handling.html https: //dev.mysql देखें .com / doc / RefMan / 5.7 / en / समूह-दर-handling.html https://dev.mysql.com/doc/refman/5.7/en/miscellaneous-functions.html#function_any-value


7
मैं कुछ साल पहले इसी समाधान के साथ आया था, और इसका एक बड़ा समाधान था। kudos to b7kich हालांकि यहाँ दो मुद्दे ... GROUP BY मामला असंवेदनशील है इसलिए LOWER () अनावश्यक है, और दूसरा, $ userID PHP से सीधे एक चर प्रतीत होता है, यदि आपका user उपयोगकर्ता-प्रदत्त है और मजबूर नहीं किया गया तो आपका कोड sql इंजेक्शन असुरक्षित हो सकता है। पूर्णांक होना
वेलक्रॉस

महत्वपूर्ण अद्यतन मारियाडीबी
आर्थर शिपकोस्की

1
As of 5.7.5 ONLY_FULL_GROUP_BY is enabled by default, i.e. it's impossible to use non-aggregate columns.SQL मोड को बिना व्यवस्थापक विशेषाधिकारों के रनटाइम के दौरान बदला जा सकता है, इसलिए ONLY_FULL_GROUP_BY को अक्षम करना बहुत आसान है। उदाहरण के लिए SET SESSION sql_mode = '';:। डेमो: db-fiddle.com/f/esww483qFQXbXzJmkHZ8VT/3
mikep

1
या सक्षम बायपास के लिए एक अन्य विकल्प ONLY_FULL_GROUP_BY किसी भी_VALUE () का उपयोग करना है। अधिक देखें dev.mysql.com/doc/refman/8.0/en/...
mikep

42

यहाँ एक दृष्टिकोण है:

SELECT cur.textID, cur.fromEmail, cur.subject, 
     cur.timestamp, cur.read
FROM incomingEmails cur
LEFT JOIN incomingEmails next
    on cur.fromEmail = next.fromEmail
    and cur.timestamp < next.timestamp
WHERE next.timestamp is null
and cur.toUserID = '$userID' 
ORDER BY LOWER(cur.fromEmail)

मूल रूप से, आप बाद की पंक्तियों को खोजते हुए, स्वयं ही तालिका से जुड़ जाते हैं। उस खंड में जहाँ आप कहते हैं कि बाद की पंक्तियाँ नहीं हो सकती हैं। यह आपको केवल नवीनतम पंक्ति देता है।

यदि एक ही टाइमस्टैम्प के साथ कई ईमेल हो सकते हैं, तो इस क्वेरी को परिष्कृत करने की आवश्यकता होगी। यदि ईमेल तालिका में एक वृद्धिशील आईडी स्तंभ है, तो JOIN बदलें:

LEFT JOIN incomingEmails next
    on cur.fromEmail = next.fromEmail
    and cur.id < next.id

कहा कि textIDअस्पष्ट था / /
जॉन कुरलक

1
फिर अम्बिगिटी को हटा दें और इसे टेबल नाम से उपसर्ग करें, जैसे cur.textID। जवाब में भी बदला।
एंडोमर

यह एकमात्र समाधान है जो डॉक्ट्रीन डीक्यूएल के साथ करना संभव है।
VisioN

यह तब काम नहीं करता है जब आप कई कॉलमों में शामिल होने की कोशिश कर रहे हैं। IE जब आप नवीनतम ईमेल और नवीनतम उपयोगकर्ता नाम खोजने की कोशिश कर रहे हैं और आपको एक ही क्वेरी में इस ऑपरेशन को करने के लिए कई स्व-बाएं जोड़ों की आवश्यकता होती है।
लवेन डायल

अतीत और भविष्य के टाइमस्टैम्प्स / तारीखों के साथ काम करते हुए, परिणामी को गैर-भविष्य की तारीखों तक सीमित करने के लिए, आपको LEFT JOINमापदंड में एक और शर्त जोड़ने की जरूरत हैAND next.timestamp <= UNIX_TIMESTAMP()
fyrye

32

जैसा कि पहले से ही एक उत्तर में कहा गया है, वर्तमान उत्तर गलत है, क्योंकि ग्रुप बाय मनमाने ढंग से खिड़की से रिकॉर्ड का चयन करता है।

यदि कोई MySQL 5.6, या MySQL 5.7 का उपयोग कर रहा है ONLY_FULL_GROUP_BY, तो सही (निर्धारक) क्वेरी है:

SELECT incomingEmails.*
  FROM (
    SELECT fromEmail, MAX(timestamp) `timestamp`
    FROM incomingEmails
    GROUP BY fromEmail
  ) filtered_incomingEmails
  JOIN incomingEmails USING (fromEmail, timestamp)
GROUP BY fromEmail, timestamp

क्वेरी को कुशलतापूर्वक चलाने के लिए, उचित अनुक्रमण की आवश्यकता होती है।

ध्यान दें कि सरलीकरण उद्देश्यों के लिए, मैंने इसे हटा दिया है LOWER(), जो ज्यादातर मामलों में उपयोग नहीं किया जाएगा।


2
यह सही उत्तर होना चाहिए। मैंने बस इसी से संबंधित अपनी वेबसाइट पर एक बग की खोज की। order byअन्य उत्तर में सबसिलेक्ट में, सब पर कोई प्रभाव नहीं है।
जेट

1
OMG, कृपया इसे स्वीकृत उत्तर दें। स्वीकृत समय ने मेरा 5 घंटे बर्बाद कर दिया :(
रिचर्ड किर्सी

29

ORDER के बाद एक ग्रुप को इस तरह से ग्रुप के साथ अपनी क्वेरी लपेटकर करें:

SELECT t.* FROM (SELECT * FROM table ORDER BY time DESC) t GROUP BY t.from

1
तो ग्रुप BY` स्वचालित रूप से नवीनतम time, या नवीनतम time, या यादृच्छिक का चयन करता है ?
xrDDDD

1
यह सबसे नए समय का चयन करता है क्योंकि हम इसके द्वारा आदेश दे रहे हैं time DESCऔर फिर समूह पहले वाला (नवीनतम) लेता है।
11101101 बी

अब अगर केवल मैं MySQL 5.1 में VIEWS में उप-चयन पर JOINS कर सकता था। हो सकता है कि वह सुविधा एक नए रिलीज़ में आए।
इकारसएनएम

21

SQL मानक के अनुसार आप चुनिंदा सूची में गैर-कुल कॉलम का उपयोग नहीं कर सकते हैं। MySQL इस तरह के उपयोग (केवल ONLY_FULL_GROUP_BY मोड का उपयोग करता है) की अनुमति देता है, लेकिन परिणाम अनुमानित नहीं है।

ONLY_FULL_GROUP_BY

आपको पहले ई-मेल, MIN (पढ़ें), और फिर दूसरी क्वेरी (या सबक्वेरी) - विषय के साथ चयन करना चाहिए।


MIN (पढ़ें) "रीड" का न्यूनतम मान लौटाएगा। वह शायद इसके बजाय नवीनतम ईमेल के "पढ़ा" ध्वज की तलाश कर रहा है।
एंडोमर

2

मैंने दिखाए गए लोगों की तुलना में अधिक जटिल प्रश्नों के लिए इन दोनों दृष्टिकोणों के साथ संघर्ष किया, क्योंकि सबक्वेरी दृष्टिकोण बुरी तरह से अक्षम था, चाहे मैं कोई भी सूचकांक डालूं, और क्योंकि मैं हाइबरनेट के माध्यम से बाहरी स्व-जुड़ नहीं पा रहा था

ऐसा करने के लिए सबसे अच्छा (और सबसे आसान) तरीका कुछ द्वारा समूहित करना है जो आपके द्वारा आवश्यक फ़ील्ड का एक संयोजन शामिल करने के लिए बनाया गया है और फिर चयन खंड में अभिव्यक्तियों का उपयोग करके उन्हें बाहर निकालने के लिए है। यदि आपको MAX () करने की आवश्यकता है, तो सुनिश्चित करें कि आप जिस क्षेत्र में MAX () पर चाहते हैं वह हमेशा संक्षिप्त इकाई के सबसे महत्वपूर्ण छोर पर है।

इसे समझने की कुंजी यह है कि क्वेरी केवल तभी समझ में आती है जब ये अन्य क्षेत्र किसी भी इकाई के लिए अपरिवर्तनीय होते हैं जो अधिकतम () को संतुष्ट करता है, इसलिए सॉर्ट के संदर्भ में दूसरे टुकड़े को अनदेखा किया जा सकता है। यह बताता है कि इस लिंक के बहुत नीचे कैसे करें। http://dev.mysql.com/doc/refman/5.0/en/group-by-hidden-columns.html

यदि आप सम्मिलित कर सकते हैं / अद्यतन करने की घटना (एक ट्रिगर की तरह) के लिए आप इसे अनुक्रमित कर सकते हैं क्षेत्रों के संघनन पूर्व गणना करने के लिए और क्वेरी के रूप में उपवास के रूप में अगर आप वास्तव में अधिकतम करना चाहते थे फ़ील्ड से बस के रूप में होगा (है) )। तुम भी कई क्षेत्रों की अधिकतम प्राप्त करने के लिए इसका इस्तेमाल कर सकते हैं। मैं इसका उपयोग नेस्टेड सेट के रूप में व्यक्त बहुआयामी पेड़ों के खिलाफ प्रश्न करने के लिए करता हूं।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.