我得到了一张包含交易清单的表格。 例如,假设它有4个字段: ID,UserID,DateAddedd,金额
我想运行一个查询,检查是否有时间,在30天内,用户进行的交易总数为100或更多
我看到很多按月或一天分组的样本,但问题是,例如 一个用户在20/4上进行了50美元的交易,而在5/5他做了另一个50美元的交易,查询应该显示它。 (30天内100美元或以上)
答案 0 :(得分:2)
我认为这应该有效(我假设交易有一个日期组件,并且用户可以在一天内拥有多个交易):
;with DailyTransactions as (
select UserID,DATEADD(day,DATEDIFF(day,0,DateAdded),0) as DateOnly,SUM(Amount) as Amount
from Transactions group by UserID,DATEADD(day,DATEDIFF(day,0,DateAdded),0)
), Numbers as (
select ROW_NUMBER() OVER (ORDER BY object_id) as n from sys.objects
), DayRange as (
select n from Numbers where n between 1 and 29
)
select
dt.UserID,dt.DateOnly as StartDate,MAX(ot.DateOnly) as EndDate, dt.Amount + COALESCE(SUM(ot.Amount),0) as TotalSpend
from
DailyTransactions dt
cross join
DayRange dr
left join
DailyTransactions ot
on
dt.UserID = ot.UserID and
DATEADD(day,dr.n,dt.DateOnly) = ot.DateOnly
group by dt.UserID,dt.DateOnly,dt.Amount
having dt.Amount + COALESCE(SUM(ot.Amount),0) >= 100.00
好的,我正在使用3个常用表表达式。第一个(DailyTransactions)将每个用户每天的事务表减少到一个事务(如果DateAdded只是一个日期,并且每个用户每天只有一个事务,则不需要这样做)。第二个和第三个(Numbers和DayRange)有点作弊 - 我想让数字1-29可供我使用(用于DATEADD)。创建永久或(如本例中)临时Numbers表有多种方法。我只选了一个,然后在DayRange中,我将其过滤到我需要的数字。
现在我们有了可用的那些,我们编写了主查询。我们正在查询DailyTransactions表中的行,但我们希望在同一个表中查找30天内的后续行。这就是DailyTransactions的左连接正在做的事情。它找到了后来的行,其中可能有0,1或更多。如果它不止一个,我们想要将所有这些值加在一起,这就是为什么我们需要在这个阶段进行更多的分组。最后,我们可以编写我们的having子句,仅过滤那些结果,其中特定日期的金额(dt.Amount
)+晚些时候的金额总和(SUM(ot.Amount)
)符合您设置的条件进行。
我的基础是这样定义的表:
create table Transactions (
UserID int not null,
DateAdded datetime not null,
Amount decimal (38,2)
)
答案 1 :(得分:1)
如果我理解正确,您需要一张日历表,然后检查日期和日期之间的总和+30。因此,如果你想检查一年的时间,你需要检查365个时期。
这是一种方法。递归CTE创建日历,交叉应用计算CalDate和CalDate + 30之间每个CalDate的总和。
declare @T table(ID int, UserID int, DateAdded datetime, Amount money)
insert into @T values(1, 1, getdate(), 50)
insert into @T values(2, 1, getdate()-29, 60)
insert into @T values(4, 2, getdate(), 40)
insert into @T values(5, 2, getdate()-29, 50)
insert into @T values(7, 3, getdate(), 70)
insert into @T values(8, 3, getdate()-30, 80)
insert into @T values(9, 4, getdate()+50, 50)
insert into @T values(10,4, getdate()+51, 50)
declare @FromDate datetime
declare @ToDate datetime
select
@FromDate = min(dateadd(d, datediff(d, 0, DateAdded), 0)),
@ToDate = max(dateadd(d, datediff(d, 0, DateAdded), 0))
from @T
;with cal as
(
select @FromDate as CalDate
union all
select CalDate + 1
from cal
where CalDate < @ToDate
)
select S.UserID
from cal as C
cross apply
(select
T.UserID,
sum(Amount) as Amount
from @T as T
where T.DateAdded between CalDate and CalDate + 30
group by T.UserID) as S
where S.Amount >= 100
group by S.UserID
option (maxrecursion 0)