Requête MySQL GROUPE PAR jour / mois / année


649

Est-il possible de faire une simple requête pour compter le nombre d'enregistrements que j'ai dans une période de temps déterminée comme une année, un mois ou un jour, ayant un TIMESTAMPchamp, comme:

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

Ou même:

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

Pour avoir une statistique mensuelle.

Merci!


1
Je suppose que c'est censé être GROUP BY record_date.MONTHdans votre premier extrait de code?
chiccodoro

Réponses:


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

Découvrez les fonctions de date et d'heure dans MySQL.


27
Vous souhaiterez peut-être ajouter une colonne supplémentaire pour plus de clarté dans certains cas, par exemple lorsque les enregistrements s'étalent sur plusieurs années. SELECT COUNT (event_id), DATE_FORMAT (event_start, '% Y /% m')
Ric

Exemple complet simple: SELECT count(*), record_date FROM anytable WHERE anytable.anycolumn = 'anycondition' GROUP BY YEAR(record_date), month(record_date);remarque: date_enregistrement est un type de date TIMESTAMP
renedet

Il vaut probablement la peine de mentionner que cela n'a pas fonctionné sur mon MySQL 5.7 avec une colonne alias COUNT (pas d'erreur, je n'ai obtenu aucun résultat). Lorsque j'ai changé pour sélectionner ces champs avec un alias, je pouvais alors les regrouper par alias. Il s'agit d'une image de docker MySQL 5.7 standard fonctionnant dans un environnement local, donc je ne sais pas pourquoi elle n'a pas généré d'erreur ou n'a renvoyé aucun résultat.
MrMesees

3
Oh mon dieu, si je le savais plus tôt ... autant de lignes de PHP pour faire quelque chose que mysql peut faire en une seule ligne.
nuits du

231
GROUP BY DATE_FORMAT(record_date, '%Y%m')

Remarque (principalement, pour les downvoters potentiels). Actuellement, cela peut ne pas être aussi efficace que d'autres suggestions. Pourtant, je le laisse comme une alternative, et une solution qui peut également servir à voir à quel point les autres solutions sont plus rapides. (Car vous ne pouvez pas vraiment dire rapide de lent jusqu'à ce que vous voyez la différence.) De plus, au fil du temps, des modifications pourraient être apportées au moteur de MySQL en ce qui concerne l'optimisation afin de rendre cette solution, à certains (peut-être pas éloigné) à l'avenir, pour devenir tout à fait comparable en efficacité avec la plupart des autres.


3
J'ai le sentiment que cela ne fonctionnerait pas bien car une fonction de format ne serait pas en mesure d'utiliser un index sur la colonne de date.
Sonny

@Stv: Vous voudrez peut-être alors considérer la réponse de @ fu-chi . Pour autant que je sache, les expressions de regroupement dans cette réponse et la mienne ont la même valeur mais EXTRACT()peuvent être plus efficaces que DATE_FORMAT(). (Je n'ai pas de MySQL pour les tests appropriés, cependant.)
Andriy M

45

essaye celui-là

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

La fonction EXTRACT (unit FROM date) est meilleure car moins de regroupement est utilisé et la fonction renvoie une valeur numérique.

La condition de comparaison lors du regroupement sera plus rapide que la fonction DATE_FORMAT (qui renvoie une valeur de chaîne). Essayez d'utiliser la fonction | champ qui renvoie une valeur non chaîne pour la condition de comparaison SQL (WHERE, HAVING, ORDER BY, GROUP BY).


43

J'ai essayé d'utiliser la déclaration «WHERE» ci-dessus, je pensais que c'était correct car personne ne l'avait corrigé mais j'avais tort; après quelques recherches, j'ai découvert que c'est la bonne formule pour l'instruction WHERE donc le code devient comme ceci:

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

30

Si votre recherche s'étale sur plusieurs années et que vous souhaitez tout de même vous regrouper mensuellement, je vous suggère:

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 (plus efficace) :

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

J'ai comparé ces versions sur une grande table avec 1 357 918 lignes (), et la 2e version semble avoir de meilleurs résultats.

version1 (moyenne de 10 exécutions) : 1,404 seconde
version2 (moyenne de 10 exécutions) : 0,780 seconde

( SQL_NO_CACHEclé ajoutée pour empêcher MySQL de mettre en cache les requêtes.)


1
Pensez à inclure la suggestion de @ fu-chi dans vos tests, cela pourrait s'avérer encore plus efficace. De plus, vous avez testé GROUP BY YEAR(record_date)*100 + MONTH(record_date), mais pourquoi ne pas tester GROUP BY YEAR(record_date), MONTH(record_date)également?
Andriy M

2
Si vous utilisez COUNT (1) insteed COUNT (*), ce sera encore plus rapide et les données de résultat seront les mêmes.
Pa0l0

2
Qu'est-ce que c'est *100sur la versión # 2? Merci d'avance.
Avión

1
*100àYEAR(record_date)*100 + MONTH(record_date) == DATE_FORMAT(record_date, '%Y%m')
Phu Duy

17

Si vous souhaitez regrouper par date dans MySQL, utilisez le code ci-dessous:

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

J'espère que cela fait gagner du temps à ceux qui vont trouver ce fil.


6
Il est important de noter que vous devez également regrouper MONTH(record_date)les données pour tenir compte de plusieurs mois.
Webnet

14

Si vous souhaitez filtrer les enregistrements d'une année particulière (par exemple 2000), optimisez la WHEREclause comme ceci:

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.

Au lieu de:

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

Les résultats ont été générés par rapport à un tableau contenant 300 000 lignes et une colonne d'index sur la date.

Quant à la GROUP BYclause, j'ai testé les trois variantes par rapport au tableau mentionné ci-dessus; Voici les résultats:

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.

Le dernier est le gagnant.


10

Solution complète et simple avec une alternative similaire, plus performante mais plus courte et plus flexible actuellement active:

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

7

Si vous souhaitez obtenir des statistiques mensuelles avec le nombre de lignes par mois de chaque année ordonné par le dernier mois, essayez ceci:

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

7

Vous pouvez le faire simplement avec la fonction Mysql DATE_FORMAT () dans GROUP BY. Vous voudrez peut-être ajouter une colonne supplémentaire pour plus de clarté dans certains cas, par exemple lorsque les enregistrements s'étalent sur plusieurs années, puis le même mois se produit sur différentes années. Voici autant d'options que vous pouvez personnaliser. Veuillez lire ceci avant de commencer. J'espère que cela devrait être très utile pour vous. Voici un exemple de requête pour votre compréhension

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 ');

4

La requête suivante a fonctionné pour moi dans Oracle Database 12c version 12.1.0.1.0

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

2

Je préfère optimiser la sélection de groupe d'un an comme suit:

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

De cette façon, vous pouvez simplement lier l'année en une seule fois, par exemple '2009', avec un paramètre nommé et ne pas avoir à vous soucier d'ajouter '-01-01'ou de passer '2010'séparément.

En outre, comme sans doute nous comptons simplement des lignes et idest jamais NULL, je préfère COUNT(*)à COUNT(id).


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


Ce serait très très lent.
earl3s
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.