उलझा हुआ, सरल और स्थिर, यह ऐसा दिखाई दे सकता है:
SELECT to_char(s.tag,'yyyy-mm') AS monat
, count(t.id) AS eintraege
FROM (
SELECT generate_series(min(date_from)::date
, max(date_from)::date
, interval '1 day'
)::date AS tag
FROM mytable t
) s
LEFT JOIN mytable t ON t.date_from::date = s.tag AND t.version = 1
GROUP BY 1
ORDER BY 1;
db<>फिडल यहाँ
सभी शोर, भ्रामक पहचानकर्ताओं और अपरंपरागत प्रारूप के बीच वास्तविक समस्या यहां छिपी हुई थी:
WHERE version = 1
आपने RIGHT [OUTER] JOIN
. का सही इस्तेमाल किया है . लेकिन एक WHERE
जोड़ना क्लॉज जिसके लिए mytable
. से मौजूदा पंक्ति की आवश्यकता है RIGHT [OUTER] JOIN
. को रूपांतरित करता है एक [INNER] JOIN
प्रभावी ढंग से।
उस फ़िल्टर को JOIN
. में ले जाएं इसे काम करने के लिए शर्त।
मैंने इसमें रहते हुए कुछ अन्य चीजों को सरल बनाया।
बेहतर, फिर भी
SELECT to_char(mon, 'yyyy-mm') AS monat
, COALESCE(t.ct, 0) AS eintraege
FROM (
SELECT date_trunc('month', date_from)::date AS mon
, count(*) AS ct
FROM mytable
WHERE version = 1
GROUP BY 1
) t
RIGHT JOIN (
SELECT generate_series(date_trunc('month', min(date_from))
, max(date_from)
, interval '1 mon')::date
FROM mytable
) m(mon) USING (mon)
ORDER BY mon;
db<>फिडल यहाँ
पहले एकत्रित करना और बाद में शामिल होना बहुत सस्ता है - प्रति दिन एक पंक्ति के बजाय प्रति माह एक पंक्ति में शामिल होना।
GROUP BY
base को आधार बनाना सस्ता है और ORDER BY
date
को रेंडर किए गए text
. के बजाय मान ।
count(*)
count(id)
. से थोड़ा तेज है , जबकि इस . में समतुल्य है क्वेरी।
generate_series()
timestamp
. पर आधारित होने पर थोड़ा तेज़ और सुरक्षित होता है date
. के बजाय . देखें:
- PostgreSQL में दो तिथियों के बीच समय श्रृंखला उत्पन्न करना