Regrouper par mois et par année dans MySQL


95

Étant donné une table avec un horodatage sur chaque ligne, comment formeriez-vous la requête pour qu'elle tienne dans ce format d'objet json spécifique.

J'essaye d'organiser un objet json en années / mois.

json pour baser la requête:

{
  "2009":["August","July","September"],
  "2010":["January", "February", "October"]
}

Voici la requête que j'ai jusqu'à présent -

SELECT
    MONTHNAME(t.summaryDateTime) as month, YEAR(t.summaryDateTime) as year
FROM
    trading_summary t 
GROUP BY MONTH(t.summaryDateTime) DESC";

La requête s'effondre car elle regroupe (de manière prévisible) les différentes années.

Réponses:


185
GROUP BY YEAR(t.summaryDateTime), MONTH(t.summaryDateTime) DESC;

est ce que vous voulez.


60
+1: Une autre alternative utilisant DATE_FORMAT :DATE_FORMAT(t.summaryDateTime, '%Y-%m')
OMG Ponies

3
De plus, FROM_UNIXTIME est nécessaire si vous avez un horodatage UNIX dans votre base de donnéesDATE_FORMAT( FROM_UNIXTIME(t.summaryDateTime), '%Y-%m' )
Duncanmoo

Merci @OMGPonies, avec votre syntaxe, je suis capable d'effectuer un GROUP BY conditionnel.
Henry le

Performances ... mon test de GROUP BY YEAR(date), MONTH(date) DESC;(~ 450 ms) et GROUP BY DATE_FORMAT(date,'%Y-%m')(~ 850 ms) sur une table InnoDB avec plus de 300 000 entrées a montré que la première (la réponse marquée à cette question) a pris environ la moitié du temps que la seconde.
ow3n

77
GROUP BY DATE_FORMAT(summaryDateTime,'%Y-%m')

Bienvenue dans StackOverflow! C'est une question ancienne et déjà répondue. Nous serons heureux si vous pouviez également contribuer à des questions plus urgentes. Vous pouvez trouver des conseils pour fournir de bonnes réponses ici .
Mifeet le

Voir mon commentaire sur la réponse ci-dessus ... Sur les tables volumineuses, cette méthode prend deux fois plus de temps.
ow3n

9

je préfère

SELECT
    MONTHNAME(t.summaryDateTime) as month, YEAR(t.summaryDateTime) as year
FROM
    trading_summary t 
GROUP BY EXTRACT(YEAR_MONTH FROM t.summaryDateTime) DESC";

8
SELECT MONTHNAME(t.summaryDateTime) as month, YEAR(t.summaryDateTime) as year
FROM trading_summary t
GROUP BY YEAR(t.summaryDateTime) DESC, MONTH(t.summaryDateTime) DESC

Doit utiliser DESC pour l'année et le mois pour obtenir un ordre correct.


7

Je sais que c'est une vieille question, mais la suivante devrait fonctionner si vous n'avez pas besoin du nom du mois au niveau de la base de données:

  SELECT EXTRACT(YEAR_MONTH FROM summaryDateTime) summary_year_month 
    FROM trading_summary  
GROUP BY summary_year_month;

Voir la documentation de la fonction EXTRACT

Vous trouverez probablement que cela est plus performant .. et si vous construisez un objet JSON dans la couche d'application, vous pouvez effectuer le formatage / classement au fur et à mesure que vous parcourez les résultats.

NB Je ne savais pas que vous pouviez ajouter DESC à une clause GROUP BY dans MySQL, il vous manque peut-être une clause ORDER BY:

  SELECT EXTRACT(YEAR_MONTH FROM summaryDateTime) summary_year_month 
    FROM trading_summary  
GROUP BY summary_year_month
ORDER BY summary_year_month DESC;

1
veuillez noter que la sortie de EXTRACT(YEAR_MONTH FROM summaryDateTime)est201901
Edgar Ortega

@EdgarOrtega Oui, mais cela devrait être suffisant pour générer l'objet JSON souhaité dans la question d'origine à l'aide de la logique d'application. En supposant qu'une forme de boucle sur le résultat de la requête se produit déjà, mon approche vise à obtenir les informations minimales requises de la base de données aussi simplement et rapidement que possible
Arth

1
Vous avez raison, cela devrait suffire. Mon commentaire était seulement pour indiquer à quoi ressemble la sortie de cette fonction, peut-être que quelqu'un n'aime pas ce format.
Edgar Ortega

@EdgarOrtega Pas de soucis, merci, une belle contribution!
Arth

2

Tu dois faire quelque chose comme ça

SELECT onDay, id, 
sum(pxLow)/count(*),sum(pxLow),count(`*`),
CONCAT(YEAR(onDay),"-",MONTH(onDay)) as sdate 
FROM ... where stockParent_id =16120 group by sdate order by onDay

2

Tu vas aussi faire ça

SELECT  SUM(amnt) `value`,DATE_FORMAT(dtrg,'%m-%y') AS label FROM rentpay GROUP BY YEAR(dtrg) DESC, MONTH(dtrg) DESC LIMIT 12

à commander par année et par mois. Disons que vous souhaitez commander à partir de cette année et ce mois-ci jusqu'à 12 mois


1

utilisez la fonction EXTRACT comme ceci

mysql> SELECT EXTRACT(YEAR FROM '2009-07-02');
       -> 2009

1

Voici comment je fais:

GROUP BY  EXTRACT(YEAR_MONTH FROM t.summaryDateTime);


0
SELECT YEAR(t.summaryDateTime) as yr, GROUP_CONCAT(MONTHNAME(t.summaryDateTime)) AS month 
FROM trading_summary t GROUP BY yr

Vous devrez néanmoins le traiter dans un script externe pour obtenir exactement la structure que vous recherchez.

Par exemple, utilisez l'explosion de PHP pour créer un tableau à partir de la liste des noms de mois, puis utilisez json_encode ()


-2

Utilisation

GROUP BY year, month DESC";

Au lieu de

GROUP BY MONTH(t.summaryDateTime) DESC";

bien qu'il semble que GROUP BY MONTH (t.summaryDateTime) DESC ne commande pas correctement les mois pour une raison quelconque ...
Derek Adair
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.