it-swarm.com.de

Gruppieren Sie die Abfrageergebnisse nach Monat und Jahr in postgresql

Ich habe folgende Datenbanktabelle auf einem Postgres-Server:

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

Ich möchte eine Abfrage erstellen, die die SUM der Sales -Spalte enthält und die Ergebnisse nach Monat und Jahr wie folgt gruppiert:

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

Gibt es einen einfachen Weg, das zu tun?

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

Auf Wunsch von Radu werde ich diese Frage erläutern:

to_char(date,'Mon') as mon,: konvertiert das Attribut "date" in das definierte Format der Kurzform Monat.

extract(year from date) as yyyy: Mit der Funktion "extract" von Postgresql wird das Jahr JJJJ aus dem Attribut "date" extrahiert.

sum("Sales") as "Sales": Die SUM () - Funktion addiert alle "Sales" -Werte und liefert einen Alias, bei dem die Groß- und Kleinschreibung in Anführungszeichen gesetzt wird.

group by 1,2: Die GROUP BY-Funktion muss alle Spalten aus der SELECT-Liste enthalten, die nicht Teil des Aggregats sind (auch bekannt als alle Spalten, die nicht in den Funktionen SUM/AVG/MIN/MAX usw. enthalten sind). Dies teilt der Abfrage mit, dass SUM () für jede eindeutige Kombination von Spalten angewendet werden soll, in diesem Fall für die Spalten month und year. Der Teil "1,2" ist eine Kurzform anstelle der Spaltenaliase, obwohl es wahrscheinlich am besten ist, die vollständigen Ausdrücke "to_char (...)" und "extract (...)" für die Lesbarkeit zu verwenden.

180
bma

Ich kann nicht glauben, dass die akzeptierte Antwort so viele positive Stimmen hat - es ist eine schreckliche Methode.

Hier ist der richtige Weg, dies mit date_trunc zu tun:

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

Es ist eine schlechte Übung, aber Ihnen könnte vergeben werden, wenn Sie sie verwenden

 GROUP BY 1

in einer sehr einfachen Abfrage.

Sie können auch verwenden

 GROUP BY date_trunc('month', txn_date)

wenn Sie das Datum nicht auswählen möchten.

249
Burak Arslan

to_char lässt Sie tatsächlich das Jahr und den Monat auf einen Schlag herausziehen!

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'

oder im Fall des obigen Beispiels des Benutzers:

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

Es gibt eine andere Möglichkeit, das Ergebnis mit der Funktion date_part () in postgres zu erzielen.

 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)

Vielen Dank

3
Nayan

bma Antwort ist großartig! Ich habe es mit ActiveRecords verwendet, hier ist es, wenn jemand es in Rails benötigt:

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 hat einige Arten von Zeitstempeln:

Zeitstempel ohne ZeitzoneTC-Zeitstempel werden bevorzugt gespeichert) Sie finden sie im multinationalen Datenbankspeicher. In diesem Fall kümmert sich der Kunde um den Zeitzonen-Offset für jedes Land.

Zeitstempel mit Zeitzone - Der Zeitzonenversatz ist bereits im Zeitstempel enthalten.

In einigen Fällen verwendet Ihre Datenbank die Zeitzone nicht, aber Sie müssen dennoch Datensätze in Bezug auf die lokale Zeitzone und die Sommerzeit gruppieren (z. B. --- (https://www.timeanddate.com/time/zone/romania/bookarest) )

Um eine Zeitzone hinzuzufügen, können Sie dieses Beispiel verwenden und den Zeitzonenversatz durch Ihren ersetzen.

"your_date_column" at time zone '+03'

Um den für die Sommerzeit spezifischen Zeitunterschied von +1 zu addieren, müssen Sie prüfen, ob Ihr Zeitstempel in eine Sommerzeit fällt. Da diese Intervalle zwischen 1 und 2 Tagen variieren, verwende ich eine Annäherung, die sich nicht auf die Monatsendeaufzeichnungen auswirkt. In diesem Fall kann ich also jedes jährliche Intervall ignorieren.

Wenn eine genauere Abfrage erstellt werden muss, müssen Sie Bedingungen hinzufügen, um weitere Fälle zu erstellen. In etwa funktioniert dies jedoch in Daten pro Monat in Bezug auf Zeitzone und Sommerzeit aufteilen, wenn Sie in Ihrer Datenbank einen Zeitstempel ohne Zeitzone finden:

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