विशिष्ट कठिनाई यहां:SELECT
. में एक या अधिक समग्र फ़ंक्शन वाली क्वेरीज़ सूची और कोई GROUP BY
क्लॉज बिल्कुल एक पंक्ति उत्पन्न करता है, भले ही कोई पंक्ति न मिले अंतर्निहित तालिका में।
WHERE
. में आप कुछ नहीं कर सकते उस पंक्ति को दबाने के लिए खंड। तथ्य के बाद . आपको ऐसी पंक्ति को बाहर करना होगा , यानी HAVING
. में खंड, या किसी बाहरी प्रश्न में।
प्रति दस्तावेज़:
<ब्लॉकक्वॉट>
अगर किसी क्वेरी में कुल फ़ंक्शन कॉल हैं, लेकिन कोई GROUP BY
नहीं है खंड, समूहीकरण अभी भी होता है:परिणाम एक एकल समूह पंक्ति है (या शायद बिल्कुल भी नहीं है, यदि एकल पंक्ति को HAVING
द्वारा समाप्त कर दिया जाता है ) वही सच है अगर इसमें HAVING
. है क्लॉज, बिना किसी एग्रीगेट फंक्शन कॉल या GROUP BY
. के भी खंड।
यह ध्यान दिया जाना चाहिए कि GROUP BY
. जोड़ना केवल एक निरंतर अभिव्यक्ति के साथ खंड (जो अन्यथा पूरी तरह से व्यर्थ है!) भी काम करता है। नीचे उदाहरण देखें। लेकिन मैं उस तरकीब का उपयोग नहीं करना चाहूंगा, भले ही वह छोटी, सस्ती और सरल हो, क्योंकि यह शायद ही स्पष्ट है कि यह क्या करती है।
निम्न क्वेरी के लिए केवल एकल तालिका स्कैन की आवश्यकता है और गिनती के आधार पर क्रमित शीर्ष 7 श्रेणियां लौटाता है। अगर (और केवल तभी ) और भी श्रेणियां हैं, बाकी को 'अन्य' में संक्षेपित किया गया है:
WITH cte AS (
SELECT categoryid, count(*) AS data
, row_number() OVER (ORDER BY count(*) DESC, categoryid) AS rn
FROM contents
GROUP BY 1
)
( -- parentheses required again
SELECT categoryid, COALESCE(ca.name, 'Unknown') AS label, data
FROM cte
LEFT JOIN category ca ON ca.id = cte.categoryid
WHERE rn <= 7
ORDER BY rn
)
UNION ALL
SELECT NULL, 'Others', sum(data)
FROM cte
WHERE rn > 7 -- only take the rest
HAVING count(*) > 0; -- only if there actually is a rest
-- or: HAVING sum(data) > 0
-
यदि कई श्रेणियों की 7वीं/8वीं रैंक पर समान गणना हो सकती है, तो आपको संबंध तोड़ने की आवश्यकता है। मेरे उदाहरण में, छोटे
categoryid
. वाली श्रेणियां ऐसी दौड़ जीतें। -
कोष्ठक में
LIMIT
. शामिल करना आवश्यक है याORDER BY
एकUNION
. के एक व्यक्तिगत पैर के लिए खंड क्वेरी। -
आपको केवल तालिका
category
में शामिल होने की आवश्यकता है शीर्ष 7 श्रेणियों के लिए। और आम तौर पर पहले एकत्र करना और बाद में इस परिदृश्य में शामिल होना सस्ता होता है। इसलिएcte
नाम के CTE (कॉमन टेबल एक्सप्रेशन) में बेस क्वेरी में शामिल न हों , केवल पहलेSELECT
. में शामिल होंUNION
. का प्रश्न, यह सस्ता है। -
सुनिश्चित नहीं हैं कि आपको
COALESCE
की आवश्यकता क्यों है . अगर आपके पासcontents.categoryid
. से कोई विदेशी कुंजी है करने के लिएcategory.id
और दोनोंcontents.categoryid
औरcategory.name
परिभाषित हैंNOT NULL
(जैसे वे शायद होना चाहिए), तो आपको इसकी आवश्यकता नहीं है।
विषम GROUP BY true
यह भी काम करेगा:
...
UNION ALL
SELECT NULL , 'Others', sum(data)
FROM cte
WHERE rn > 7
GROUP BY true;
और मुझे थोड़ी तेज क्वेरी प्लान भी मिलते हैं। लेकिन यह एक अजीब हैक है...
एसक्यूएल फिडल सभी का प्रदर्शन।
UNION ALL
. के लिए अधिक स्पष्टीकरण के साथ संबंधित उत्तर / LIMIT
तकनीक:
- कुछ प्रश्नों के योग परिणाम और फिर SQL में शीर्ष 5 खोजें