क्वेरी को शायद सरल बनाया जा सकता है:
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 taskWHEREजोड़ें खंड: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. के साथ लेफ्ट-जॉइन करने से पहले - सबक्वेरी के बिना। -
तालिका उपनाम जटिल प्रश्नों को लिखना आसान बनाएं।