2010-02-16 6 views
6

données:Comment obtenir des valeurs pour tous les jours dans un mois

values date 
14 1.1.2010 
20 1.1.2010 
10 2.1.2010 
7 4.1.2010 
... 

exemple de requête sur les janvier 2010 devrait obtenir 31 lignes. Un pour tous les jours. Et des valeurs seront ajoutées. En ce moment, je pourrais le faire avec 31 requêtes, mais je voudrais que cela fonctionne avec un. C'est possible?

résultats:

1. 34 
2. 10 
3. 0 
4. 7 
... 
+0

Bienvenue chez SO ivar. Je pense que vous devez ajouter plus de détails sur ce que vous interrogez et comment? –

+0

Plus de détails seraient nécessaires ... quelle langue utilisez-vous? Quel système est-ce? – Mala

+0

Quel est le type de votre colonne de date? Est-ce une DATE ou un VARCHAR? –

Répondre

10

C'est étonnamment difficile à faire en SQL. Une façon de le faire est d'avoir une longue déclaration select avec ALLs UNION pour générer les nombres de 1 à 31. Cela démontre le principe, mais je me suis arrêté à 4 pour plus de clarté:

SELECT MonthDate.Date, COALESCE(SUM(`values`), 0) AS Total 
FROM (
    SELECT 1 AS Date UNION ALL 
    SELECT 2 UNION ALL 
    SELECT 3 UNION ALL 
    SELECT 4 UNION ALL 
    -- 
    SELECT 28 UNION ALL 
    SELECT 29 UNION ALL 
    SELECT 30 UNION ALL 
    SELECT 31) AS MonthDate 
LEFT JOIN Table1 AS T1 
ON MonthDate.Date = DAY(T1.Date) 
AND MONTH(T1.Date) = 1 AND YEAR(T1.Date) = 2010 
WHERE MonthDate.Date <= DAY(LAST_DAY('2010-01-01')) 
GROUP BY MonthDate.Date 

Il pourrait être préférable d'utiliser un table pour stocker ces valeurs et se joindre à la place.

Résultat:

1, 34 
2, 10 
3, 0 
4, 7 
5

Étant donné que, pour certaines dates que vous avez pas de données, vous aurez besoin de combler les lacunes. Une approche à ceci est d'avoir une table de calendrier préremplie avec toutes les dates dont vous avez besoin, et se joindre à cela. Si vous souhaitez que les résultats affichent les numéros de jour comme vous l'avez indiqué dans votre question, vous pouvez également les insérer dans votre calendrier en tant qu'étiquettes.

Vous joindrez votre champ de date de la table de données au champ de date de la table du calendrier, au groupe correspondant à ce champ et aux valeurs de somme. Vous pouvez spécifier des limites pour la plage de dates couverte.

Alors vous pourriez avoir:

CREATE TABLE Calendar (
    label varchar, 
    cal_date date, 
    primary key (cal_date) 
) 

Requête:

SELECT 
    c.label, 
    SUM(d.values) 
FROM 
    Calendar c 
JOIN 
    Data_table d 
ON d.date_field = c.cal_date 
WHERE 
    c.cal_date BETWEEN '2010-01-01' AND '2010-01-31' 
GROUP BY 
    d.date_field 
ORDER BY 
    d.date_field 

Mise à jour:

Je vois que vous avez datetimes plutôt que des dates. Vous pouvez simplement utiliser la fonction MySQL DATE() dans la jointure, mais cela ne sera probablement pas optimal. Une autre approche consisterait à avoir des heures de début et de fin dans la table Calendrier définissant un «intervalle de temps» pour chaque jour.

0

Si je comprends bien la question assez vague, vous voulez connaître le nombre d'enregistrements pour chaque jour dans un mois. Si cela est vrai, voici comment vous pouvez le faire:

SELECT COUNT(value_column) FROM table WHERE date_column LIKE '2010-01-%' GROUP BY date_column 
+0

date_column n'est pas définie – NineCattoRules

+1

@NineCattoRules À moins que vous ne soyez l'OP d'il y a sept ans, je ne sais pas comment vous le sauriez. Si c'est le cas, la requête peut facilement être modifiée pour s'ajuster. – ceejayoz

+0

dans la question "... pour chaque jour ..." et dans 'results' (de OP) il y a' 3. 0' – NineCattoRules

1

Pour obtenir dynamiquement les dates dans une plage de dates en utilisant SQL, vous pouvez le faire (par exemple dans une base MySQL):

Créer une table pour contenir les numéros 0 à 9.

CREATE TABLE ints (i tinyint(4)); 

insert into ints (i) 
values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); 

exécuter une requête comme ceci:

select ((curdate() - interval 2 year) + interval (t.i * 100 + u.i * 10 + v.i) day) AS Date 
from 
    ints t 
    join ints u 
    join ints v 
having Date between '2015-01-01' and '2015-05-01' 
order by t.i, u.i, v.i 

Cela va générer toutes les dates entre 1er janvier 2015 et 1er mai 2015.

Output 
2015-01-01 
2015-01-02 
2015-01-03 
2015-01-04 
2015-01-05 
2015-01-06 
... 
2015-05-01 

La requête joint la table ints 3 fois et obtient un nombre d'incrémentation (0 à 999). Il ajoute ensuite ce nombre en tant qu'intervalle de jour à partir d'une certaine date, en l'occurrence une date il y a 2 ans. Il est possible d'obtenir toute période de 2 ans et de 1 000 jours avec l'exemple ci-dessus. Pour générer une requête qui génère des dates pour plus de 1 000 jours, il suffit de rejoindre la table ints une fois de plus pour autoriser jusqu'à 10 000 jours d'intervalle, et ainsi de suite.

1

Cela fonctionne pour moi ... C'est une modification d'une requête que j'ai trouvée sur un autre site. La clause "INTERVAL 1 MONTH" garantit que je reçois les données du mois en cours, y compris les zéros pour les jours qui n'ont pas de hits. Changez cela en "INTERVAL 2 MOIS" pour obtenir les données du dernier mois, etc.

J'ai une table appelée "payload" avec une colonne "timestamp" - Im puis joignant la colonne timestamp aux dates générées dynamiquement, en la moulant de sorte que les dates correspondent dans la clause ON.


SELECT `calendarday`,COUNT(P.`timestamp`) AS `cnt` FROM 
(SELECT @tmpdate := DATE_ADD(@tmpdate, INTERVAL 1 DAY) `calendarday` 
    FROM (SELECT @tmpdate := 
     LAST_DAY(DATE_SUB(CURDATE(),INTERVAL 1 MONTH))) 
     AS `dynamic`, `payload`) AS `calendar` 
LEFT JOIN `payload` P ON DATE(P.`timestamp`) = `calendarday` 
GROUP BY `calendarday` 
Questions connexes