группировать данные по любому диапазону 30 дней (не по диапазону дат) в SQL Server - PullRequest
2 голосов
/ 10 апреля 2011

Я получил таблицу со списком транзакций.например, предположим, что у него есть 4 поля: ID, UserID, DateAddedd, Amount

Я хотел бы выполнить запрос, который проверяет, было ли время, что через 30 дней пользователь совершал транзакции всумма 100 или более

Я видел много образцов группировки по месяцам или дням, но проблема в том, что если, например, пользователь совершил транзакцию 50 $ 20/4 и 5/5, онсовершил еще 50 $ транзакцию, запрос должен показать это.(его 100 $ или более в течение 30 дней)

Ответы [ 2 ]

2 голосов
/ 10 апреля 2011

Я думаю, что это должно работать (я предполагаю, что транзакции имеют компонент даты, и что пользователь может иметь несколько транзакций в один день):

;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). Существует множество способов создания постоянной или (как в данном случае) временной таблицы чисел. Я выбрал один, а затем в DayRange отфильтровал его до нужных мне чисел.

Теперь, когда у нас есть те, которые нам доступны, мы пишем основной запрос. Мы запрашиваем строки из таблицы DailyTransactions, но мы хотим найти более поздние строки в той же таблице, которые находятся в пределах 30 дней. Именно этим и занимается левое присоединение к DailyTransactions. Он находит те более поздние строки, которых может быть 0, 1 или больше. Если их больше одного, мы хотим сложить все эти значения вместе, поэтому на этом этапе нам нужно еще немного сгруппировать. Наконец, мы можем написать наш пункт «Имея», чтобы отфильтровать только те результаты, в которых сумма за определенный день (dt.Amount) + сумма сумм за более поздние дни (SUM(ot.Amount)) соответствует установленным вами критериям. *

Я основал это на таблице, определенной таким образом:

create table Transactions (
    UserID int not null,
    DateAdded datetime not null,
    Amount decimal (38,2)
)
1 голос
/ 10 апреля 2011

Если я вас правильно понял, вам нужна таблица календаря, а затем проверьте сумму между датой и датой + 30. Поэтому, если вы хотите проверить период в 1 год, вам нужно проверить что-то вроде 365 периодов.

Вот один из способов сделать это. Рекурсивный CTE создает календарь, а перекрестное применение вычисляет сумму для каждого CalDate между CalDate и CalDate + 30.

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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...