MySQL Query GROUP BY Tag / Monat / Jahr

649

Ist es möglich, eine einfache Abfrage durchzuführen, um zu zählen, wie viele Datensätze ich in einem bestimmten Zeitraum wie einem Jahr, einem Monat oder einem Tag habe und ein TIMESTAMPFeld habe, wie z.

SELECT COUNT(id)
FROM stats
WHERE record_date.YEAR = 2009
GROUP BY record_date.YEAR

Oder auch:

SELECT COUNT(id)
FROM stats
GROUP BY record_date.YEAR, record_date.MONTH

Eine monatliche Statistik haben.

Vielen Dank!

Fernando Barrocal
quelle
1
Ich denke, es soll GROUP BY record_date.MONTHin Ihrem ersten Code-Snippet sein?
Chiccodoro

Antworten:

1012
GROUP BY YEAR(record_date), MONTH(record_date)

Überprüfen Sie die Datums- und Uhrzeitfunktionen in MySQL.

codelogic
quelle
27
In einigen Fällen möchten Sie möglicherweise eine zusätzliche Spalte hinzufügen, um die Übersichtlichkeit zu erhöhen, z. B. wenn Datensätze mehrere Jahre umfassen. SELECT COUNT (event_id), DATE_FORMAT (event_start, '% Y /% m')
Ric
Einfaches vollständiges Beispiel: SELECT count(*), record_date FROM anytable WHERE anytable.anycolumn = 'anycondition' GROUP BY YEAR(record_date), month(record_date);Hinweis: record_date ist ein Datumstyp TIMESTAMP
renedet
Erwähnenswert ist wahrscheinlich, dass dies auf MySQL 5.7 mit einer COUNT-Alias-Spalte nicht ausgeführt wurde (kein Fehler, ich habe keine Ergebnisse erhalten). Wenn ich diese Felder mit Alias ​​ausgewählt habe, konnte ich sie nach dem Alias ​​gruppieren. Dies ist ein Standard-Docker-Image für MySQL 5.7, das in einer lokalen Umgebung ausgeführt wird. Ich habe keine Ahnung, warum es keine Fehler gemacht oder Ergebnisse zurückgegeben hat.
MrMesees
3
Oh Gott, wenn ich das früher wüsste ... so viele PHP-Zeilen, um etwas zu tun, was MySQL in einer Zeile tun kann.
Nächte
230
GROUP BY DATE_FORMAT(record_date, '%Y%m')

Hinweis (hauptsächlich für potenzielle Downvoter). Derzeit ist dies möglicherweise nicht so effizient wie andere Vorschläge. Trotzdem lasse ich es als Alternative und auch als eine, die dazu beitragen kann, zu sehen, wie schneller andere Lösungen sind. (Denn man kann nicht wirklich schnell von langsam unterscheiden, bis man den Unterschied sieht.) Im Laufe der Zeit könnten auch Änderungen an der MySQL-Engine in Bezug auf die Optimierung vorgenommen werden, um diese Lösung bei einigen (vielleicht auch nicht) zu machen entfernt) Punkt in der Zukunft, um in der Effizienz mit den meisten anderen vergleichbar zu werden.

Andriy M.
quelle
3
Ich habe das Gefühl, dass dies nicht gut funktioniert, da eine Formatierungsfunktion keinen Index für die Datumsspalte verwenden kann.
Sonny
@Stv: Vielleicht möchten Sie dann die Antwort von @ fu-chi in Betracht ziehen . Soweit ich das beurteilen kann, werden die Gruppierungsausdrücke sowohl in dieser als auch in meiner Antwort als gleich bewertet, sind jedoch EXTRACT()möglicherweise effizienter als DATE_FORMAT(). (Ich habe jedoch kein MySQL für ordnungsgemäße Tests.)
Andriy M
45

Probier diese

SELECT COUNT(id)
FROM stats
GROUP BY EXTRACT(YEAR_MONTH FROM record_date)

Die EXTRACT-Funktion (Einheit ab Datum) ist besser, da weniger Gruppierungen verwendet werden und die Funktion einen Zahlenwert zurückgibt.

Die Vergleichsbedingung beim Gruppieren ist schneller als die Funktion DATE_FORMAT (die einen Zeichenfolgenwert zurückgibt). Versuchen Sie, das Feld function | zu verwenden, das einen Wert ohne Zeichenfolge für die SQL-Vergleichsbedingung zurückgibt (WHERE, HAVING, ORDER BY, GROUP BY).

Fu-Chi
quelle
43

Ich habe versucht, die obige 'WHERE'-Anweisung zu verwenden. Ich dachte, sie ist korrekt, da niemand sie korrigiert hat, aber ich habe mich geirrt. Nach einigen Suchen habe ich herausgefunden, dass dies die richtige Formel für die WHERE-Anweisung ist, sodass der Code folgendermaßen aussieht:

SELECT COUNT(id)  
FROM stats  
WHERE YEAR(record_date) = 2009  
GROUP BY MONTH(record_date)
dimazaid
quelle
30

Wenn Ihre Suche mehrere Jahre dauert und Sie dennoch monatlich gruppieren möchten, schlage ich vor:

Version 1:

SELECT SQL_NO_CACHE YEAR(record_date), MONTH(record_date), COUNT(*)
FROM stats
GROUP BY DATE_FORMAT(record_date, '%Y%m')

Version 2 (effizienter) :

SELECT SQL_NO_CACHE YEAR(record_date), MONTH(record_date), COUNT(*)
FROM stats
GROUP BY YEAR(record_date)*100 + MONTH(record_date)

Ich habe diese Versionen auf einer großen Tabelle mit 1.357.918 Zeilen verglichen (), und die 2. Version scheint bessere Ergebnisse zu haben.

version1 (Durchschnitt von 10 führt) : 1,404 Sekunden
version2 (Durchschnitt von 10 führt) : 0,780 Sekunden

( SQL_NO_CACHESchlüssel hinzugefügt, um zu verhindern, dass MySQL bei Abfragen CACHING.)

mr.baby123
quelle
1
Erwägen Sie, den Vorschlag von @ fu-chi in Ihre Tests aufzunehmen, da dies möglicherweise noch effizienter ist. Sie haben auch getestet GROUP BY YEAR(record_date)*100 + MONTH(record_date), aber warum nicht auch testen GROUP BY YEAR(record_date), MONTH(record_date)?
Andriy M
2
Wenn Sie COUNT (1) insteed COUNT (*) verwenden, ist dies sogar noch schneller und die Ergebnisdaten sind dieselben.
Pa0l0
2
Was ist das *100auf der Versión # 2? Danke im Voraus.
Avión
1
*100zuYEAR(record_date)*100 + MONTH(record_date) == DATE_FORMAT(record_date, '%Y%m')
Phu Duy
17

Wenn Sie in MySQL nach Datum gruppieren möchten, verwenden Sie den folgenden Code:

 SELECT COUNT(id)
 FROM stats
 GROUP BY DAYOFMONTH(record_date)

Hoffe, das spart etwas Zeit für diejenigen, die diesen Thread finden werden.

Haijerome
quelle
6
Es ist wichtig zu beachten, dass Sie auch nach gruppieren müssen, MONTH(record_date)um mehrere Monate zu berücksichtigen.
Webnet
14

Wenn Sie Datensätze für ein bestimmtes Jahr (z. B. 2000) filtern möchten, optimieren Sie die WHEREKlausel wie folgt:

SELECT MONTH(date_column), COUNT(*)
FROM date_table
WHERE date_column >= '2000-01-01' AND date_column < '2001-01-01'
GROUP BY MONTH(date_column)
-- average 0.016 sec.

Anstatt:

WHERE YEAR(date_column) = 2000
-- average 0.132 sec.

Die Ergebnisse wurden anhand einer Tabelle generiert, die 300.000 Zeilen und eine Index-On-Date-Spalte enthielt.

In GROUP BYBezug auf die Klausel habe ich die drei Varianten anhand der oben genannten Tabelle getestet. Hier sind die Ergebnisse:

SELECT YEAR(date_column), MONTH(date_column), COUNT(*)
FROM date_table
GROUP BY YEAR(date_column), MONTH(date_column)
-- codelogic
-- average 0.250 sec.

SELECT YEAR(date_column), MONTH(date_column), COUNT(*)
FROM date_table
GROUP BY DATE_FORMAT(date_column, '%Y%m')
-- Andriy M
-- average 0.468 sec.

SELECT YEAR(date_column), MONTH(date_column), COUNT(*)
FROM date_table
GROUP BY EXTRACT(YEAR_MONTH FROM date_column)
-- fu-chi
-- average 0.203 sec.

Der letzte ist der Gewinner.

Salman A.
quelle
10

Komplette und einfache Lösung mit ähnlich leistungsfähiger, aber kürzerer und flexiblerer Alternative, die derzeit aktiv ist:

SELECT COUNT(*) FROM stats
-- GROUP BY YEAR(record_date), MONTH(record_date), DAYOFMONTH(record_date)
GROUP BY DATE_FORMAT(record_date, '%Y-%m-%d')
Cees Timmerman
quelle
7

Wenn Sie eine monatliche Statistik mit Zeilenzahlen pro Monat eines jeden Jahres erhalten möchten, die nach dem letzten Monat sortiert sind, versuchen Sie Folgendes:

SELECT count(id),
      YEAR(record_date),
      MONTH(record_date) 
FROM `table` 
GROUP BY YEAR(record_date),
        MONTH(record_date) 
ORDER BY YEAR(record_date) DESC,
        MONTH(record_date) DESC
user3019799
quelle
7

Sie können dies einfach mit der Funktion Mysql DATE_FORMAT () in GROUP BY tun . In einigen Fällen möchten Sie möglicherweise eine zusätzliche Spalte hinzufügen, um die Übersichtlichkeit zu verbessern, z. B. wenn Datensätze mehrere Jahre umfassen und derselbe Monat in verschiedenen Jahren auftritt. Hier können Sie so viele Optionen anpassen. Bitte lesen Sie dies vor dem Start. Hoffe es sollte sehr hilfreich für dich sein. Hier ist eine Beispielabfrage für Ihr Verständnis

SELECT
    COUNT(id),
    DATE_FORMAT(record_date, '%Y-%m-%d') AS DAY,
    DATE_FORMAT(record_date, '%Y-%m') AS MONTH,
    DATE_FORMAT(record_date, '%Y') AS YEAR

FROM
    stats
WHERE
    YEAR = 2009
GROUP BY
    DATE_FORMAT(record_date, '%Y-%m-%d ');
Faisal
quelle
4

Die folgende Abfrage hat in Oracle Database 12c Release 12.1.0.1.0 für mich funktioniert

SELECT COUNT(*)
FROM stats
GROUP BY 
extract(MONTH FROM TIMESTAMP),
extract(MONTH FROM TIMESTAMP),
extract(YEAR  FROM TIMESTAMP);
Minisha
quelle
2

Ich bevorzuge es, die einjährige Gruppenauswahl so zu optimieren:

SELECT COUNT(*)
  FROM stats
 WHERE record_date >= :year 
   AND record_date <  :year + INTERVAL 1 YEAR;

Auf diese Weise können Sie das Jahr nur einmal binden, z. B. '2009'mit einem benannten Parameter, und müssen sich nicht um das Hinzufügen '-01-01'oder Übergeben '2010'separat kümmern .

Da wir vermutlich nur Zeilen zählen und dies idniemals tun NULL, ziehe ich es COUNT(*)vor COUNT(id).

Arth
quelle
0

.... group by to_char(date, 'YYYY') -> 1989

.... group by to_char(date,'MM') -> 05

.... group by to_char(date,'DD') ---> 23

.... group by to_char(date,'MON') ---> MAI

.... group by to_char(date,'YY') ---> 89

aromita sen
quelle
Das wäre sehr sehr langsam.
Earl3s