按 SQL 分组时处理未观察到的类别
Handle unobserved categories when group by SQL
我对按类别分组时处理未观察到的类别有疑问。
例如,
Month Number
Jan. 1
Jan. 4
Mar. 5
Apr. 3
July. 1
Sept. 4
Nov. 7
Nov. 8
Dec. 9
Dec. 1
Dec. 2
如果我使用这个查询
select t.Month, sum(t.Number) as sum from table t group by t.Month;
它会 return 一个 table 这样的
Month sum
Jan. 5
Mar. 5
Apr. 3
July. 1
Sept. 4
Nov. 15
Dec. 12
但我想得到的其实是这个
Month sum
Jan. 5
Feb. 0
Mar. 5
Apr. 3
May. 0
June. 0
July. 1
Aug. 0
Sept. 4
Oct. 0
Nov. 15
Dec. 12
它还将包括那些未观察到的月份和 return 值为 0。
我该怎么做?
谢谢。
使用 left outer join
,其中左侧是所有月份的 table,右侧是与每个月关联的值的 table。这是一个例子:
创建一个 table 月份(1 代表一月 - 如果这样更容易,您也可以坚持使用月份名称):
create table month (month int);
insert into month values
(1), (2), (3), (4), (5), (6), (7), (8), (9), (10), (11), (12);
与每个月关联的 table 个可求和值:
create table month_val (month int, val int);
insert into month_val values
(1, 10), (1, 11), (2, 20), (2, 21), (3, 30);
左加入 tables:
select month.month, coalesce(sum(month_val.val), 0)
from month
left join month_val on (month.month = month_val.month)
group by month.month
结果:
month coalesce(sum(month_val.val), 0)
1 21
2 41
3 30
4 0
5 0
6 0
7 0
8 0
9 0
10 0
11 0
12 0
您当然可以使用月份名称代替月份编号,或者使用特定于您的数据库的函数将月份编号转换为名称。
您需要LEFT JOIN
一个日历,按日历的月份分组。
select cd.months, coalesce(sum(t.Number),0) as 'sum'
from (
SELECT 'Jan.' as 'months' UNION ALL
SELECT 'Feb.' UNION ALL
SELECT 'Mar.' UNION ALL
SELECT 'Apr.' UNION ALL
SELECT 'May.' UNION ALL
SELECT 'June.' UNION ALL
SELECT 'July.' UNION ALL
SELECT 'Aug.' UNION ALL
SELECT 'Sept.' UNION ALL
SELECT 'Oct.' UNION ALL
SELECT 'Nov.' UNION ALL
SELECT 'Dec.'
) cd LEFT JOIN T on cd.months = t.Month
group by cd.months;
sqlfiddle:https://dbfiddle.uk/?rdbms=sqlserver_2017&fiddle=1aca12dbcc087ce85145e3a8919a6182
我对按类别分组时处理未观察到的类别有疑问。 例如,
Month Number
Jan. 1
Jan. 4
Mar. 5
Apr. 3
July. 1
Sept. 4
Nov. 7
Nov. 8
Dec. 9
Dec. 1
Dec. 2
如果我使用这个查询
select t.Month, sum(t.Number) as sum from table t group by t.Month;
它会 return 一个 table 这样的
Month sum
Jan. 5
Mar. 5
Apr. 3
July. 1
Sept. 4
Nov. 15
Dec. 12
但我想得到的其实是这个
Month sum
Jan. 5
Feb. 0
Mar. 5
Apr. 3
May. 0
June. 0
July. 1
Aug. 0
Sept. 4
Oct. 0
Nov. 15
Dec. 12
它还将包括那些未观察到的月份和 return 值为 0。
我该怎么做?
谢谢。
使用 left outer join
,其中左侧是所有月份的 table,右侧是与每个月关联的值的 table。这是一个例子:
创建一个 table 月份(1 代表一月 - 如果这样更容易,您也可以坚持使用月份名称):
create table month (month int);
insert into month values
(1), (2), (3), (4), (5), (6), (7), (8), (9), (10), (11), (12);
与每个月关联的 table 个可求和值:
create table month_val (month int, val int);
insert into month_val values
(1, 10), (1, 11), (2, 20), (2, 21), (3, 30);
左加入 tables:
select month.month, coalesce(sum(month_val.val), 0)
from month
left join month_val on (month.month = month_val.month)
group by month.month
结果:
month coalesce(sum(month_val.val), 0)
1 21
2 41
3 30
4 0
5 0
6 0
7 0
8 0
9 0
10 0
11 0
12 0
您当然可以使用月份名称代替月份编号,或者使用特定于您的数据库的函数将月份编号转换为名称。
您需要LEFT JOIN
一个日历,按日历的月份分组。
select cd.months, coalesce(sum(t.Number),0) as 'sum'
from (
SELECT 'Jan.' as 'months' UNION ALL
SELECT 'Feb.' UNION ALL
SELECT 'Mar.' UNION ALL
SELECT 'Apr.' UNION ALL
SELECT 'May.' UNION ALL
SELECT 'June.' UNION ALL
SELECT 'July.' UNION ALL
SELECT 'Aug.' UNION ALL
SELECT 'Sept.' UNION ALL
SELECT 'Oct.' UNION ALL
SELECT 'Nov.' UNION ALL
SELECT 'Dec.'
) cd LEFT JOIN T on cd.months = t.Month
group by cd.months;
sqlfiddle:https://dbfiddle.uk/?rdbms=sqlserver_2017&fiddle=1aca12dbcc087ce85145e3a8919a6182