2010-11-05 4 views
1

je tente de recueillir des statistiques simples sur une table, disons la structure simplifiée est la suivante:requête SQL (postgresql) pour l'extraction de l'année et la somme

ID |  CREATIONDATE  | VALUE | 
------------------------------------------------ 
    1 | 2007-01-06 13:54:00.000 |  7  | 
    2 | 2007-03-07 15:03:00.000 |  8  | 
    3 | 2008-07-02 18:55:00.000 |  12  | 
    4 | 2008-09-10 19:12:00.000 |  1  | 
    5 | 2010-01-06 13:54:00.000 |  4  | 
    6 | 2010-01-07 07:13:00.000 |  5  | 

J'aimerais résumer les valeurs basées sur l'année de la date de création, donc actuellement j'exécuter ce qui suit:

select extract('year' from i.creationdate) as d1, 
     sum(i.value) 
    from items i 
    group d1 
    order by d1; 

qui sortira

2007;15 
2008;13 
2010;9 

Est-il possible d'améliorer la requête pour qu'elle produise automatiquement 0 pour l'année 2009 manquante, même s'il n'y a pas de ligne dans le tableau avec une date en 2009?

2007;15 
2008;13 
2009;0 
2010;9 

Répondre

0

Une manière simple (mais pas sympa) est de créer une table (temporaire) en tenant toutes les années dans une colonne. Ensuite, vous venez de rejoindre la table de données à votre nouvelle table.

1

Je voudrais faire cela dans le logiciel qui fait la requête, par opposition à dans la requête elle-même. J'ai fait de telles choses (par exemple dans Oracle) en utilisant des boucles for SQL (sans doute il y a des choses similaires dans Postgres) mais je suis arrivé à la conclusion que c'était la mauvaise approche. La solution était plus difficile à maintenir que si j'avais simplement écrit le code dans le langage de programmation de l'application.

SQL renvoie des données qui existent et fonctionne sur des données existantes. Dans ce cas, il n'existe aucune donnée pour l'année en question. C'est pourquoi ce n'est pas une bonne solution d'essayer SQL. Il suffit de demander SQL pour les données que vous avez, et lorsque vous générez votre sortie dans votre langage de programmation pour l'utilisateur (par exemple table HTML), ajoutez la boucle for pour itérer entre la première et la dernière année et zéro si aucun résultat .

3

Utilisez une jointure externe gauche d'une série de générer

select year_list.year, 
     coalesce(item_list.val,0) 
from (select generate_series(2007,2010) as year) AS year_list 
     left outer join 
     (select date_part('year',creationdate) item_year,sum(value) as val from i group by item_year) AS item_list 
     on item_year = year_list.year;  

pour éviter coder en dur les années dans les generate_series substituer de la part de l'année une sélection min() et max().

3

Utilisez generate_series dans un JOIN:

SELECT 
    generate_series as d1, 
    COALESCE(sum(i.value) , 0) 
FROM 
    generate_series(2005, 2010) 
     LEFT JOIN items i ON generate_series = extract('year' from i.creationdate) 
GROUP BY 
    d1 
ORDER BY 
    d1; 
Questions connexes