2010-04-16 3 views
5

J'ai mysql table appelé utilisateur (id, nom, join_on) rejoindre sur est un champ de date ce que je veux est de montrer dans chaque jour combien d'utilisations a été créé, je peux utiliser le groupe par mais il ne me donner les dates auxquelles les utilisateurs sont ajoutés comme si Datevoulait obtenir toutes les dates dans le résultat mysql

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

récents ici 14/04/10 manque et je veux la liste de toutes les dates dans un mois. J'ai une solution pour cela en créant une autre table uniquement pour l'ajout de date et cette table sera ajoutée à ma table users sur join_on et donnera le résultat total mais je ne veux pas faire ça pour créer que j'ai besoin de créer et ajouter les entrées dans le tableau des dates, veuillez suggérer l'approche différente pour ce faire.

Merci.

+0

+1 Je l'ai fait dans le code (en dehors de SQL) mais très intéressant de voir si des solutions propres SQL uniquement surgiront – Tomas

+0

Ceci est un souvent posée et répondu à la question sur le SO (recherche de 'jour 'et' [sql] 'ou' [mysql] '). Voir, par exemple, http://stackoverflow.com/questions/1046865/mysql-select-all-dates-in-a-range-even-if-no-records-present – pilcrow

+0

@pilcrow: c'est une question fréquemment posée, mais la réponse liée n'est pas particulièrement exhaustive dans les détails. @OP: normalement ce genre de chose n'est pas si facile dans les bases de données qui ne supportent pas le SQL récursif; J'ai quand même posté un peu de SQL (avec quelques problèmes, mais ça pourrait être utile) – Unreason

Répondre

2

données de tout mois Il y a une approche cela peut le faire en pur SQL mais il a des limites.

Vous devez d'abord avoir une séquence de nombres 1,2,3 ... n en tant que lignes (supposons que select row from rows renvoie cela).

Ensuite, vous pouvez vous joindre à cela et convertir en dates en fonction du nombre de jours entre min et 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; 

vous donnera le nombre requis de lignes, ce qui vous pouvez utiliser pour

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

renverra une séquence requise de dates auxquelles vous pouvez faire une gauche rejoindre à la table des utilisateurs .
L'utilisation de variables peut être évitée si vous utilisez des sous-requêtes, je l'ai décomposé pour la lisibilité.

Maintenant, le problème est que le nombre de lignes dans la table rows doit être plus grand que @no_rows. Pour 10 000 lignes, vous pouvez travailler avec des plages de dates allant jusqu'à 27 ans, avec 100 000 lignes, vous pouvez travailler avec des plages de dates allant jusqu'à 273 ans (cela semble vraiment mauvais, mais je crains que si vous ne voulez pas utiliser procédures, il faudra regarder et se sentir maladroit). Alors

, si vous pouvez travailler avec cette date fixe plages vous pouvez même remplacer la table à la requête, comme ce

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 

qui produira 10.000 lignes allant de 1 à 10 000 et il ne sera pas terriblement inefficace. Donc, à la fin, c'est faisable dans une seule requête.

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

Il est peut-être plus simple d'utiliser GROUP BY et ensuite dans votre code actuel ajouter les dates manquantes (ou parcourir toute la plage de dates et afficher un zéro si la date manque dans les résultats de la requête).

Tout ne doit pas être résolu en SQL, et beaucoup de choses sont plus faciles à résoudre ailleurs. :)

+0

merci pour la réponse mais je veux le faire seulement en sql car je veux faire plus de choses avec ça, et à part ça je vais apprendre un peu plus thins trop :) –

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

Cela donnera u toutes les données pour le mois d'avril 2010

De même u peut obtenir en spécifiant la valeur numérique de mois soit 4 dans ce cas

+0

ce n'est pas comme je veux obtenir la date de la gamme seulement Je veux aussi obtenir toutes les autres dates qui ne sont pas dans mes dossiers –

+1

Vous devriez travailler avec des dates comme des dates, pas des chaînes. Le code ci-dessus pourrait vous donner des données pour le mois d'avril ou il pourrait vous donner le 4ème de chaque mois, ou finalement il pourrait vous donner une erreur. – Unreason

+0

@PankajK: dans ce cas, vous pouvez avoir mis le code dans votre programme a/c ur besoin. Cela pourrait être fait par des requêtes mais cela augmentera le temps d'exécution – nik

Questions connexes