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>
我有一个 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>