2010-04-16 28 views
5

Tengo una tabla de mysql llamada usuario (id, name, join_on) join on es un campo de fecha. Lo que quiero es mostrar cada día cuántos usos se han creado. Puedo usar group by pero sólo me dará las fechas en las que los usuarios se agregan como si fechaquería obtener todas las fechas en el resultado de mysql

4/12/10 5 users added 
4/13/10 2 users added 
4/15/10 7 users added 

aquí datan 4/14/10 falta y quiero lista de todas las fechas en un mes. Tengo una solución para ello al crear otra tabla solo para agregar fecha y esa tabla quedará unida a mi tabla de usuarios en join_on y dará un resultado total, pero no quiero hacer eso para crear eso. Necesito crear y agregar las entradas en la tabla de fechas sugieren el diferente enfoque para hacerlo.

Gracias.

+0

+1 lo he hecho en código (fuera de SQL), pero muy interesante ver si algunas soluciones limpias SQL de sólo aparecerá – Tomas

+0

Este es un comúnmente preguntado y respondido a la pregunta sobre el SO (búsqueda de 'date 'y' [sql] 'o' [mysql] '). Véase, por ejemplo, http://stackoverflow.com/questions/1046865/mysql-select-all-dates-in-a-range-even-if-no-records-present – pilcrow

+0

@pilcrow: es una pregunta frecuente, pero la respuesta vinculada no es particularmente exhaustiva en los detalles. @OP: normalmente este tipo de cosas no es tan fácil en las bases de datos que no admiten SQL recursivo; todavía publiqué algunos SQL (con algunos problemas, pero podría ser útil) – Unreason

Respuesta

2

Hay un enfoque eso puede hacer esto en SQL puro pero tiene limitaciones.

Primero debe tener una secuencia de números 1,2,3 ... n como filas (suponga que select row from rows lo devuelve).

Luego puede unirse a esto y convertir a fechas en función del número de días entre min y max.

select @min_join_on := (select min(join_on) from user); 
select @no_rows := (select datediff(max(join_on), @min_join_on) from user)+1; 

le dará el número requerido de filas, que luego se puede utilizar para

select adddate(@min_join_on, interval row day) from rows where row <= @no_rows; 

devolverá una secuencia necesaria de fechas en las que a continuación, puede hacer una combinación izquierda de nuevo a la tabla de usuarios .
Se pueden evitar el uso de variables si utiliza subconsultas, lo descompuse para facilitar la lectura.

Ahora, el problema es que el número de filas en la tabla rows tiene que ser mayor que @no_rows. Para 10.000 filas puede trabajar con rangos de fechas de hasta 27 años, con 100.000 filas puede trabajar con rangos de fechas de hasta 273 años (esto se siente realmente mal, pero me temo que si no desea utilizar almacenado procedimientos que tendrá que verse y sentirse incómodo).

lo tanto, si se puede trabajar con una fecha fija rangos incluso se puede sustituir la mesa con la consulta, como este

SELECT @row := @row + 1 as row FROM (select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) t, (select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) t2, (select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) t3, (select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) t4, (SELECT @row:=0) r 

que producirá 10.000 filas que van de 1 a 10.000 y que no habrá terriblemente ineficiente en eso.

Por lo tanto, al final es factible en una sola consulta.

create table user(id INT NOT NULL AUTO_INCREMENT, name varchar(100), join_on date, PRIMARY KEY(id)); 

mysql> select * from user; 
+----+-------+------------+ 
| id | name | join_on | 
+----+-------+------------+ 
| 1 | user1 | 2010-04-02 | 
| 2 | user2 | 2010-04-04 | 
| 3 | user3 | 2010-04-08 | 
| 4 | user4 | 2010-04-08 | 
+----+-------+------------+ 
4 rows in set (0.00 sec) 

insert into user values (null, 'user1', '2010-04-02'), (null, 'user2', '2010-04-04'), (null, 'user3', '2010-04-08'), (null, 'user4', '2010-04-08') 


SELECT date, count(id) 
FROM (
SELECT adddate((select min(join_on) from user), row-1) as date 
FROM ( 
SELECT @row := @row + 1 as row FROM (select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) t, (select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) t2, (SELECT @row:=0) r) n 
WHERE n.row <= (select datediff(max(join_on), min(join_on)) from user) + 1 
) dr LEFT JOIN user u ON dr.date = u.join_on 
GROUP BY dr.date 

+------------+-----------+ 
| date  | count(id) | 
+------------+-----------+ 
| 2010-04-02 |   1 | 
| 2010-04-03 |   0 | 
| 2010-04-04 |   1 | 
| 2010-04-05 |   0 | 
| 2010-04-06 |   0 | 
| 2010-04-07 |   0 | 
| 2010-04-08 |   2 | 
+------------+-----------+ 
7 rows in set (0.00 sec) 
4

Puede ser más simple usar GROUP BY y luego en su código actual agregar las fechas faltantes (o iterar a través de todo el rango de fechas y generar un cero si la fecha no aparece en los resultados de la consulta).

No todo tiene que resolverse en SQL, y muchas cosas son más fáciles de resolver en otros lugares. :)

+0

gracias por la respuesta, pero quiero hacerlo solo en sql, ya que quiero hacer algunas cosas más con él, y además de eso, aprenderé un poco más. adelgaza demasiado :) –

1
SELECT * FROM TABLE WHERE DATE LIKE '4/%/10' 

Este u dará todos los datos para el mes de Abril de 2010

Del mismo modo u puede obtener datos de cualquier mes especificando es decir, valor numérico 4 del mes en este caso

+0

no es como quiero obtener la fecha del rango solamente también quiero obtener todas las otras fechas que no están en mis registros –

+1

Debe trabajar con las fechas como fechas, no como cadenas. El código anterior podría proporcionarle información para el mes de abril o podría darle el 4 de cada mes, o finalmente podría darle un error. – Unreason

+0

@PankajK: en ese caso, puede haber puesto el código en su programa a/c ur necesita. Podría hacerse mediante consultas, pero eso aumentará el tiempo de ejecución – nik

Cuestiones relacionadas