2010-11-16 17 views
3

Ma tête fume de (stupide) essais d'utiliser JOIN, WITH et GROUP BY pour trouver une solution pour mon scénario assez commun - je ne peux tout simplement pas enrouler ma tête autour d'elle. Permettez-moi de jeter l'exemple à vous tout de suite:SQL joint mensuel et pourcentage total mensuel

J'ai deux tables (ColorCount et colorName):

ColorCount: 
ColorID Count Date 
1  42 2010-09-07 
1  1  2010-09-08 
2  22 2010-09-14 
1  20 2010-10-10 
3  4  2010-10-14 

ColorName: 
ColorID Name 
1  Purple 
2  Green 
3  Yellow 
4  Red 

Maintenant, tout ce que je veux est à se joindre à la table colorName au tableau ColorCount, additionnez tous les comptes de couleurs par mois et calculez le pourcentage de chaque compte à partir du total mensuel. Les tables sont mieux que des mots:

Output: 
Month Color Count Percentage 
09 Purple 43 66% 
09 Green 22 33% 
09 Yellow 0  0% 
09 Red  0  0% 
10 Purple 20 83% 
10 Green 0  0% 
10 Yellow 4  16% 
10 Red  0  0% 

(S'il vous plaît noter le nombre total de mois 09 est 65, d'où le 66% pour Purple et aussi les 0 « s pour les couleurs non existantes):

I espère que quelqu'un rêve dans SQL ce qui est une tâche facile ...

Répondre

3

Cela fonctionne, avec les mises en garde suivantes:

  • Les valeurs datetime doivent être ce jour seulement
  • Il ne répertorie que les mois pour lesquels il existe des données
  • liste I par premier jour du mois , dans le cas où vous avez des données qui dépassent des années (je suppose que vous ne voulez pas agréger les données de Jan 2009 avec les données de Jan 2010)
  • Les détails précis de la mise en forme de la colonne Pourcentage Je vous laisse, je dois revenir travailler

code:

;with cte (ColorId, Mth, TotalCount) 
as (select 
     ColorId 
     ,dateadd(dd, -datepart(dd, Date) + 1, Date) Mth 
     ,sum(Count) TotalCount 
     from ColorCount 
     group by ColorId, dateadd(dd, -datepart(dd, Date) + 1, Date)) 
select 
    AllMonths.Mth [Month] 
    ,cn.Name 
    ,isnull(AggData.TotalCount, 0) [Count] 
    ,isnull(100 * AggData.TotalCount/sum(AggData.TotalCount * 1.00) over (partition by AllMonths.Mth), 0) Percentage 
    from (select distinct Mth from cte) AllMonths 
    cross join ColorName cn 
    left outer join cte AggData 
    on AggData.ColorId = cn.ColorId 
    and AggData.Mth = AllMonths.Mth 
    order by AllMonths.Mth, cn.ColorId 
+0

Utilisation de la partition par. Agréable! –

+0

oui, bien. Doit obtenir un bon livre sur MSSQL 2008 – AlexanderMP

+0

Bonne discussion des techniques de fenêtrage sur SimpleTalk, à http://www.simple-talk.com/sql/learn-sql-server/working-with-window-functions-in-sql- serveur /? utm_source = simpletalk & utm_medium = email-principal & utm_content = WindowsFunction-20101101 & utm_campaign = SQL –

2
SELECT 
    [Month], 
    [Name], 
    [Count], 
    CASE WHEN TotalMonth=0 THEN 'INF' ELSE cast(round([Count],0)*100.0/TotalMonth,0) as int) + '%' END as [Percentage] 
FROM 
(
SELECT 
    [Months].[Month] as [Month], 
    CN.[Name], 
    isnull(CC.[Count],0) as [Count], 
    (SELECT SUM([Count]) FROM ColorCount WHERE 
      datepart(month,[Date])=datepart(month,CC.[Date]) 
    ) as [TotalMonth] 
FROM (SELECT DISTINCT datepart(month,[Date]) as [Month] FROM ColorCount) [Months] 
LEFT JOIN ColorName CN ON [Months].[Month]=datepart(month,CC.[Date]) 
LEFT JOIN ColorCount CC ON CN.ColorID=CC.ColorID 
) AS tbl1 
ORDER BY 
    [Month] ASC, 
    [Name] ASC 

Quelque chose comme ça .... Il n'affichera pas le zéro principal du mois, mais est-ce vraiment important?

+0

Bien essayé, mais les pourcentages sont éteints. –

+0

mieux mais vous devriez convertir en flotteur pour éviter les erreurs d'arrondi. –

+0

il peut également générer une division par zéro exception, mais pour éviter cela, il ya juste beaucoup de taper impliqué. Je vais essayer de régler ça. Et qu'en est-il des pourcentages? Pourquoi? – AlexanderMP