क्वेरी को शायद सरल बनाया जा सकता है:
SELECT u.name AS user_name
, p.name AS project_name
, tl.created_on::date AS changeday
, coalesce(sum(nullif(new_value, '')::numeric), 0)
- coalesce(sum(nullif(old_value, '')::numeric), 0) AS hours
FROM users u
LEFT JOIN (
tasks t
JOIN fixins f ON f.id = t.fixin_id
JOIN projects p ON p.id = f.project_id
JOIN task_log_entries tl ON tl.task_id = t.id
AND tl.field_id = 18
AND (tl.created_on IS NULL OR
tl.created_on >= '2013-09-08' AND
tl.created_on < '2013-09-09') -- upper border!
) ON t.assignee_id = u.id
WHERE EXISTS (SELECT 1 FROM tasks t1 WHERE t1.assignee_id = u.id)
GROUP BY 1, 2, 3
ORDER BY 1, 2, 3;
यह उन सभी उपयोगकर्ताओं को लौटाता है जिनके पास कभी कोई कार्य था।
प्लस डेटा प्रति प्रोजेक्ट और दिन जहां डेटा निर्दिष्ट दिनांक सीमा में task_log_entries
. में मौजूद है .
प्रमुख बिंदु
-
एग्रीगेट फंक्शन
sum()
NULL
. पर ध्यान नहीं देता मूल्य।COALESCE()
प्रति पंक्ति जैसे ही आप गणना को दो राशियों के अंतर के रूप में पुन:व्यवस्थित करते हैं, इसकी अब आवश्यकता नहीं है:,coalesce(sum(nullif(new_value, '')::numeric), 0) - coalesce(sum(nullif(old_value, '')::numeric), 0) AS hours
हालांकि, अगर यह संभव है कि सभी चयन के कॉलम में
NULL
है या खाली स्ट्रिंग्स, योगों कोCOALESCE
. में लपेटें एक बार।
मैंnumeric
का उपयोग कर रहा हूंfloat
. के बजाय , गोलाई त्रुटियों को कम करने का सुरक्षित विकल्प। -
users
. के शामिल होने से अलग मान प्राप्त करने का आपका प्रयास औरtasks
व्यर्थ है, क्योंकि आपtasks
. में शामिल होते हैं एक बार और नीचे। पूरी क्वेरी को सरल और तेज़ बनाने के लिए समतल करें। -
ये स्थितीय संदर्भ केवल एक उल्लेखनीय सुविधा है:
GROUP BY 1, 2, 3 ORDER BY 1, 2, 3
... आपकी मूल क्वेरी के समान ही कर रहा है।
-
date
प्राप्त करने के लिएtimestamp
. से आप बसdate
. पर कास्ट कर सकते हैं :tl.created_on::date AS changeday
लेकिन
WHERE
. में मूल मानों के साथ परीक्षण करना बहुत बेहतर है खंड याJOIN
स्थिति (यदि संभव हो, और यह यहां संभव है), तो पोस्टग्रेज़ कॉलम पर सादे सूचकांकों का उपयोग कर सकते हैं (यदि उपलब्ध हो):AND (tl.created_on IS NULL OR tl.created_on >= '2013-09-08' AND tl.created_on < '2013-09-09') -- next day as excluded upper border
ध्यान दें कि एक तिथि शाब्दिक एक
timestamp
. में कनवर्ट किया जाता है पर00:00
दिन का आपके वर्तमान समय पर क्षेत्र . आपको अगला . चुनना होगा दिन और बहिष्कृत करें इसे ऊपरी सीमा के रूप में। या'2013-09-22 0:0 +2':: timestamptz
जैसा अधिक स्पष्ट टाइमस्टैम्प शाब्दिक प्रदान करें . ऊपरी सीमा को छोड़कर पर अधिक: -
आवश्यकता के लिए
every user who has ever been assigned to a task
WHERE
जोड़ें खंड:WHERE EXISTS (SELECT 1 FROM tasks t1 WHERE t1.assignee_id = u.id)
-
सबसे महत्वपूर्ण :ए
LEFT [OUTER] JOIN
शामिल होने के बाईं ओर सभी पंक्तियों को सुरक्षित रखता है। एकWHERE
जोड़ना दाएं . पर खंड तालिका इस प्रभाव को शून्य कर सकती है। इसके बजाय, फ़िल्टर एक्सप्रेशन कोJOIN
. पर ले जाएं खंड। अधिक स्पष्टीकरण यहाँ: -
कोष्ठक उस क्रम को बाध्य करने के लिए इस्तेमाल किया जा सकता है जिसमें टेबल शामिल हो गए हैं। सरल प्रश्नों के लिए शायद ही कभी आवश्यक हो, लेकिन इस मामले में बहुत उपयोगी है। मैं
tasks
. में शामिल होने के लिए सुविधा का उपयोग करता हूं ,fixins
,projects
औरtask_log_entries
सभी कोusers
. के साथ लेफ्ट-जॉइन करने से पहले - सबक्वेरी के बिना। -
तालिका उपनाम जटिल प्रश्नों को लिखना आसान बनाएं।