मूल समाधान
महीनों की पूरी सूची तैयार करें और LEFT JOIN
इसके लिए बाकी:
SELECT *
FROM (
SELECT to_char(m, 'YYYY-MON') AS yyyymmm
FROM generate_series(<start_date>, <end_date>, interval '1 month') m
) m
LEFT JOIN ( <your query here> ) q USING (yyyymmm);
अधिक स्पष्टीकरण के साथ संबंधित उत्तर:
- पोस्टग्रेज में एक generate_series पर एक काउंट क्वेरी में शामिल हों और "0" के रूप में Null-values को पुनः प्राप्त करें
- Rails+Postgres में मनमाने समय अंतराल द्वारा रिकॉर्ड गिनने का सबसे अच्छा तरीका
आपके मामले का उन्नत समाधान
आपकी क्वेरी मेरी समझ से कहीं अधिक जटिल है। आपको सभी . से अधिक चलने वाली राशि चाहिए चयनित आइटम की पंक्तियाँ, फिर आप न्यूनतम तिथि से पुरानी पंक्तियों को ट्रिम करना चाहते हैं, और पिछले महीने की पूर्व-गणना के साथ लापता महीनों को भरना चाहते हैं।
मैं इसे अब LEFT JOIN LATERAL
. के साथ प्राप्त करता हूं .
SELECT COALESCE(m.yearmonth, c.yearmonth)::date, sold_qty, on_hand
FROM (
SELECT yearmonth
, COALESCE(sold_qty, 0) AS sold_qty
, sum(on_hand_mon) OVER (ORDER BY yearmonth) AS on_hand
, lead(yearmonth) OVER (ORDER BY yearmonth)
- interval '1 month' AS nextmonth
FROM (
SELECT date_trunc('month', c.change_date) AS yearmonth
, sum(c.sold_qty / s.qty)::numeric(18,2) AS sold_qty
, sum(c.on_hand) AS on_hand_mon
FROM item_change c
LEFT JOIN item i USING (item_id)
LEFT JOIN item_size s ON s.item_id = i.item_id AND s.name = i.sell_size
LEFT JOIN item_plu p ON p.item_id = i.item_id AND p.seq_num = 0
WHERE c.change_date < date_trunc('month', now()) - interval '1 day'
AND c.item_id = (SELECT item_id FROM item_plu WHERE number = '51515')
GROUP BY 1
) sub
) c
LEFT JOIN LATERAL generate_series(c.yearmonth
, c.nextmonth
, interval '1 month') m(yearmonth) ON TRUE
WHERE c.yearmonth > date_trunc('year', now()) - interval '540 days'
ORDER BY COALESCE(m.yearmonth, c.yearmonth);
SQL Fiddle न्यूनतम परीक्षण मामले के साथ।
प्रमुख बिंदु:
-
मैंने आपके व्यू को पूरी तरह से क्वेरी से हटा दिया है। बिना किसी लाभ के बहुत अधिक लागत।
-
चूंकि आप एक एकल . का चयन करते हैं
item_id
, आपकोGROUP BY item_id
करने की आवश्यकता नहीं है याPARTITION BY item_id
। -
लघु तालिका उपनामों का उपयोग करें और सभी संदर्भों को स्पष्ट करें - विशेष रूप से सार्वजनिक मंच पर पोस्ट करते समय।
-
आपके जुड़ने में कोष्ठक सिर्फ शोर थे। जॉइन वैसे भी डिफ़ॉल्ट रूप से बाएं से दाएं निष्पादित होते हैं।
-
सरलीकृत तिथि सीमाएं (चूंकि मैं टाइमस्टैम्प के साथ काम करता हूं):
date_trunc('year', current_date) - interval '540 days' date_trunc('month', current_date) - interval '1 day'
समकक्ष, लेकिन इससे सरल और तेज़:
current_date - date_part('day',current_date)::integer - 540 current_date - date_part('day',current_date)::integer -
अब मैं
generate_series()
. के साथ सभी गणनाओं के बाद लापता महीनों को भरता हूं प्रति पंक्ति कॉल। -
यह होना चाहिए
LEFT JOIN LATERAL ... ON TRUE
,JOIN LATERAL
. का संक्षिप्त रूप नहीं अंतिम पंक्ति के कोने के मामले को पकड़ने के लिए। विस्तृत विवरण:
महत्वपूर्ण साइड नोट:
character(22)
एक भयानक है प्राथमिक कुंजी के लिए डेटा प्रकार (या कोई भी कॉलम)। विवरण:
आदर्श रूप से यह एक int
होगा या bigint
कॉलम, या संभवतः एक UUID
।
साथ ही, धन राशियों को money
टाइप करें या integer
(सेंट का प्रतिनिधित्व) समग्र रूप से बेहतर प्रदर्शन करता है।
लंबे समय में , प्रदर्शन खराब होना तय है, क्योंकि आपको अपनी गणना में शुरुआत से ही सभी पंक्तियों को शामिल करना होगा। आपको पुरानी पंक्तियों को काट देना चाहिए और on_hold
. के संतुलन को अमल में लाना चाहिए वार्षिक आधार पर या कुछ और।