Come raggruppare per settimana in MySQL?


92

Offerte Server Tabella di Oracle un built-in funzione TRUNC(timestamp,'DY'). Questa funzione converte qualsiasi timestamp alla mezzanotte della domenica precedente. Qual è il modo migliore per farlo in MySQL?

Oracle offre anche TRUNC(timestamp,'MM')di convertire un timestamp a mezzanotte del primo giorno del mese in cui si verifica. In MySQL, questo è semplice:

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

Ma questo DATE_FORMATtrucco non funzionerà per settimane. Sono a conoscenza della WEEK(timestamp)funzione, ma davvero non voglio il numero della settimana entro l'anno; questa roba è per lavori pluriennali.


intendi trunc (sysdate, 'W'), non trunc (sysdate, 'DY')
— David Aldridge

TRUNC(date, 'DY' )ottiene settimane con un inizio di domenica. 'W'inizia il lunedì, almeno nel mio sistema.
— O. Jones

Risposte:


123

È possibile utilizzare entrambi YEAR(timestamp)e WEEK(timestamp), e utilizzare entrambi i queste espressioni nella SELECTe della GROUP BYclausola.

Non eccessivamente elegante, ma funzionale ...

E ovviamente puoi anche combinare queste due parti della data in un'unica espressione, cioè qualcosa di simile

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

Modifica : come sottolinea Martin , puoi anche utilizzare la YEARWEEK(mysqldatefield)funzione, sebbene il suo output non sia così facile da vedere come la formula più lunga sopra.


Modifica 2 [3 anni e mezzo dopo!]:
YEARWEEK(mysqldatefield)Con il secondo argomento opzionale ( mode) impostato su 0 o 2 è probabilmente il modo migliore per aggregare per settimane complete (cioè includendo per settimane che si trovano a cavallo del 1 ° gennaio), se questo è ciò che si desidera. L' YEAR() / WEEK()approccio inizialmente proposto in questa risposta ha l'effetto di suddividere i dati aggregati per tali settimane "a cavallo tra" in due: uno con l'anno precedente, uno con il nuovo anno.
Un taglio netto ogni anno, a costo di avere fino a due settimane parziali, una per ciascuna estremità, è spesso richiesto in contabilità ecc. E per questo l' YEAR() / WEEK()approccio è migliore.


12
YEARWEEK()risultati in un INT(6)che credo sarà più veloce da ordinare / partecipare / raggruppare con
— KCD

@mjv: cosa succede quando due anni condividono la stessa settimana? come per questo dal 31-12-2012 al 6-1-2013 (dal lunedì alla domenica). c'è qualche soluzione a questo ?
— hardik

@hardik: vedere Modifica 2. A seconda delle proprie esigenze YEARWEEK () può essere una chiave migliore su cui aggregarsi, se si preferisce lavorare con settimane complete piuttosto che dividere l'ultima / prima settimana parziale dell'anno.
— mjv

@mjv ecco un'altra soluzione per quel collegamento
— hardik

assicurati che il "timestamp" non sia un numero intero, come avevo nella mia tabella. WEEK (timestamp) accetta il tipo di colonna data / timestamp come argomento valido
— Usman Shaukat

37

La risposta accettata sopra non ha funzionato per me, perché ha ordinato le settimane in ordine alfabetico, non in ordine cronologico:

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

Ecco la mia soluzione per contare e raggruppare per settimana:

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

Genera:

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

5
anche l'ordinazione per data ( ORDER BY date ASC) dovrebbe funzionare
— Fender

36

Capito ... è un po 'ingombrante, ma eccolo qui.

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

E, se le regole della tua azienda dicono che le tue settimane iniziano il lunedì, cambia -1in -2.


modificare

Sono passati anni e finalmente sono riuscito a scriverlo. http://www.plumislandmedia.net/mysql/sql-reporting-time-intervals/


@Ollie: prenderei in considerazione l'utilizzo di DAYOFWEEK () o WEEKDAY () per facilitare la leggibilità.
— martin clayton

1
Martin, ci ho pensato e ho scoperto che quelle funzioni funzionano da 0 a 6 dal lunedì alla domenica. Le mie regole aziendali dicono che le settimane iniziano la domenica alle 00:00, quindi le cose WEEKDAY sono diventate un po 'brutte. Hai ragione sulla leggibilità.
— O. Jones,

@OllieJones perfetto! Grazie mille!
— Joe Cheng

1
Ottima soluzione e articolo. Grazie!
— Jeremy Wiggins

C'è un modo per impostare "lunedì" come primo giorno?
— Pedro Joaquín

25

È possibile ottenere l'anno e il numero della settimana concatenati (200945) utilizzando la funzione YEARWEEK () . Se comprendo correttamente il tuo obiettivo, ciò dovrebbe consentirti di raggruppare i tuoi dati pluriennali.

Se hai bisogno del timestamp effettivo per l'inizio della settimana, è meno carino:

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

Per l'ordinamento mensile, potresti prendere in considerazione la funzione LAST_DAY () - l'ordinamento sarebbe per l'ultimo giorno del mese, ma dovrebbe essere equivalente all'ordinamento per il primo giorno del mese ... non dovrebbe?


1
+1 Martin. Duh per me mi sono dimenticato di YEARWEEK () ... Non lo uso molto.
— mjv

4

Basta aggiungere questo nella selezione:

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

E

group_by(week);

come raggruppare per mese
— Ravi Teja

Non
— acquisisce

2

Se hai bisogno della data di "fine settimana", anche questa funzionerà. Questo conterà il numero di record per ogni settimana. Esempio: se tre ordini di lavoro sono stati creati tra (incluso) 1/2/2010 e 1/8/2010 e 5 sono stati creati tra (incluso) 1/9/2010 e 1/16/2010, ciò restituirebbe:

3 1/8/2010
5

Ho dovuto usare la funzione DATE () extra per troncare il mio campo 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;
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.