web-dev-qa-db-fra.com

Comment grouper par semaine dans MySQL?

Le serveur de table Oracle propose une fonction intégrée, TRUNC(timestamp,'DY'). Cette fonction convertit l’horodatage à minuit le dimanche précédent. Quelle est la meilleure façon de faire cela dans MySQL?

Oracle propose également la fonction TRUNC(timestamp,'MM') pour convertir un horodatage en minuit le premier jour du mois au cours duquel il se produit. Dans MySQL, celui-ci est simple:

TIMESTAMP(DATE_FORMAT(timestamp, '%Y-%m-01'))

Mais cette astuce DATE_FORMAT Ne fonctionnera pas avant des semaines. Je suis conscient de la fonction WEEK(timestamp), mais je ne veux vraiment pas de numéro de semaine dans l'année; ce truc est pour un travail pluriannuel.

75
O. Jones

Je l'ai compris ... c'est un peu lourd, mais le voici.

FROM_DAYS(TO_DAYS(TIMESTAMP) -MOD(TO_DAYS(TIMESTAMP) -1, 7))

Et, si vos règles commerciales prévoient que vos semaines commencent le lundi, modifiez le -1 à -2.


Modifier

Des années ont passé et je me suis enfin mis à écrire ça. http://www.plumislandmedia.net/mysql/sql-reporting-time-intervals/

25
O. Jones

Vous pouvez utiliser à la fois YEAR(timestamp) et WEEK(timestamp) , et utiliser les deux expressions suivantes dans SELECT et la clause GROUP BY.

Pas trop élégant, mais fonctionnel ...

Et bien sûr, vous pouvez également combiner ces deux parties de date dans une seule expression, c'est-à-dire quelque chose comme:

SELECT CONCAT(YEAR(timestamp), '/', WEEK(timestamp)), etc...
FROM ...
WHERE ..
GROUP BY CONCAT(YEAR(timestamp), '/', WEEK(timestamp))

Edit : Comme Martin fait remarquer , vous pouvez également utiliser le YEARWEEK(mysqldatefield) fonction, bien que sa sortie ne soit pas aussi agréable pour les yeux que la formule plus longue ci-dessus.


Modifier 2 [3 ans et demi plus tard!]:
YEARWEEK(mysqldatefield) avec le deuxième argument optionnel ( mode ) défini sur 0 ou 2 est probablement le meilleur moyen agréger par complète semaines (c'est-à-dire y compris pour les semaines chevauchant le 1er janvier), si c'est ce que vous souhaitez. L’approche YEAR() / WEEK() initialement proposée dans cette réponse a pour effet de scinder les données agrégées de telles "chevauchements" en deux semaines: une avec l’année précédente, une avec la nouvelle an.
Une comptabilité nette chaque année, au prix de deux semaines partielles, une à chaque extrémité, est souvent souhaitée en comptabilité, etc. et pour cette raison, la méthode YEAR() / WEEK() est meilleure.

102
mjv

La réponse acceptée ci-dessus n'a pas fonctionné pour moi, car elle a ordonné les semaines par ordre alphabétique et non par ordre chronologique:

2012/1
2012/10
2012/11
...
2012/19
2012/2

Voici ma solution pour compter et grouper par semaine:

SELECT CONCAT(YEAR(date), '/', WEEK(date)) AS week_name, 
       YEAR(date), WEEK(date), COUNT(*)
FROM column_name
GROUP BY week_name
ORDER BY YEAR(DATE) ASC, WEEK(date) ASC

Génère:

YEAR/WEEK   YEAR   WEEK   COUNT
2011/51     2011    51      15
2011/52     2011    52      14
2012/1      2012    1       20
2012/2      2012    2       14
2012/3      2012    3       19
2012/4      2012    4       19
26
B Seven

Vous pouvez obtenir le numéro d'année et de semaine concaténés (200945) à l'aide de la fonction YEARWEEK () . Si je comprends bien votre objectif, cela devrait vous permettre de regrouper vos données pluriannuelles.

Si vous avez besoin de l'horodatage pour le début de la semaine, c'est moins sympa:

DATE_SUB( field, INTERVAL DAYOFWEEK( field ) - 1 DAY )

Pour les commandes mensuelles, vous pouvez envisager la fonction LAST_DAY () - le tri se fera selon le dernier jour du mois, mais cela devrait être équivalent au tri effectué le premier jour du mois ... si ce n'était pas le cas ?

22
martin clayton

Il suffit d’ajouter ceci dans la sélection:

DATE_FORMAT($yourDate, \'%X %V\') as week

Et

group_by(week);
4
Xavier

Si vous avez besoin de la date "fin de semaine", cela fonctionnera également. Cela comptera le nombre d'enregistrements pour chaque semaine. Exemple: si trois ordres de travail ont été créés entre le (inclus) 1/2/2010 et le 1/8/2010 et que 5 ont été créés entre le (inclus) 1/9/2010 et le 16/01/2010, ceci renverrait:

3 1/8/2010
5 1/16/2010

Je devais utiliser la fonction supplémentaire DATE () pour tronquer mon champ datetime.

SELECT COUNT(*), DATE_ADD( DATE(wo.date_created), INTERVAL (7 - DAYOFWEEK( wo.date_created )) DAY) week_ending FROM work_order wo GROUP BY week_ending;

2
Randy