2009-02-03 23 views
494

¿Es posible hacer una consulta simple para contar cuántos registros tengo en un período de tiempo determinado como un año, mes o día, teniendo un campo TIMESTAMP, como:MySQL Query GROUP POR día/mes/año

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

O incluso:

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

Para tener una estadística mensual.

Gracias!

+1

supongo que se supone que es 'GROUP BY en record_date.MONTH' ¿Tu primer fragmento de código? – chiccodoro

Respuesta

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

Compruebe el date and time functions en MySQL.

+14

Es posible que desee agregar una columna adicional para mayor claridad en algunos casos, como cuando los registros abarcan varios años. SELECT COUNT (event_id), DATE_FORMAT (event_start, '% Y /% m') –

+0

Ejemplo completo simple: 'SELECT count (*), record_date FROM anytable WHERE anytable.anycolumn = 'anycondition' GROUP BY YEAR (record_date), month (record_date); 'note: record_date es un tipo de fecha TIMESTAMP – renedet

+0

Probablemente valga la pena mencionar que esto no se ejecutó en MySQL 5.7 con una columna COUNT aliased (no hay error, obtuve cero resultados). Cuando cambié para seleccionar esos campos con alias, podía agrupar por el alias. Esta es la imagen estándar de docker de MySQL 5.7 que se ejecuta en un entorno local, así que no tengo idea de por qué no cometió un error o no devolvió los resultados. – MrMesees

36

He intentado usar la instrucción 'DONDE' anterior, pensé que era correcto ya que nadie lo corrigió pero estaba equivocado; después de algunas búsquedas descubrí que esta es la fórmula correcta para la instrucción WHERE por lo que el código se convierte de esta manera:

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

En realidad, puede omitir 'AÑO (record_date)' de GROUP BY ya que está limitando los datos a un solo año. –

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

Nota (principalmente, a downvoters potenciales). En la actualidad, esto puede no ser tan eficiente como otras sugerencias. Aún así, lo dejo como una alternativa, y una, también, que puede servir para ver qué tan rápido otras soluciones son. (Porque realmente no se puede decir rápido desde lento hasta que se ve la diferencia.) Además, a medida que pasa el tiempo, se podrían hacer cambios en el motor de MySQL con respecto a la optimización para hacer esta solución, en algunos (quizás, no tan distante) punto en el futuro, para ser bastante comparable en eficiencia con la mayoría de los demás.

+1

Tengo la sensación de que esto no funcionaría bien porque una función de formato no podría usar un índice en la columna de fecha. – Sonny

+0

@Stv: Es posible que desee considerar la respuesta de [@ fu-chi] (http://stackoverflow.com/a/7721169/297408). Por lo que puedo decir, las expresiones de agrupamiento tanto en la respuesta como en la mía evalúan lo mismo pero 'EXTRACT()' puede ser más eficiente que 'DATE_FORMAT()'. (No tengo un MySQL para las pruebas adecuadas, sin embargo). –

14

Si desea agrupar por fecha en MySQL a continuación, utilizar el código de abajo:

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

Hope esto ahorra algo de tiempo para los que se van a encontrar este hilo.

+5

Es importante tener en cuenta que también deberá agrupar por 'MES (fecha_registro)' y contabilizar varios meses. – Webnet

32

tratar esta función se

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

EXTRACT(unit FROM date) es mejor como menos agrupación se utiliza y la función devuelve un valor numérico.

Condición de comparación cuando la agrupación será más rápida que la función DATE_FORMAT (que devuelve un valor de cadena). Intente usar la función | campo que devuelve un valor que no sea cadena para la condición de comparación SQL (DONDE, TENER, ORDEN POR, GRUPO POR).

18

Si su búsqueda ha terminado varios años, y todavía se desean agrupar mensual, sugiero:

la versión # 1:

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

la versión # 2 (más eficiente) :

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

He comparado estas versiones o n una gran mesa con 1.357.918 filas (), y la segunda versión parece tener mejores resultados.

version1(promedio de 10 ejecuta): 1.404 segundos
version2(promedio de 10 ejecuta): 0.780 segundos

(SQL_NO_CACHE clave añadió para evitar MySQL de almacenamiento en caché para consultas .)

+1

Considere incluir la sugerencia de @ fu-chi en sus pruebas, puede resultar aún más eficiente. Además, probó 'GROUP BY YEAR (record_date) * 100 + MONTH (record_date)', pero ¿por qué no probar 'GROUP BY YEAR (record_date), MONTH (record_date)' también? –

+2

Si usa COUNT (1) cuenta INTELIGENTE (*), será aún más rápido y los datos de resultado serán los mismos. – Pa0l0

+0

¿Qué es eso '* 100' en la versión # 2? Gracias por adelantado. –

6

Si desea obtener una estadística mensual con recuentos de filas por mes de cada año ordenado por el último mes, intente esto:

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 
9

Si quiere filtrar los registros de un año en particular (p. 2000), entonces optimizar la cláusula WHERE como esto:

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. 

En lugar de:

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

Los resultados se generaron contra una tabla que contiene 300k filas y índice en la columna fecha.

En cuanto a la cláusula GROUP BY, probé las tres variantes en la tabla mencionada anteriormente; Aquí están los resultados:

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. 

El último es el ganador.

1

prefiero para optimizar la selección de un grupo de años, así:

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

De esta manera usted puede simplemente enlazar el año de una vez, por ejemplo, '2009', con un parámetro con nombre y no necesita preocuparse por agregar '-01-01' o pasar por '2010' por separado.

También, como presumiblemente sólo estamos contando filas y id no es NULL, prefiero COUNT(*)-COUNT(id).

4

La siguiente consulta trabajó para mí en la base de datos Oracle 12c Release 12.1.0.1.0

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

.... 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') ---> MAY

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

+0

Esto sería muy, muy lento. – earl3s

2

Puede hacerlo simplemente con la función Mysql DATE_FORMAT() en GROUP BY. Es posible que desee agregar una columna adicional para mayor claridad en algunos casos, como cuando los registros abarcan varios años, luego el mismo mes ocurre en diferentes años. Hay tantas opciones que puede personalizar esto. Por favor, lea esto antes de comenzar. Espero que sea muy útil para ti.Aquí es consulta de ejemplo por su comprensión

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

solución completa y sencilla con la realización de manera similar aún más corto y más flexible alternativa actualmente activo:

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