2015-03-31 1 views
2

Disons que j'ai cette recherche requête comme ceci:Obtenez nombre d'entrées créées pour chaque jour

SELECT COUNT(id), date(created_at) 
FROM entries 
WHERE date(created_at) >= date(current_date - interval '1 week') 
GROUP BY date(created_at) 

Comme vous le savez alors, par exemple, j'obtenir un résultat en arrière comme ceci:

count | date 
    2 | 15.01.2014 
    1 | 13.01.2014 
    9 | 09.01.2014 

Mais je fais pas obtenir les jours de la semaine où aucune entrée n'a été créée.

Comment puis-je obtenir un résultat de recherche qui ressemble à ceci, en incluant les jours où aucune entrée n'a été créée?

count | date 
    2 | 15.01.2014 
    0 | 14.01.2014 
    1 | 13.01.2014 
    0 | 12.01.2014 
    0 | 11.01.2014 
    0 | 10.01.2014 
    9 | 09.01.2014 

Répondre

2
SELECT day, COALESCE(ct, 0) AS ct 
FROM (SELECT now::date - d AS day FROM generate_series (0, 6) d) d -- 6, not 7 
LEFT JOIN (
    SELECT created_at::date AS day, count(*) AS ct 
    FROM entries 
    WHERE created_at >= date_trunc('day', now()) - interval '6d' 
    GROUP BY 1 
    ) e USING (day); 
  • Utilisez une expression sargable pour votre condition WHERE, donc Postgres peut utiliser un indice clair sur created_at. Beaucoup plus important pour la performance que tout le reste.

  • Pour couvrir une semaine (y compris aujourd'hui), il faut soustraire 6 jours après le début de « aujourd'hui », et non 7.

  • En supposant que id est défini NOT NULL, count(*) est identique à count(id), mais un peu plus rapide .

  • Un CTE serait trop cher ici. C'est plus lent et plus verbeux.

  • Agréger en premier, rejoindre plus tard. C'est plus rapide dans ce cas.

  • now() est l'implémentation Postgres légèrement plus courte et plus rapide de la norme SQL CURRENT_TIMESTAMP (que vous pouvez également utiliser).

Cette requête devrait être la plus courte et la plus rapide. Test avec EXPLAIN ANALYZE.

connexes:

+0

Merci pour votre réponse! Si cela fonctionne, je vais le marquer comme correct, mais actuellement je reçois une erreur: FEHLER: Unteranfrage dans FROM muss Aliasnamen erhalten ZEILE 2: DE (SELECT maintenant :: date - d AS jour FROM générer_series (0, ... –

+0

Dou vous savoir comment je peux corriger cela merci! –

+0

Je l'ai corrigé en utilisant «date actuelle» et en donnant un alias pour la table! Merci –

0

Vous devez indiquer à SQL de gérer NULL. Retour 0 si NULL

Vous pouvez le faire en COALESCE

http://www.postgresql.org/docs/devel/static/functions-conditional.html

+0

Merci! Mais je ne comprends pas. Complètement pourriez-vous ajouter une requête s'il vous plaît, spécifique à ma question? –

+0

Une date qui n'est pas présente ne s'affichera pas avec COALESCE. Cela ne fonctionne tout simplement pas. –

2

Essayez cette requête:

with a as (select current_date - n as dt from generate_series(0, 6) as t(n)), 
    b as (select count(id) cnt, date(created_at) created_at 
      from entries 
      where date(created_at) >= date(current_date - interval '1 week') 
      group by date(created_at)) 
select coalesce(b.cnt,0), a.dt 
from a 
left join b on (a.dt = b.created_at) 
order by a.dt; 

fonction count ne génère 0 pour les lignes non-existantes. Vous devez donc remplir les lignes pour les dates manquantes. Avec generate_series et arithmétique de date simple, vous pouvez générer des lignes pour les dates d'une certaine période (dans ce cas, 1 semaine). Ensuite, vous pouvez vous joindre à l'extérieur pour générer le résultat final. coalesce remplacera null à 0.

+0

Fonctionne! Mais n'y a-t-il rien de plus court? –

+0

Vous pouvez supprimer COALESCE(), COUNT (colonne) ne compte pas les valeurs NULL. COUNT (*) compte les enregistrements et ne vérifie pas la valeur NULL. –

-1

Utilisez generate_series() pour créer les dates dont vous avez besoin et nous rejoindre à cette liste de dates:

SELECT COUNT(id), 
    date(gdate) 
FROM entries 
    RIGHT JOIN generate_series(current_date - interval '1 week', current_date, '1 day') g(gdate) 
    ON date(created_at) = date(gdate) AND date(created_at) >= date(current_date - interval '1 week') 
GROUP BY 
    date(gdate) 
ORDER BY 
    date(gdate) DESC; 
+0

Désolé, mais ne semble pas fonctionner! –

+0

@JohnSmith: Quel genre d'erreurs/problèmes obtenez-vous? Ça doit être quelque chose comme ça, mais je ne l'ai pas testé. –

+0

Je reçois le même résultat qu'avant! –