it-swarm.dev

نتائج استعلام المجموعة حسب الشهر والسنة في postgresql

لدي جدول قاعدة البيانات التالي على خادم Postgres:

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

هل هناك طريقة بسيطة للقيام بذلك؟

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

بناءً على طلب Radu ، سأشرح هذا الاستعلام:

to_char(date,'Mon') as mon,: يحول السمة "date" إلى التنسيق المحدد للشكل القصير من الشهر.

extract(year from date) as yyyy: يتم استخدام وظيفة "استخراج" Postgresql لاستخراج سنة YYYY من سمة "التاريخ".

sum("Sales") as "Sales": تضيف الدالة SUM () جميع قيم "المبيعات" ، وتوفر اسمًا مستعارًا حساسًا لحالة الأحرف ، مع الحفاظ على حساسية الحالة باستخدام علامات الاقتباس المزدوجة.

group by 1,2: يجب أن تحتوي الدالة GROUP BY على جميع الأعمدة من قائمة SELECT التي ليست جزءًا من التجميع (ويعرف أيضًا باسم جميع الأعمدة غير الموجودة في وظائف SUM/AVG/MIN/MAX وغيرها). يوضح هذا الاستعلام أنه يجب تطبيق SUM () على كل مجموعة فريدة من الأعمدة ، والتي في هذه الحالة هي أعمدة الشهر والسنة. الجزء "1،2" عبارة عن اختصار بدلاً من استخدام الأسماء المستعارة للأعمدة ، على الرغم من أنه من الأفضل استخدام التعبيرات "to_char (...)" و "extract (...)" الكاملة للقراءة.

168
bma

لا أستطيع أن أصدق أن الإجابة المقبولة بها الكثير من الأصوات - إنها طريقة مروعة.

إليك الطريقة الصحيحة للقيام بذلك ، مع 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)

إذا كنت لا تريد تحديد التاريخ.

229
Burak Arslan

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;
25
mgoldwasser

هناك طريقة أخرى لتحقيق النتيجة باستخدام دالة date_part () في postgres.

 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)

شكر

3
Nayan

bma الجواب رائع! لقد استخدمتها مع ActiveRecords ، فإليك ما يحتاجه أي شخص في Rails:

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"
)
1
mekdigital

يحتوي Postgres على أنواع قليلة من الطوابع الزمنية:

الطابع الزمني دون منطقة زمنية - (يفضل تخزين الطوابع الزمنية بالتوقيت العالمي المنسق) يمكنك العثور عليه في تخزين قاعدة البيانات المتعددة الجنسيات. سيقوم العميل في هذه الحالة برعاية إزاحة المنطقة الزمنية لكل بلد.

الطابع الزمني مع المنطقة الزمنية - تم تضمين إزاحة المنطقة الزمنية بالفعل في الطابع الزمني.

في بعض الحالات ، لا تستخدم قاعدة البيانات الخاصة بك المنطقة الزمنية ولكن لا تزال بحاجة إلى تجميع السجلات فيما يتعلق بالتوقيت المحلي والتوقيت الصيفي (مثل https://www.timeanddate.com/time/zone/romania/buc Bucharest )

لإضافة منطقة زمنية ، يمكنك استخدام هذا المثال واستبدال إزاحة المنطقة الزمنية بك.

"your_date_column" at time zone '+03'

لإضافة إزاحة التوقيت الصيفي +1 الخاصة بـ DST ، تحتاج إلى التحقق مما إذا كان الطابع الزمني الخاص بك يقع في DST الصيفي. نظرًا لاختلاف تلك الفواصل الزمنية مع يوم أو يومين ، سأستخدم تقريبًا لا يؤثر على سجلات نهاية الشهر ، لذلك في هذه الحالة يمكنني تجاهل الفاصل الزمني المحدد كل عام.

إذا كان لابد من إنشاء استعلام أكثر دقة ، فعليك إضافة شروط لإنشاء المزيد من الحالات. لكن تقريبًا ، سيعمل هذا بشكل جيد في تقسيم البيانات شهريًا فيما يتعلق بالمنطقة الزمنية و SummerTime عندما تجد الطابع الزمني دون منطقة زمنية في قاعدة البيانات الخاصة بك:

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)
0
profimedica