LEFT JOIN
को ठीक करें
यह काम करना चाहिए:
SELECT o.name AS organisation_name, count(e.id) AS total_used
FROM organisations o
LEFT JOIN exam_items e ON e.organisation_id = o.id
AND e.item_template_id = #{sanitize(item_template_id)}
AND e.used
GROUP BY o.name
ORDER BY o.name;
आपके पास एक LEFT [OUTER] JOIN
. था लेकिन बाद में WHERE
शर्तों ने इसे एक सादे [INNER] JOIN
. की तरह काम करने के लिए बनाया है .
शर्तों को JOIN
. पर ले जाएं इसे इरादा के अनुसार काम करने के लिए खंड। इस तरह, केवल इन सभी शर्तों को पूरा करने वाली पंक्तियों को पहले स्थान पर जोड़ा जाता है (या दाएं से कॉलम) तालिका NULL से भरी हुई है)। जैसा कि आपके पास था, सम्मिलित पंक्तियों का वस्तुतः बाद . अतिरिक्त स्थितियों के लिए परीक्षण किया जाता है LEFT JOIN
और अगर वे पास नहीं होते हैं तो उन्हें हटा दिया जाता है, ठीक वैसे ही जैसे एक सादे JOIN
।
count()
शुरू करने के लिए कभी भी NULL नहीं लौटाता। यह इस संबंध में कुल कार्यों के बीच एक अपवाद है। इसलिए, <स्ट्राइक>COALESCE(COUNT(col))
स्ट्राइक> कभी नहीं अतिरिक्त मापदंडों के साथ भी समझ में आता है। मैनुअल:
यह ध्यान दिया जाना चाहिए कि count
को छोड़कर , जब कोई पंक्ति नहीं चुनी जाती है तो ये फ़ंक्शन एक शून्य मान लौटाते हैं।
बोल्ड जोर मेरा। देखें:
- उन विशेषताओं की संख्या गिनें जो एक पंक्ति के लिए NULL हैं
count()
परिभाषित कॉलम पर होना चाहिए NOT NULL
(जैसे e.id
), या जहां शामिल होने की स्थिति गारंटी देती है NOT NULL
(e.organisation_id
, e.item_template_id
, या e.used
) उदाहरण में।
चूंकि used
टाइप है boolean
, व्यंजक e.used = true
शोर है जो केवल e.used
. तक जल जाता है ।
चूंकि o.name
परिभाषित नहीं है UNIQUE NOT NULL
, आप GROUP BY o.id
. करना चाह सकते हैं इसके बजाय (id
पीके होने के नाते) - जब तक आप इरादा पंक्तियों को एक ही नाम (NULL सहित) से मोड़ने के लिए।
पहले एकत्र करें, बाद में शामिल हों
यदि exam_items
. की अधिकांश या सभी पंक्तियाँ प्रक्रिया में गिना जाता है, यह समकक्ष क्वेरी आमतौर पर काफी तेज/सस्ता होती है:
SELECT o.id, o.name AS organisation_name, e.total_used
FROM organisations o
LEFT JOIN (
SELECT organisation_id AS id -- alias to simplify join syntax
, count(*) AS total_used -- count(*) = fastest to count all
FROM exam_items
WHERE item_template_id = #{sanitize(item_template_id)}
AND used
GROUP BY 1
) e USING (id)
ORDER BY o.name, o.id;
(यह माना जा रहा है कि आप पंक्तियों को उसी नाम से मोड़ना नहीं चाहते हैं जैसा कि ऊपर बताया गया है - सामान्य मामला।)
अब हम तेज़ / सरल count(*)
. का उपयोग कर सकते हैं सबक्वेरी में, और हमें GROUP BY
. की आवश्यकता नहीं है बाहरी में SELECT
।
देखें:
- एक ही क्वेरी में कई array_agg() कॉल