2011-04-10 68 views
2

我收到了一张包含事务列表的表。 的例子,可以说有4个领域: ID,用户名,DateAddedd,金额SQL Server中的任何30天范围内的数据(不是日期范围内的)

我想在运行30天来检查,如果有一个时间的查询,即,用户进行的交易总数为100或更多

我看到很多月份或一天的分组样本,但问题是如果例如 用户在20/4和5/5上做了50美元的交易另一个50美元的交易,查询应该显示它。 (在30天内100美元以上)

回答

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 

好的,我m使用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) 
) 
+0

这可能是。尽管我现在看到了这个查询,但我并不真正了解它。你能解释一下你做了什么吗? – Shay 2011-04-10 07:46:51

+0

@Shay - 我已添加一些评论 – 2011-04-10 07:56:14

+0

谢谢达米安,辉煌! – Shay 2011-04-10 09:31:26

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) 
+0

嘿的Mikael,感谢您的评论。我的问题是我没有FromDate和ToDate变量。我需要一直从数据库中获取用户在任何日期范围内超过100美元的交易,只要这些日期的范围为30天 – Shay 2011-04-10 07:43:32

+0

@Shay - FromDate和ToDate只是在那里定义间隔你想检查你是否想检查整个表,你可以从表中获取FromDate和ToDate。我会用那个更新答案。 – 2011-04-10 08:08:04