MySQL Query GROUP PER giorno / mese / anno


649

È possibile fare una semplice query per contare quanti record ho in un determinato periodo di tempo come un anno, un mese o un giorno, con un TIMESTAMPcampo, come:

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

O anche:

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

Avere una statistica mensile.

Grazie!


1
Immagino che dovrebbe essere GROUP BY record_date.MONTHnel tuo primo frammento di codice?
Chiccodoro,

Risposte:


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

Controlla le funzioni di data e ora in MySQL.


27
È possibile che si desideri aggiungere una colonna aggiuntiva per maggiore chiarezza in alcuni casi, ad esempio in cui i record durano diversi anni. SELECT COUNT (event_id), DATE_FORMAT (event_start, '% Y /% m')
Ric

Semplice esempio completo: SELECT count(*), record_date FROM anytable WHERE anytable.anycolumn = 'anycondition' GROUP BY YEAR(record_date), month(record_date);nota: record_date è un tipo di data TIMESTAMP
renedet

Probabilmente vale la pena ricordare che questo non è stato eseguito sul mio MySQL 5.7 con una colonna COUNT alias (nessun errore, ho ottenuto zero risultati). Quando ho cambiato per selezionare quei campi con alias, ho potuto quindi raggruppare in base all'alias. Questa è l'immagine docker MySQL 5.7 standard in esecuzione in un ambiente locale, quindi non ho idea del perché non abbia restituito errori o restituito risultati.
MrMesees,

3
Oddio, se lo avessi saputo prima ... così tante righe di PHP per fare qualcosa che mysql può fare in una riga.
notti

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

Nota (principalmente ai potenziali downvoter). Attualmente, questo potrebbe non essere efficiente come altri suggerimenti. Tuttavia, lo lascio come alternativa e anche uno che può servire a vedere quanto più veloci sono le altre soluzioni. (Perché non puoi davvero dire velocemente dal lento fino a quando non vedi la differenza.) Inoltre, col passare del tempo, potrebbero essere apportate modifiche al motore di MySQL per quanto riguarda l'ottimizzazione in modo da rendere questa soluzione, in alcuni (forse, non così distante) punto in futuro, per diventare abbastanza comparabili in termini di efficienza con la maggior parte degli altri.


3
Ho la sensazione che ciò non funzionerebbe bene perché una funzione di formattazione non sarebbe in grado di utilizzare un indice nella colonna della data.
Sonny,

@Stv: potresti prendere in considerazione la risposta di @ fu-chi allora. Per quanto ne so, le espressioni di raggruppamento sia in quella che nella mia risposta valutano la stessa cosa ma EXTRACT()possono essere più efficienti di DATE_FORMAT(). (Non ho un MySQL per i test corretti, però.)
Andriy M

45

prova questo

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

La funzione EXTRACT (unit FROM date) è migliore poiché viene utilizzato meno raggruppamento e la funzione restituisce un valore numerico.

La condizione di confronto durante il raggruppamento sarà più veloce della funzione DATE_FORMAT (che restituisce un valore di stringa). Prova a utilizzare il campo funzione | che restituisce un valore non stringa per la condizione di confronto SQL (WHERE, HAVING, ORDER BY, GROUP BY).


43

Ho provato a usare la frase "WHERE" sopra, ho pensato che fosse corretta poiché nessuno l'ha corretta ma mi sbagliavo; dopo alcune ricerche ho scoperto che questa è la formula giusta per l'istruzione WHERE, quindi il codice diventa così:

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

30

Se la tua ricerca dura da diversi anni e desideri comunque raggruppare mensilmente, ti suggerisco di:

versione n. 1:

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

versione # 2 (più efficiente) :

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

Ho confrontato queste versioni su un grande tavolo con 1.357.918 righe () e la seconda versione sembra avere risultati migliori.

versione1 (media di 10 esecuzioni) : 1,404 secondi
versione2 (media di 10 esecuzioni) : 0,780 secondi

( SQL_NO_CACHEchiave aggiunta per impedire a MySQL di memorizzare nella cache le query).


1
Considera di includere il suggerimento di @ fu-chi nei tuoi test, potrebbe rivelarsi ancora più efficiente. Inoltre, hai testato GROUP BY YEAR(record_date)*100 + MONTH(record_date), ma perché non testare anche tu GROUP BY YEAR(record_date), MONTH(record_date)?
Andriy M,

2
Se usi COUNT (1) contete COUNT (*) sarà ancora più veloce e i dati dei risultati saranno gli stessi.
Pa0l0

2
Cosa c'è *100nella versione 2? Grazie in anticipo.
Avión,

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

17

Se vuoi raggruppare per data in MySQL, usa il codice qui sotto:

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

Spero che questo risparmi un po 'di tempo per coloro che stanno per trovare questa discussione.


6
È importante notare che dovresti anche raggruppare MONTH(record_date)per tenere conto di più mesi.
Webnet,

14

Se si desidera filtrare i record per un determinato anno (ad es. 2000), ottimizzare la WHEREclausola in questo modo:

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.

Invece di:

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

I risultati sono stati generati su una tabella contenente 300k righe e indice sulla colonna della data.

Per quanto riguarda la GROUP BYclausola, ho testato le tre varianti rispetto alla tabella sopra menzionata; ecco i risultati:

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.

L'ultimo è il vincitore.


10

Soluzione completa e semplice con alternativa altrettanto performante ma più breve e più flessibile attualmente attiva:

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

Se desideri ottenere statistiche mensili con conteggi delle righe per mese di ogni anno ordinati per ultimo mese, prova questo:

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

Puoi farlo semplicemente Mysql DATE_FORMAT () funzione in GROUP BY. Potresti voler aggiungere una colonna in più per maggiore chiarezza in alcuni casi, ad esempio in cui i record si estendono per diversi anni, quindi lo stesso mese si verifica in anni diversi. Qui ci sono così tante opzioni che puoi personalizzare. Si prega di leggere questo prima di iniziare. Spero che ti possa essere di grande aiuto. Ecco una query di esempio per la tua comprensione

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 seguente query ha funzionato per me in Oracle Database 12c versione 12.1.0.1.0

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

2

Preferisco ottimizzare la selezione di gruppi di un anno in questo modo:

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

In questo modo puoi semplicemente associare l'anno in una volta, ad esempio '2009', con un parametro denominato e non devi preoccuparti di aggiungere '-01-01'o passare '2010'separatamente.

Inoltre, come presumibilmente stiamo solo contando le righe e idnon è mai NULL, preferisco COUNT(*)a 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') ---> MAGGIO

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


Questo sarebbe molto molto lento.
Earl3s
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.