我有这三张桌子 账户和bounse之间存在多对多的关系,我想比较每个账户与前一个月的比率,减去当月与前一个月的比较
tbl_account
account_id account_name
----------- ---------------------
1 Account1
2 Account2
tbl_bounse
bounse_id bounse_name
----------- -------------
42 bounseA
43 bounseB
44 BounseC
tbl_detail(tbl_account和tbl_bounse之间的链接表)
detail_accound_id detail_bounce_id detail_value detail_id detail_date
----------------- ---------------- -------------------- ----------- -----------
1 42 24000 158981 2013-05-05
1 42 25000 159113 2013-06-06
1 43 150 158982 2013-05-05
1 43 150 159114 2013-06-06
1 44 23000 158983 2013-05-05
1 44 25150 159115 2013-06-06
2 42 20000 159025 2013-05-05
2 42 23000 159157 2013-06-06
2 43 400 159026 2013-05-05
2 43 350 159158 2013-06-06
2 44 10000 159021 2013-05-05
2 44 11000 159159 2013-06-06
我希望将结果总结为
accound_id detail_date BounseA BounseB BounseC
----------- ----------- ------- ------- -------
1 2013-05-05 24000 150 23000
1 2013-06-06 25000 150 25500
1 differ date 1000 0 2500
2 2013-05-05 20000 400 10000
2 2013-06-06 23000 350 11000
2 differ date 3000 -50 1000
将Temp Table返回为
accound_id detail_date BounseA BounseB BounseC
----------- ----------- ------- ------- -------
1 differ date 1000 0 2500
2 differ date 3000 -50 1000
我试图使用pivot和动态sql,但我不知道如何减去行并将减去的结果插入临时表
SQL server 2008 r2,使用T-SQL或LINQ
的查询答案 0 :(得分:1)
我会使用CTE来执行枢轴,然后使用窗口函数动态获取最新日期或添加变量以可能进行上个月的比较。示例是使用表变量自解压缩,因此如果您具有SQL Management Studio 2008或更高版本,它将按原样运行:
declare @account table ( id int identity, name varchar(16) );
declare @bonus table ( id int identity(42,1), bonusname varchar(16) );
declare @detail table ( accountId int, bonusid int, detailvalue int, detailid int, detaildate date);
insert into @account values ( 'Account1'),('Account2');
insert into @bonus values ('bonusA'),('bonusB'),('BonusC');
insert into @detail values ( 1, 42, 24000, 158981, '2013-05-05')
,(1, 42, 25000, 159113 ,'2013-06-06')
,(1, 43, 150, 158982 ,'2013-05-05')
,(1, 43, 150, 159114 ,'2013-06-06')
,(1, 44, 23000, 158983 ,'2013-05-05')
,(1, 44, 25150, 159115 ,'2013-06-06')
,(2, 42, 20000, 159025 ,'2013-05-05')
,(2, 42, 23000, 159157 ,'2013-06-06')
,(2, 43, 400, 159026 ,'2013-05-05')
,(2, 43, 350, 159158 ,'2013-06-06')
,(2, 44, 10000, 159021 ,'2013-05-05')
,(2, 44, 11000, 159159 ,'2013-06-06')
;
-- Method 1 determines the current month and year by finding greatest date in your table, there is an issue with this method if you want to see other months.
with cte as
(
select
a.id
, d.detaildate
-- perform pivots based on id
, max(case when b.bonusname = 'BonusA' then detailvalue end) as BonusA
, max(case when b.bonusname = 'BonusB' then detailvalue end) as BonusB
, max(case when b.bonusname = 'BonusC' then detailvalue end) as BonusC
-- find the maximum date with a windowed function changing scope to group by (partition by) the identifier of the account
, max( d.detaildate) over(partition by a.id) as MaxDate
from @account a
join @detail d on a.id = d.accountId
join @bonus b on d.bonusid = b.id
group by
a.id
, d.detaildate
)
select
id
, max(case when Year(MaxDate) = Year(detaildate) and Month(MaxDate) = Month(detailDate) then BonusA end) -
max(case when Year(MaxDate) = Year(detaildate) and Month(MaxDate) - 1 = Month(detailDate) then BonusA end) as BonusADif
, max(case when Year(MaxDate) = Year(detaildate) and Month(MaxDate) = Month(detailDate) then BonusB end) -
max(case when Year(MaxDate) = Year(detaildate) and Month(MaxDate) - 1 = Month(detailDate) then BonusB end) as BonusBDif
, max(case when Year(MaxDate) = Year(detaildate) and Month(MaxDate) = Month(detailDate) then BonusC end) -
max(case when Year(MaxDate) = Year(detaildate) and Month(MaxDate) - 1 = Month(detailDate) then BonusC end) as BonusCDif
from cte
group by id
;
-- Method 2 determines the current month and year by YOU listing a variable, this offers more flexibility in the future.
-- You could create a function or proc off of this for even more functionality
declare @MaxDate date = '6-1-2013';
with cte as
(
select
a.id
, d.detaildate
-- perform pivots based on id
, max(case when b.bonusname = 'BonusA' then detailvalue end) as BonusA
, max(case when b.bonusname = 'BonusB' then detailvalue end) as BonusB
, max(case when b.bonusname = 'BonusC' then detailvalue end) as BonusC
-- find the maximum date with a windowed function changing scope to group by (partition by) the identifier of the account
from @account a
join @detail d on a.id = d.accountId
join @bonus b on d.bonusid = b.id
group by
a.id
, d.detaildate
)
select
id
, max(case when Year(@MaxDate) = Year(detaildate) and Month(@MaxDate) = Month(detailDate) then BonusA end) -
max(case when Year(@MaxDate) = Year(detaildate) and Month(@MaxDate) - 1 = Month(detailDate) then BonusA end) as BonusADif
, max(case when Year(@MaxDate) = Year(detaildate) and Month(@MaxDate) = Month(detailDate) then BonusB end) -
max(case when Year(@MaxDate) = Year(detaildate) and Month(@MaxDate) - 1 = Month(detailDate) then BonusB end) as BonusBDif
, max(case when Year(@MaxDate) = Year(detaildate) and Month(@MaxDate) = Month(detailDate) then BonusC end) -
max(case when Year(@MaxDate) = Year(detaildate) and Month(@MaxDate) - 1 = Month(detailDate) then BonusC end) as BonusCDif
from cte
group by id