Sql 将项目相加,但分别计数,分组和子分组?
我希望每个月将top+base项目对的美元金额相加,同时仅将该项目对作为一个单位计算。看起来很容易吧 唯一重要的是,一个基数可以与多个TOP和多个零件号配对,这些收入需要根据这些不同的TOP零件号进行分组 1000吨底座可搭配tops 052和952。 9000T底座可搭配tops 087和787 销售订单表:Sql 将项目相加,但分别计数,分组和子分组?,sql,sql-server,accounting,Sql,Sql Server,Accounting,我希望每个月将top+base项目对的美元金额相加,同时仅将该项目对作为一个单位计算。看起来很容易吧 唯一重要的是,一个基数可以与多个TOP和多个零件号配对,这些收入需要根据这些不同的TOP零件号进行分组 1000吨底座可搭配tops 052和952。 9000T底座可搭配tops 087和787 销售订单表: order_num | part_num | month | quantity | revenue 01 052 January
order_num | part_num | month | quantity | revenue
01 052 January 1 4000
01 1000T January 1 2000
02 052 January 1 4000
02 1000T January 1 2000
03 087 January 1 5000
03 9000T January 1 2500
04 087 January 1 5000
04 9000T January 1 2500
05 787 February 1 5500
05 9000T February 1 2500
06 952 January 1 3000
06 1000T January 1 2000
我需要:
part_num | month | quantity | revenue
052 January 2 12000
952 January 1 5000
087 January 2 15000
787 January 0 0
787 February 1 8000
如果我按part_num分组,那么我的基础将从顶部分开。我不能在销售订单上求和,因为有些销售订单由不同的产品组成,尽管我的示例中没有。当销售订单号匹配时,我需要对每次出现的top+base组合求和,对吗?我可以在excel中做一些类似于SUMPRODUCT的操作,得到一个组合数组,然后对每个组合求和吗?感谢您的帮助。示例数据
最后,我将月份改为整数,便于按时间顺序排序
declare @SalesOrder table
(
num nvarchar(2),
prt nvarchar(5),
mth int,
qty int,
rev int
);
insert into @SalesOrder (num, prt, mth, qty, rev) values
('01', '052', 1, 1, 4000),
('01', '1000T', 1, 1, 2000),
('02', '052', 1, 1, 4000),
('02', '1000T', 1, 1, 2000),
('03', '087', 1, 1, 5000),
('03', '9000T', 1, 1, 2500),
('04', '087', 1, 1, 5000),
('04', '9000T', 1, 1, 2500),
('05', '787', 2, 1, 5500),
('05', '9000T', 2, 1, 2500),
('06', '952', 1, 1, 3000),
('06', '1000T', 1, 1, 2000);
解决方案
因为您还希望月份的销售额为零,所以顶部部分和月份分别从两个常用表表达式cte_topPrt和cte_mth中的数据中提取,并以交叉联接的方式组合以获得所有组合
with cte_topPrt as -- collect all top parts
(
select distinct so.prt
from @SalesOrder so
where right(so.prt, 1) <> 'T'
),
cte_mth as -- collect all months (because you also want to see months with 0 sales)
(
select distinct so.mth
from @SalesOrder so
)
select tp.prt as [part_num],
m.mth as [month],
coalesce(sum(case when so_tp.prt = so_c.prt then so_tp.qty else 0 end), 0) as [quantity],
coalesce(sum(so_c.rev), 0) as [revenue]
from cte_topPrt tp
cross join cte_mth m
left join @SalesOrder so_tp -- sales order top part
on so_tp.prt = tp.prt
and so_tp.mth = m.mth
left join @SalesOrder so_c -- sales order complete
on so_c.num = so_tp.num
group by tp.prt, m.mth
order by m.mth, tp.prt;
这一个从匹配顶部和底部获得数量和收入。如果订单上还有其他内容,这一点很重要
;
with SalesOrder as (
select order_num
,part_num
,[month]
,quantity
,revenue
from (
values ('01', '052', 'January', 1, 4000)
, ('01', '1000T', 'January', 1, 2000)
, ('01', '44', 'January', 1, 20000)
, ('02', '052', 'January', 1, 4000)
, ('02', '1000T', 'January', 1, 2000)
, ('03', '087', 'January', 1, 5000)
, ('03', '9000T', 'January', 1, 2500)
, ('04', '087', 'January', 1, 5000)
, ('04', '9000T', 'January', 1, 2500)
, ('05', '787', 'February', 1, 5500)
, ('05', '9000T', 'February', 1, 2500)
, ('06', '952', 'January', 1, 3000)
, ('06', '1000T', 'January', 1, 2000)
) as so(
order_num,
part_num,
[month],
quantity,
revenue
)
),
tops as (
select part_num
, base_part_num
from (
values ('052', '1000T')
, ('952', '1000T')
, ('087', '9000T')
, ('787', '9000T')
) as t(
part_num,
base_part_num
)
),
months as (
select 1 as MonthNumber
, datename(month, '2000' + FORMAT(1,'00') + '01') as MonthName
union all
select m.MonthNumber + 1
, datename(month, '2000' + FORMAT(m.MonthNumber + 1,'00') + '01')
from months m
where m.MonthNumber < 12
)
select x.part_num
, x.MonthName
, coalesce(o.quantity, 0) as quantity
, coalesce(o.revenue, 0) as revenue
from (
select so.part_num
, so.month
, sum(so.quantity) as quantity
, sum(so.revenue + baseorder.revenue) as revenue
from SalesOrder so
inner join tops t on t.part_num = so.part_num
inner join SalesOrder baseorder on baseorder.part_num = t.base_part_num
and baseorder.order_num = so.order_num
group by so.part_num
, so.month
) o
full outer join (
select m.MonthName
, m.MonthNumber
, t.part_num
from months m
, tops t
) x on x.part_num = o.part_num
and x.MonthName = o.month
order by x.MonthNumber
, x.part_num
顶部和底部与您提供的数据有什么关系?零件号087、787、052和952是顶部。零件号1000T和2000T为基数。我想我还不清楚。这是两类成对的项。您的示例数据可能缺乏必要的复杂性。如果客户订购787顶部和1000吨底座怎么办。。。一次订购两件上衣和一个底座?这是不可能的,我们不允许客户订购没有底座的上衣。如果为顶部订购了替换底座,则会得到不同的名称1000T>1000T-P。
;
with SalesOrder as (
select order_num
,part_num
,[month]
,quantity
,revenue
from (
values ('01', '052', 'January', 1, 4000)
, ('01', '1000T', 'January', 1, 2000)
, ('01', '44', 'January', 1, 20000)
, ('02', '052', 'January', 1, 4000)
, ('02', '1000T', 'January', 1, 2000)
, ('03', '087', 'January', 1, 5000)
, ('03', '9000T', 'January', 1, 2500)
, ('04', '087', 'January', 1, 5000)
, ('04', '9000T', 'January', 1, 2500)
, ('05', '787', 'February', 1, 5500)
, ('05', '9000T', 'February', 1, 2500)
, ('06', '952', 'January', 1, 3000)
, ('06', '1000T', 'January', 1, 2000)
) as so(
order_num,
part_num,
[month],
quantity,
revenue
)
),
tops as (
select part_num
, base_part_num
from (
values ('052', '1000T')
, ('952', '1000T')
, ('087', '9000T')
, ('787', '9000T')
) as t(
part_num,
base_part_num
)
),
months as (
select 1 as MonthNumber
, datename(month, '2000' + FORMAT(1,'00') + '01') as MonthName
union all
select m.MonthNumber + 1
, datename(month, '2000' + FORMAT(m.MonthNumber + 1,'00') + '01')
from months m
where m.MonthNumber < 12
)
select x.part_num
, x.MonthName
, coalesce(o.quantity, 0) as quantity
, coalesce(o.revenue, 0) as revenue
from (
select so.part_num
, so.month
, sum(so.quantity) as quantity
, sum(so.revenue + baseorder.revenue) as revenue
from SalesOrder so
inner join tops t on t.part_num = so.part_num
inner join SalesOrder baseorder on baseorder.part_num = t.base_part_num
and baseorder.order_num = so.order_num
group by so.part_num
, so.month
) o
full outer join (
select m.MonthName
, m.MonthNumber
, t.part_num
from months m
, tops t
) x on x.part_num = o.part_num
and x.MonthName = o.month
order by x.MonthNumber
, x.part_num