Postgresql में महीने और साल के अनुसार समूह क्वेरी परिणाम


156

मेरे पास पोस्टग्रेज सर्वर पर निम्नलिखित डेटाबेस तालिका है:

id      date          Product Sales
1245    01/04/2013    Toys    1000     
1245    01/04/2013    Toys    2000
1231    01/02/2013    Bicycle 50000
456461  01/01/2014    Bananas 4546

मैं एक क्वेरी बनाना चाहता हूं SUMजो Salesकॉलम और समूहों को महीने और साल के अनुसार परिणाम निम्नानुसार देता है:

Apr    2013    3000     Toys
Feb    2013    50000    Bicycle
Jan    2014    4546     Bananas

क्या ऐसा करने का एक सरल तरीका है?

जवाबों:


217
select to_char(date,'Mon') as mon,
       extract(year from date) as yyyy,
       sum("Sales") as "Sales"
from yourtable
group by 1,2

राडू के अनुरोध पर, मैं उस प्रश्न की व्याख्या करूंगा:

to_char(date,'Mon') as mon, : "दिनांक" विशेषता को महीने के संक्षिप्त रूप के परिभाषित प्रारूप में परिवर्तित करता है।

extract(year from date) as yyyy : Postgresql के "एक्सट्रैक्ट" फ़ंक्शन का उपयोग "दिनांक" विशेषता से YYYY वर्ष निकालने के लिए किया जाता है।

sum("Sales") as "Sales" : एसयूएम () फ़ंक्शन सभी "बिक्री" मूल्यों को जोड़ता है, और केस-संवेदी उपनाम की आपूर्ति करता है, मामले की संवेदनशीलता को दोहरे-उद्धरणों का उपयोग करके बनाए रखा जाता है।

group by 1,2: ग्रुप बाय फंक्शन में सेलेक्ट लिस्ट के सभी कॉलम शामिल होने चाहिए जो एग्री (aka, सभी कॉलम SUM / AVG / MIN / MAX आदि फंक्शंस के अंदर नहीं हैं) का हिस्सा होना चाहिए। यह प्रश्न बताता है कि कॉलम के प्रत्येक अद्वितीय संयोजन के लिए SUM () लागू किया जाना चाहिए, जो इस मामले में महीने और वर्ष के कॉलम हैं। "1,2" भाग कॉलम उपनामों का उपयोग करने के बजाय एक शॉर्टहैंड है, हालांकि पठनीयता के लिए पूर्ण "to_char (...)" और "अर्क (...)" अभिव्यक्तियों का उपयोग करना संभवतः सबसे अच्छा है।


5
मुझे नहीं लगता कि स्पष्टीकरण के बिना जवाब देना एक बहुत अच्छा विचार है, खासकर शुरुआती लोगों के लिए। आपको अपने उत्तर के पीछे के तर्क को स्पष्ट करना चाहिए, शायद कम से कम थोड़ा (हालांकि यह हम में से बाकी लोगों के लिए सरल और सीधा लग सकता है)।
राडू घोरघिउ

1
@BurakArslan परिणाम क्या ओपी के लिए विशेष रूप से पूछा की तरह दिखते हैं?
bma

2
@rogerdpack, का आउटपुट date_truncवैसा नहीं है जैसा select date_trunc('month', timestamp '2001-02-16 20:38:40')::date2001-02-01
पूछने वाला

2
मुझे क्लॉज date_truncमें उपयोग करने का विचार पसंद है group by
पिसरुक

1
संभावित "फ़ील्ड को क्लॉज़" मुद्दों द्वारा समूह में होना चाहिए ... OVER (PARTITION BY) का उपयोग करना बेहतर है।
ज़ोन

317

मुझे विश्वास नहीं हो रहा है कि स्वीकृत उत्तर में इतने उतार-चढ़ाव हैं - यह एक भयानक तरीका है।

यहाँ यह करने का सही तरीका है, date_trunc के साथ :

   SELECT date_trunc('month', txn_date) AS txn_month, sum(amount) as monthly_sum
     FROM yourtable
 GROUP BY txn_month

यह बुरा अभ्यास है लेकिन यदि आप उपयोग करते हैं तो आपको माफ किया जा सकता है

 GROUP BY 1

एक बहुत ही सरल क्वेरी में।

आप भी उपयोग कर सकते हैं

 GROUP BY date_trunc('month', txn_date)

यदि आप तिथि का चयन नहीं करना चाहते हैं।


6
दुर्भाग्य से आउटपुट date_truncवह नहीं है जो पूछने वाले ने उम्मीद की थी: select date_trunc('month', timestamp '2001-02-16 20:38:40')=> 2001-02-01 00:00:00
पिसरुक

4
मैं मानता हूं कि यह तरीका बेहतर है। मुझे यकीन नहीं है, लेकिन मुझे लगता है कि यह अधिक कुशल है, क्योंकि दो के बजाय केवल एक समूह है। यदि आपको उस तिथि को पुन: स्वरूपित करने की आवश्यकता है जो आप बाद में अन्य उत्तरों में वर्णित विधियों का उपयोग करके कर सकते हैं:to_char(date_trunc('month', txn_date), 'YY-Mon')
पवेल सोकोलोव्स्की

1
हां, स्वीकृत उत्तर के लिए वोटों की संख्या दिमाग चकरा देने वाली है। date_truncइस सटीक उद्देश्य के लिए बनाया गया था। दो कॉलम बनाने का कोई कारण नहीं है
एलनविले

2
बहुत अच्छा! यह एक बेहतर जवाब है, खासकर जब से आप ऑर्डर कर सकते हैं। Upvoted!
बॉबॉर्स्की

1
फिर भी एक और उदाहरण जहां सबसे उत्तोलित उत्तर स्वीकार किए गए उत्तर से पहले प्रकट होना चाहिए
ब्रायन रिस्क

33

to_char वास्तव में आप एक झपट्टा में वर्ष और महीने बाहर खींचने की सुविधा देता है!

select to_char(date('2014-05-10'),'Mon-YY') as year_month; --'May-14'
select to_char(date('2014-05-10'),'YYYY-MM') as year_month; --'2014-05'

या ऊपर उपयोगकर्ता के उदाहरण के मामले में:

select to_char(date,'YY-Mon') as year_month
       sum("Sales") as "Sales"
from some_table
group by 1;

6
यदि आप अपनी तालिका में एक अच्छी मात्रा में डेटा रखते हैं तो मैं इसे करने के लिए दृढ़ता से सलाह दूंगा। यह प्रदर्शन बहुत से भी बदतर date_truncविधि जब से समूह प्रदर्शन। एक DB पर प्रयोग करना मेरे पास 270k पंक्तियों वाली तालिका पर है, दिनांक_trunc विधि TO_CHAR की गति से दोगुनी है
क्रिस क्लार्क

@ChrisClark अगर प्रदर्शन एक चिंता का विषय है, तो मैं मानता हूं कि यह date_trunc का उपयोग करने के लिए समझ में आता है, लेकिन कुछ मामलों में एक स्वरूपित तारीख स्ट्रिंग बेहतर है, और यदि आप एक परफॉर्मेंट डेटा वेयरहाउस का उपयोग कर रहे हैं तो अतिरिक्त गणना एक सौदा ब्रेकर नहीं हो सकती है । उदाहरण के लिए, यदि आप रेडशिफ्ट का उपयोग करके एक त्वरित एनालिटिक्स रिपोर्ट चला रहे हैं, और इसमें आमतौर पर 3 सेकंड लगते हैं, तो 6 सेकंड की क्वेरी शायद ठीक है (हालांकि, यदि आप रिपोर्ट चला रहे हैं, तो अतिरिक्त गणना एक छोटे प्रतिशत से चीजों को धीमा कर सकती है, क्योंकि वहाँ एक बड़ा कम्प्यूटेशनल ओवरहेड है)
mgoldwasser

1
आप अभी भी ऐसा कर सकते हैं - बस समूह को क्वेरी द्वारा 'रैपिंग' करके एक अलग चरण के रूप में प्रारूपित करें। जैसे SELECT_char (d, 'YYYY-DD') FROM (SELECT date_trunc ('month', d) AS "d" Fbl tbl) AS foo के रूप में। दोनों ओर से लाभदायक!
क्रिस क्लार्क

1
यह समाधान सरल और सुरुचिपूर्ण है। मुझे यह पसंद है और मेरे मामले में यह काफी तेज है। इस उत्तर के लिए धन्यवाद!
गुफ्तगू

5

पोस्टग्रेज़ में date_part () फ़ंक्शन का उपयोग करके परिणाम प्राप्त करने का एक और तरीका है।

 SELECT date_part('month', txn_date) AS txn_month, date_part('year', txn_date) AS txn_year, sum(amount) as monthly_sum
     FROM yourtable
 GROUP BY date_part('month', txn_date)

धन्यवाद


1

bma जवाब बहुत अच्छा है! मैंने इसे ActiveRecords के साथ उपयोग किया है, यहाँ यह है कि अगर किसी को रेल में इसकी आवश्यकता है:

Model.find_by_sql(
  "SELECT TO_CHAR(created_at, 'Mon') AS month,
   EXTRACT(year from created_at) as year,
   SUM(desired_value) as desired_value
   FROM desired_table
   GROUP BY 1,2
   ORDER BY 1,2"
)

3
या आप कर सकते हैं yourscopeorclass.group("extract(year from tablename.colname)")और आप साल, महीने, दिन पाने के लिए 3 बार एक साथ चेन कर सकते हैं
nruth

1

इस ट्यूटोरियल के उदाहरण E पर एक नज़र डालें -> https://www.postgresqltutorial.com/postgresql-gat-b//

आपको अपने द्वारा चुने गए वर्चुअल विशेषता के नाम को कॉल करने के बजाय अपने ग्रुप द्वारा फ़ंक्शन को कॉल करने की आवश्यकता है। मैं वही कर रहा था जो ऊपर दिए गए सभी उत्तरों ने सुझाया था और मुझे एक column 'year_month' does not existत्रुटि मिल रही थी ।

मेरे लिए क्या काम था:

SELECT 
    date_trunc('month', created_at), 'MM/YYYY' AS month
FROM 
    "orders"  
GROUP BY 
    date_trunc('month', created_at)

0

Postgres में टाइमस्टैम्प के कुछ प्रकार हैं:

टाइमज़ोन के बिना टाइमस्टैम्प - (UTC टाइमस्टैम्प को स्टोर करने के लिए उपयुक्त) आप इसे बहुराष्ट्रीय डेटाबेस भंडारण में पाते हैं। इस मामले में ग्राहक प्रत्येक देश के लिए टाइमजोन ऑफसेट का ध्यान रखेगा।

टाइमज़ोन के साथ टाइमस्टैम्प - टाइमज़ोन ऑफसेट को टाइमस्टैम्प में पहले से ही शामिल किया गया है।

कुछ मामलों में, आपका डेटाबेस टाइमज़ोन का उपयोग नहीं करता है, लेकिन फिर भी आपको स्थानीय टाइमज़ोन और डेलाइट सेविंग टाइम (उदाहरण https://www.timeanddate.com/time/zone/romania/bucharest ) के संबंध में समूह रिकॉर्ड करने की आवश्यकता है

टाइमज़ोन जोड़ने के लिए आप इस उदाहरण का उपयोग कर सकते हैं और टाइमज़ोन ऑफसेट को अपने साथ बदल सकते हैं।

"your_date_column" at time zone '+03'

डीएसटी के लिए विशिष्ट +1 समर टाइम ऑफसेट को जोड़ने के लिए आपको यह जांचना होगा कि आपका टाइमस्टैम्प समर डीएसटी में आता है या नहीं। जैसा कि उन अंतरालों में 1 या 2 दिन का अंतर होता है, मैं एक औचित्य का उपयोग करूंगा जो महीने के रिकॉर्ड के अंत को प्रभावित नहीं करता है, इसलिए इस मामले में मैं प्रत्येक वर्ष के सटीक अंतराल को अनदेखा कर सकता हूं।

यदि अधिक सटीक क्वेरी का निर्माण करना है, तो आपको अधिक मामले बनाने के लिए शर्तों को जोड़ना होगा। लेकिन मोटे तौर पर, यह समय-सारणी और समरटाइम के संबंध में प्रति माह डेटा को विभाजित करने में ठीक काम करेगा जब आप अपने डेटाबेस में टाइमज़ोन के बिना टाइमस्टैम्प पाते हैं:

SELECT 
    "id", "Product", "Sale",
    date_trunc('month', 
        CASE WHEN 
            Extract(month from t."date") > 03 AND
            Extract(day from t."date") > 26 AND
            Extract(hour from t."date") > 3 AND
            Extract(month from t."date") < 10 AND
            Extract(day from t."date") < 29 AND
            Extract(hour from t."date") < 4
        THEN 
            t."date" at time zone '+03' -- Romania TimeZone offset + DST
        ELSE
            t."date" at time zone '+02' -- Romania TimeZone offset 
        END) as "date"
FROM 
    public."Table" AS t
WHERE 1=1
    AND t."date" >= '01/07/2015 00:00:00'::TIMESTAMP WITHOUT TIME ZONE
    AND t."date" < '01/07/2017 00:00:00'::TIMESTAMP WITHOUT TIME ZONE
GROUP BY date_trunc('month', 
    CASE WHEN 
        Extract(month from t."date") > 03 AND
        Extract(day from t."date") > 26 AND
        Extract(hour from t."date") > 3 AND
        Extract(month from t."date") < 10 AND
        Extract(day from t."date") < 29 AND
        Extract(hour from t."date") < 4
    THEN 
        t."date" at time zone '+03' -- Romania TimeZone offset + DST
    ELSE
        t."date" at time zone '+02' -- Romania TimeZone offset 
    END)
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.