虽然这段代码可以工作,但效率不高——大量使用临时表,我宁愿整合这些临时表。任何有兴趣使用示例数据的人都可以使用 create sumtest 表和写入该表的 insert 语句。
CREATE TABLE SumTest(
POSDate datetime NULL,
debit money NULL,
credit money NULL,
RollingBalance money NULL,
expires datetime NULL,
ExpiringDebitBalance_2013 money,
ExpiringDebitBalance_2014 money
);
-- mimic actual sales transactions
insert into sumtest (POSDate,debit,credit,expires) values ('Jan 5 2013 12:00AM','670.00','22.00','Dec 31 2014 12:00AM');
insert into sumtest (POSDate,debit,credit,expires) values ('Jan 6 2013 12:00AM','821.00','0.00','Dec 31 2014 12:00AM');
insert into sumtest (POSDate,debit,credit,expires) values ('Mar 8 2013 12:00AM','62.00','700.00','Dec 31 2014 12:00AM');
insert into sumtest (POSDate,debit,credit,expires) values ('Mar 11 2013 12:00AM','78.00','29.00','Dec 31 2014 12:00AM');
insert into sumtest (POSDate,debit,credit,expires) values ('Mar 11 2013 12:00AM','900.00','87.00','Dec 31 2014 12:00AM');
insert into sumtest (POSDate,debit,credit,expires) values ('Apr 16 2013 12:00AM','0.00','440.00',NULL);
insert into sumtest (POSDate,debit,credit,expires) values ('Aug 18 2013 12:00AM','0.00','50.00',NULL);
insert into sumtest (POSDate,debit,credit,expires) values ('Aug 19 2013 12:00AM','470.00','200.00','Dec 31 2014 12:00AM');
insert into sumtest (POSDate,debit,credit,expires) values ('Dec 31 2012 12:00AM','1000.00','200.00','Dec 31 2013 12:00AM');
insert into sumtest (POSDate,debit,credit,expires) values ('Dec 22 2013 12:00AM','200.00','0.00','Dec 31 2014 12:00AM');
insert into sumtest (POSDate,debit,credit,expires) values ('Dec 20 2013 12:00AM','500.00','0.00','Dec 31 2014 12:00AM');
insert into sumtest (POSDate,debit,credit,expires) values ('Nov 10 2012 12:00AM','200.00','0.00','Dec 31 2013 12:00AM');
insert into sumtest (POSDate,debit,credit,expires) values ('Nov 11 2012 12:00AM','150.00','0.00','Dec 31 2013 12:00AM');
insert into sumtest (POSDate,debit,credit,expires) values ('Nov 15 2012 12:00AM','0.00','100.00',NULL);
-- // ---------- REAL CODE BEGINS -------------------------- // --
create table #work
(
POSYear int NULL,
POSMonth int NULL,
debit money NULL,
credit money NULL,
RollingBalance money NULL,
expires datetime
)
-- start with ditching the time
insert into #work
(POSYear,POSMonth,debit,credit,expires)
select datepart(Year, POSDate) as POSYear
,datepart(Month, POSDate) as POSMonth
,debit
,credit
,expires
from sumtest
-- dump an ordered set by year,month with a rolling balance of all points/redemptions
;with distilled as
(select POSYear,
POSMonth,
TotalDebit = sum(debit),
TotalCredit = sum(credit),
expires
from #work
group by POSYear,POSMonth,expires
)
select POSYear,
POSMonth,
TotalDebit,
TotalCredit,
RollingBalance = sum(totaldebit + (totalcredit)*-1) over ( order by POSYear, POSMonth),
expires
into #work2
from distilled
order by POSYear,POSMonth,TotalDebit,TotalCredit
-- filter out credits lines that dont have an expiration date
-- Note: I would rather not do this--if there is a better way
-- to sum up by yyyy,mm here to consolidate to
-- single rows please advise.
select x.POSYear,
x.POSMonth,
sum(x.TotalDebit) as TotalDebit,
sum(x.TotalCredit) as TotalCredit,
x.RollingBalance,
EXPYear = datepart(Year, y.expires),
EXPMonth = datepart(Month, y.expires)
into #work3
from #work2 x
inner join #work2 y on x.posyear = y.posyear
and x.posmonth = y.posmonth
where y.expires is not null
group by x.posyear,x.posmonth,x.rollingbalance,y.expires
order by posyear,posmonth
-- add back in lines that are single credits, w/o debits
-- Note: I like this even less! :-\
INSERT INTO #work3
(POSYear,POSMonth,TotalDebit,TotalCredit,RollingBalance,EXPYear,EXPMonth)
select
POSYear,
POSMonth,
TotalDebit,
TotalCredit,
RollingBalance,
case
when expires is null then (POSYear + 1)
end as EXPYear,
case
when expires is null then 12
end as EXPMonth
from #work2
where (POSYear + POSMonth) NOT IN (
select POSYear + POSMonth
from #work3);