SQL 服务器:使用递归 CTE 获取每周存款变化

SQL Server: get weekly deposit changes using recursive CTE

我有一个 table 账户存款。

+-----------+------------+-----------+
| DepositId |    Date    |  Amount   |
+-----------+------------+-----------+
|         1 | 2014-06-12 | 2342,00   |
|         2 | 2014-08-05 | 23423,00  |
|         3 | 2014-09-07 | 7745,00   |
|....................................|
|        12 | 2014-12-05 | 35435,00  |
|        13 | 2014-12-11 | 353453,00 |
|        14 | 2014-12-29 | 53453,00  |
+-----------+------------+-----------+

我想看到这样的每周余额变化:

+------------+----------+
|     Date   |  Amount  |
+------------+----------+
| 2014-10-07 | 74754,00 |
| 2014-10-14 | 74754,00 |
| 2014-10-21 | 6353,00  |
| 2014-10-28 | 6353,00  |
| ........   | ......   |
| 2014-12-30 | 53453,00 |
+------------+----------+

要查看过去 3 个月(~ 13 周)的变化,我可以使用以下查询:


select CONVERT(date, DATEADD(WEEK, -13, GETDATE())) as Date, ad.Amount
from AccountDeposits as ad
inner join
    (select Max(Date) as Date
    from AccountDeposits
    where (Date < DATEADD(WEEK, -13, GETDATE())))
    as ad2 on (ad.Date = ad2.Date)

    union all

select CONVERT(date, DATEADD(WEEK, -12, GETDATE())) as Date, ad.Amount
from AccountDeposits as ad
inner join
    (select Max(Date) as Date
    from AccountDeposits
    where (Date < DATEADD(WEEK, -12, GETDATE())))
    as ad2 on (ad.Date = ad2.Date)

......................................................

select CONVERT(date, DATEADD(WEEK, -1, GETDATE())) as Date, ad.Amount
from AccountDeposits as ad
inner join
    (select Max(Date) as Date
    from AccountDeposits
    where (Date < DATEADD(WEEK, -1, GETDATE())))
    as ad2 on (ad.Date = ad2.Date)

我必须使用递归通用 Table 表达式来执行此操作,但在 CTE 的递归部分我不能使用 MAX() 函数。我应该如何使用 CTE 将此查询系列写入 on query?

使用:

SELECT 前 1 [日期] 来自帐户存款 --添加WHERE子句 按 [日期] 排序

:)大卫

我可能误解了这个问题(如果有的话,我深表歉意)但是如果问题是 "for each week when there were deposits, give the sum of the total deposits for that week and the last day of that week" 那么下面的 T-SQL 会给出正确的结果。

with myCte1 as
(
    select *, datepart(week,d.[Date]) as wk, datepart(year,d.[Date]) as yr, 
        dateadd(dd, 7-(datepart(dw,d.[Date])), d.[Date]) as weekEndDate
    from dbo.AccountDeposits as d
),

myCte2 as
(
    select *, sum(m.Amount) over (partition by m.yr, m.wk) as totalWeeklyAmt
    from myCte1 as m
)

select distinct m.weekEndDate, m.totalWeeklyAmt
from myCte2 as m

不用CTE就解决了... 首先创建table,开始日期和结束日期为13周,从getdate()开始。

Create table weeklydates
(Startdate date,
 Enddate date
)
Declare @startdate date
Declare @enddate date

Set @startdate = cast (dateadd (week,-13,getdate ()) as date)
Set @enddate = dateadd (day,7,@startdate)

While @enddate < = getdate ()
Begin
Insert into weeklydates
Select @startdate, @enddate
Set @startdate = dateadd (day,1,@enddate)
Set @enddate = dateadd (day,7,@startdate)
End

现在使用此 table 显示金额,该金额将是日期介于开始日期和结束日期之间的金额之和

Select a.startdate,a.enddate, (select sum (amount) from yourtablehavingamount as b 
Where b.deposit >=a.startdate and b.deposit <=a.enddate)
From weeklydates as a

这使用了两个 CTE,一个总结了我们的源数据,另一个使用递归 CTE 生成所有周数,这使我们还可以显示没有存款的周数。它还使用两个相互关联的子查询从第一个 CTE 中获取汇总数据。

我认为这可以满足您的任务要求。'


--NOTE: this gets data based on week end date, so all deposits for week of @WeeksHistory ago not just the deposits after the date (today  minus @WeeksHistory weeks).
--NOTE: this gets all historical data so that we can start with opening balance of [=10=] otherwise Closing balance wont take previous deposits into account.
--NOTE: this gets the week starting @WeeksHistory ago and also this week so you will end up with @WeeksHistory +1 records - you might want to adjust this as necessary</p>

<p>-- set up our source data
declare @AccountDeposits table (DepID int, AcctHolderID int, TxnDate date, Amount numeric(10,2)) </p>

<p>insert into @AccountDeposits 
values
    (1, 3,'12-25-2014', 2423.00),
    (2, 1,'12-13-2014',4231.00),
    (3, 2,'11-01-2014',666.00),
    (4, 1,'11-01-2014',4241.34),
    (5, 4,'10-23-2014',4221.00),
    (6, 2,'10-22-2014',9992.00),
    (7, 2,'10-04-2014',3524.00),
    (8, 2,'10-14-2014',3524.00),
    (9, 2,'10-15-2014',3524.00),
    (10, 2,'10-16-2014',3524.00),
    (11, 3,'10-14-2014',3524.00),
    (12, 3,'10-15-2014',3524.00),
    (13, 3,'10-16-2014',3524.00),
    (14, 1,'10-01-2014',3524.00),
    (15, 2,'10-01-2014',3524.00),
    (16, 3,'10-01-2014',3524.00),
    (17, 4,'01-01-2015',3524.00)</p>

<p>declare @AcctHolderID as int = 2
declare @WeeksHistory int = -13</p>

<p>select dateadd(week,@WeeksHistory,getdate()) ThirteenWeeksAgo</p>

<p>;with 
    src (AcctHolderID, WeekEndsOn, Amount)
as (select
        AcctHolderID, 
        DATEADD(DAY, 7-DATEPART(WEEKDAY, TxnDate), TxnDate),
        SUM(Amount)
    from @AccountDeposits
    where AcctHolderID = @AcctHolderID -- we filter up here so that we arent processing data we dont care about.
    group by
        AcctHolderID, 
        DATEADD(DAY, 7-DATEPART(WEEKDAY, TxnDate), TxnDate)
    ),
    r_cte (AcctHolderID, WeekEndsOn, TotalDep, ClosingBal)
as (select
        AcctHolderID,
        dateadd(ww,-1,Min(WeekEndsOn)),
        convert(numeric(10,2),0.00),
        convert(numeric(10,2),0.00)
    from
        src
    group by 
        AcctHolderID
    union all
    select
        r_cte.AcctHolderID,
        dateadd(WW,1,r_cte.WeekEndsOn),
        convert(numeric(10,2),ISNULL((select Amount from src where AcctHolderID = r_cte.AcctHolderID and WeekEndsOn = dateadd(WW,1,r_cte.WeekEndsOn)),0)),
        convert(numeric(10,2),ISNULL((select Amount from src where AcctHolderID = r_cte.AcctHolderID and WeekEndsOn = dateadd(WW,1,r_cte.WeekEndsOn)),0) + r_cte.ClosingBal)
    from 
        r_cte
    where
        AcctHolderID = r_cte.AcctHolderID 
        and r_cte.WeekEndsOn < DATEADD(DAY, 7-DATEPART(WEEKDAY, Getdate()), DATEADD(WW,-1,Getdate()))
    )
select AcctHolderID, DATEDIFF(ww, WeekEndsOn, getdate()) as WeeksAgo, WeekEndsOn, TotalDep, ClosingBal 
from r_cte
where r_cte.WeekEndsOn > dateadd(week,@WeeksHistory,getdate())
order by
    AcctHolderID,
    WeekEndsOn
</pre>