虽然这段代码工作正常但效率不高 - 大量使用临时表,我宁愿合并。对于有兴趣使用示例数据的任何人,都包含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);
答案 0 :(得分:1)
似乎不需要#work
可以替换为
;with distilled as
(
select POSYear,
POSMonth,
TotalDebit = sum(debit),
TotalCredit = sum(credit),
expires
from (
select datepart(Year, POSDate) as POSYear
,datepart(Month, POSDate) as POSMonth
,debit
,credit
,expires
from sumtest
)
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
我认为最后两个查询可以简化为
select x.POSYear,
x.POSMonth,
sum(case when expires is null then 0 else x.TotalDebit end) as TotalDebit,
sum(case when expires is null then 0 else x.TotalCredit end) as TotalCredit,
x.RollingBalance,
EXPYear = case when expires is null then (POSYear + 1)
else datepart(Year, y.expires)
end,
EXPMonth = case when expires is null then 12
else datepart(Month, y.expires)
end
into #work3
from #work2 x
inner join #work2 y on x.posyear = y.posyear
and x.posmonth = y.posmonth
group by x.posyear,x.posmonth,x.rollingbalance,y.expires
您似乎也不需要order
任何事情
答案 1 :(得分:0)
好的,这是精炼版 - 没有临时表。
SELECT
POSYear
, POSMonth
, TotalDebit AS TotalEarned
, TotalCredit AS TotalRedeemed
, RollingBalance
, EXPYear
, EXPMonth
, case
when EXPYear = 2013 then RollingBalance
else 0
end as EXPRollingBal_2013
, case
when prevEXPYear <> EXPYear then lag(RollingBalance,1) over (ORDER BY POSYear ,POSMonth) - TotalCredit
end as "EXPCarryForwardBal" -- // Note: This only works for the first instance AFTER then new year. Wrong!
, case
-- when EXPYear = 2014 then RollingBalance // Note: This is WRONG, zero it out for now.
when EXPYear = 2014 then 0.00
else 0
end as EXPRollingBal_2014
INTO #baseExpiring
FROM (
SELECT
POSYear
, POSMonth
, TotalDebit
, TotalCredit
, sum(TotalDebit - TotalCredit) over (ORDER BY POSYear ,POSMonth) AS RollingBalance
, EXPYear
, EXPMonth
, lag(EXPYear,1) over (ORDER BY POSYear ,POSMonth) as prevEXPYear
FROM (
SELECT
year(posdate) AS POSYear
, month(posdate) AS POSMonth
, sum(debit) AS TotalDebit
, sum(credit) AS TotalCredit
, CASE
WHEN expires IS NULL THEN year(posdate) + 1
ELSE year(expires)
END AS EXPYear
, CASE
WHEN expires IS NULL THEN 12
ELSE month(expires)
END AS EXPMonth
FROM SumTest
GROUP BY
year(posdate)
, month(posdate)
, CASE
WHEN expires IS NULL THEN year(posdate) + 1
ELSE year(expires)
END
, CASE WHEN expires IS NULL THEN 12
ELSE month(expires)
END
) as dataset1 -- // resolve line consolidation when there's a standalone redempton when summed, leaving 2 distinct yyyy,mm rows.
) as dataset2 -- // broader resolution of rolling balance w/windowing.
;