2011-04-10 48 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