sql pivot汇总表并比较行

时间:2013-05-12 20:44:04

标签: sql linq tsql pivot

我有这三张桌子 账户和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

的查询

1 个答案:

答案 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