2016-11-09 9 views
3

SQL Server 2012를 사용하여 판매 대리점의 롤링 판매 정보를 추출합니다. 이 에이전트는 롤링 기간이 6 일 이내 인 15 건의 매출을 달성하면 보너스로 지급됩니다. 타겟을 만들면 롤링 횟수가 재설정됩니다. 일요일은 무시해야합니다.리셋으로 누적 합계를 사용하는 판매 목표

SELECT 1 AgentID,'2016-10-31' Date,1 Sales 
INTO #Sales 
UNION SELECT 1,'2016-11-01',2 
UNION SELECT 1,'2016-11-02',1 
UNION SELECT 1,'2016-11-03',5 
UNION SELECT 1,'2016-11-04',3 
UNION SELECT 1,'2016-11-05',2 
UNION SELECT 1,'2016-11-07',6 
UNION SELECT 1,'2016-11-08',5 
UNION SELECT 1,'2016-11-09',4 
UNION SELECT 1,'2016-11-10',6 
UNION SELECT 1,'2016-11-11',1 
UNION SELECT 1,'2016-11-12',3 
UNION SELECT 1,'2016-11-14',2 
UNION SELECT 1,'2016-11-15',2 
UNION SELECT 1,'2016-11-16',4 
UNION SELECT 1,'2016-11-17',2 
UNION SELECT 1,'2016-11-18',2 

내가 대상이 타격을받을 것으로 예상 날짜는 다음과 같습니다 : 나는 몇 가지 방법 그러나 나는 시도했다

2016-11-07 (period 2016-11-01 -> 2016-11-07) 
2016-11-10 (period 2016-11-08 -> 2016-11-10) 
2016-11-18 (period 2016-11-12 -> 2016-11-18) 

AgentID Date Sales Qualify 
------------------------------- 
1 2016-10-31 1 0 
1 2016-11-01 2 0 
1 2016-11-02 1 0 
1 2016-11-03 5 0 
1 2016-11-04 3 0 
1 2016-11-05 2 0 
1 2016-11-07 6 1 
1 2016-11-08 5 0 
1 2016-11-09 4 0 
1 2016-11-10 6 1 
1 2016-11-11 1 0 
1 2016-11-12 3 0 
1 2016-11-14 2 0 
1 2016-11-15 2 0 
1 2016-11-16 4 0 
1 2016-11-17 2 0 
1 2016-11-18 2 1 

다음 AgentID, 날짜 및 판매 데이터를 제공

그래서 총계를 재설정하는 방법을 찾을 수 없습니다.

나는 창 함수가 갈 길이라고 생각한다.

Window Functions - Running Total with reset

같은 게시물을 보면 나는 이것이 내가 필요 비슷하지만 아주 제대로 동작하지 않습니다 수 있다고 생각합니다.

업데이트 : 내가 시도한 첫 번째 일은 6 일짜리 롤링 윈도우를 만드는 것이지만 세트 기반 방식으로는 작동하지 않습니다. 커서를 사용하여이 행을 단계별로 실행할 수는 있지만 실제로 아이디어가 마음에 들지 않습니다.

SELECT DATEADD(DAY,-6,a.Date) StartDate,Date EndDate,a.AgentID,a.Sales, 
(SELECT SUM(b.Sales) 
    FROM cteSales b 
    WHERE b.Date <= a.Date 
    AND b.Date >= DATEADD(DAY,-6,a.Date)) TotalSales 
FROM cteSales a 

나는 다음 위의 URL에서 언급 된 스크립트를 사용하려하지만 난 정말 무엇을하고 있는지 이해하지 않습니다. 저는 솔루션을 가로막을 수있게 바라고 있습니다. 단지 작동하지 않습니다.

WITH c1 as 
(
    select *, 
    sum(sales) over(order by IDDate rows unbounded preceding) as rt 
    from cteSales 
) 

SELECT date, sales, rt, 
    SalesTarget_rt - lag(SalesTarget_rt, 1, 0) over(order by date) as SalesTarget, 
    rt * SalesTarget_rt as new_rt 

from c1 
    cross apply(values(case when rt >= 15 then 1 else 0 end)) as a1(SalesTarget_rt); 
+0

당신은 당신이 지금까지 시도 스크립트가 있습니까? – iamdave

+1

또한 같은 날의 15 일 이후의 판매가 다음 목표를 향해 계산됩니까? 그래서 그들이 1 일에 14 개를 판매하고 2 일에 3을 판매한다면 다음 목표를 향한 계산은 3 일에 2 또는 0으로 시작합니까? – iamdave

+0

아 그리고 또한 (!) 각 요원에 대해 하루에 최대 한 개의 레코드 만있을 것입니까? – iamdave

답변

1

바로 그때! 이것은 재미있는 도전이었다. 그리고 나는 그것이 내가 그것을 부 that다라고 매우 기쁜 것이다. Notes 등은 코드 주석에 있습니다. 보너스가 발생할 수있는 일 수를 변경하려면 @DaysInBonusPeriod의 값을 변경하십시오. 이것은 또한 누락 된 날짜가 보너스 적립 기간에 포함되지 않은 가정, 여러 AgentID들과 날짜의 순서 작동 - 예 : 당신이 일요일 무시하고 수요일 기간에 따라서 계산하는 경우 :

Day  Period Day 
Monday 1 
Tuesday 2 
Thursday 3 
Friday 4 
Saturday 5 
Monday 6 

솔루션

declare @t table(AgentID int 
       ,DateValue Date 
       ,Sales int 
       ); 
insert into @t     
select 1,'2016-10-31',1 union all 
select 1,'2016-11-01',2 union all 
select 1,'2016-11-02',1 union all 
select 1,'2016-11-03',5 union all 
select 1,'2016-11-04',3 union all 
select 1,'2016-11-05',2 union all 
select 1,'2016-11-07',6 union all 
select 1,'2016-11-08',5 union all 
select 1,'2016-11-09',4 union all 
select 1,'2016-11-10',6 union all 
select 1,'2016-11-11',1 union all 
select 1,'2016-11-12',3 union all 
select 1,'2016-11-14',2 union all 
select 1,'2016-11-15',2 union all 
select 1,'2016-11-16',4 union all 
select 1,'2016-11-17',2 union all 
select 1,'2016-11-18',2 union all 

select 2,'2016-10-31',1 union all 
select 2,'2016-11-01',7 union all 
select 2,'2016-11-02',0 union all 
select 2,'2016-11-03',0 union all 
select 2,'2016-11-04',0 union all 
select 2,'2016-11-05',0 union all 
select 2,'2016-11-07',0 union all 
select 2,'2016-11-08',0 union all 
select 2,'2016-11-09',1 union all 
select 2,'2016-11-10',3 union all 
select 2,'2016-11-11',2 union all 
select 2,'2016-11-12',3 union all 
select 2,'2016-11-14',7 union all 
select 2,'2016-11-15',6 union all 
select 2,'2016-11-16',3 union all 
select 2,'2016-11-17',5 union all 
select 2,'2016-11-18',3; 

-- Set the number of days that sales can accrue towards a Bonus. 
declare @DaysInBonusPeriod int = 6; 

with rn -- Derived table to get incremental ordering for recursice cte. This is useful as Sundays are ignored. 
as 
(
    select t.AgentID 
      ,t.DateValue 
      ,t.Sales 
      ,row_number() over (order by t.AgentID, t.DateValue) as rn 
    from @t t 
) 
,prev -- Using the row numbering above, find the number of sales in the day before the bonus accrual period. We have to use the row numbers as Sundays are ignored. 
as 
(
     select t.AgentID 
       ,t.DateValue 
       ,t.Sales 
       ,t.rn 
       ,isnull(tp.Sales,0) as SalesOnDayBeforeCurrentPeriod 
     from rn t 
      left join rn tp 
       on(t.AgentID = tp.AgentID 
        and tp.rn = t.rn - @DaysInBonusPeriod  -- Get number of sales on the day before the max Bonus period. 
        ) 
) 
,cte -- Use a recursive cte to calculate running totals based on sales, whether the bonus was achieved the previous day and if the previous bonus was more than 5 days ago. 
as 
(
    select rn 
      ,AgentID 
      ,DateValue 
      ,Sales 
      ,SalesOnDayBeforeCurrentPeriod 
      ,Sales as TotalSales 
      ,case when Sales >= 15 then 1 else 0 end as Bonus 
      ,1 as DaysSinceLastBonus 

    from prev 
    where rn = 1 -- Select just the first row in the dataset. 

    union all 

    select t.rn 
      ,t.AgentID 
      ,t.DateValue 
      ,t.Sales 
      ,t.SalesOnDayBeforeCurrentPeriod 

      -- If the previous row was for the same agent and not a bonus, add the day's sales to the total, subtracting the sales from the day before the 6 day bonus period if it has been more than 6 days since the last bonus. 
      ,case when t.AgentID = c.AgentID 
       then case when c.Bonus = 0 
         then t.Sales + c.TotalSales - case when c.DaysSinceLastBonus >= @DaysInBonusPeriod then t.SalesOnDayBeforeCurrentPeriod else 0 end 
         else t.Sales 
         end 
       else t.Sales 
       end as TotalSales 

      -- If the value in the TotalSales field above is 15 or more, flag a bonus. 
      ,case when 
        case when t.AgentID = c.AgentID                            --\ 
        then case when c.Bonus = 0                             -- \ 
          then t.Sales + c.TotalSales - case when c.DaysSinceLastBonus >= @DaysInBonusPeriod then t.SalesOnDayBeforeCurrentPeriod else 0 end -- \ Same statement 
          else t.Sales                              --/as TotalSales 
          end                                 --/
        else t.Sales                                --/ 
        end >= 15 
       then 1 
       else 0 
       end as Bonus 

      -- If there is no flag in Bonus field above, increment the number of days since the last bonus. 
      ,case when 
       case when                                   --\ 
         case when t.AgentID = c.AgentID                            -- \ 
         then case when c.Bonus = 0                             -- | 
           then t.Sales + c.TotalSales - case when c.DaysSinceLastBonus >= @DaysInBonusPeriod then t.SalesOnDayBeforeCurrentPeriod else 0 end -- | 
           else t.Sales                              -- \ Same statement 
           end                                 --/as Bonus 
         else t.Sales                                -- | 
         end >= 15                                 -- | 
        then 1                                   --/
        else 0                                   --/ 
        end = 0 
       then c.DaysSinceLastBonus + 1 
       else 0 
       end as DaysSinceLastBonus 

    from prev t 
     inner join cte c 
      on(t.rn = c.rn+1) 
) 
select AgentID 
     ,DateValue 
     ,Sales 
     ,TotalSales 
     ,Bonus 
from cte 
order by rn 
option (maxrecursion 0); 
+0

위대한 일을 내가. 코드가 복잡하고 코드를 보았다. 실현 한 것 이상이다. CTE에 재귀 적 제한이 있는데, 제한을 늘리거나 작게 나누어서 해결할 수있을 것이라고 확신한다. 척. 라이브 데이터에 대해 더 많은 테스트를 해보 겠지만 작동하는 것처럼 보입니다. – Bob

+1

@Bob 걱정하지 말자. :) 마지막으로, 업데이트 된 스크립트마다'maxrecursion' 옵션을 추가하십시오. '0'은 데이터가 끝날 때까지 실행되며 0이 아닌 값은 해당 재귀 횟수까지 실행되어 적중 될 경우 오류가 발생합니다. – iamdave