SQL ежемесячное объединение и ежемесячный общий процент
Моя голова курит от (глупых) попыток использования JOIN
, WITH
а также GROUP BY
придумать решение для моего довольно распространенного сценария - я просто не могу обернуться вокруг него. Позвольте мне сразу бросить вам пример:
У меня есть две таблицы (ColorCount и 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
Теперь все, что мне нужно, - это присоединить таблицу ColorName к таблице ColorCount, суммировать все количества цветов за месяц и рассчитать процент каждого счета от месячной суммы. Таблицы лучше слов:
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%
(Обратите внимание на общее количество месяцев 09
является 65
, следовательно 66%
за Purple
а также 0
для несуществующих цветов):
Я надеюсь, что кто-то мечтает о SQL, и это простая задача...
2 ответа
Это работает со следующими оговорками:
- Значения datetime должны быть только date
- В нем перечислены только те месяцы, для которых есть какие-либо данные
- Я перечисляю по первому дню месяца, если у вас есть данные, которые пересекают годы (я предполагаю, что вы не хотите объединять данные за январь 2009 г. с данными за январь 2010 г.)
- Точные детали форматирования столбца Процент, которые я оставляю на ваше усмотрение, я должен вернуться к работе
Код:
;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
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
Нечто подобное... Это не будет отображать ведущий ноль месяца, но действительно ли это имеет значение?