2013-03-21 92 views
0

假設我有一個表,指出每個銷售代表在特定月份銷售的物品數量。但是,在沒有銷售的情況下,幾個月內不會有一個特定的人排隊。例如sql服務器滾動12個月總計與日期差距

rep_id  month_yr  num_sales  
1   01/01/2012 3  
1   05/01/2012 1  
1   11/01/2012 1  
2   02/01/2012 2  
2   05/01/2012 1 

我希望能夠創建一個查詢,顯示每個rep_id和所有可能個月(01/01/2012,02/01/2012,通過等電流)一個連續12個月銷量總和,像這樣:

rep_id  month_yr  R12_Sum  
1   11/01/2012 5  
1   12/01/2012 5  
1   01/01/2013 5  
1   02/01/2013 2 

我在網上找到了一些例子,但我遇到的問題是我錯過了每個rep_id的一些日期。我是否需要交叉加入或什麼?

+0

使用CTE或數字表來生成所需日期的範圍,然後左外部連接您的數據。 – HABO 2013-03-21 15:10:03

+0

嘿HABO,我會如何實現這個?我創建了一個指定從1/01/11向前的所有日期的CTE。左外連接是否真的會從CTE返回所有行? – Jeremy 2013-03-21 15:25:04

+0

您希望創建一個CTE,以返回報告範圍內每月的第一個月份,例如,過去的12個月。然後加入你的滾動12個月總結表。需要外部聯接以確保輸出中仍包含沒有活動的報告月份。 – HABO 2013-03-21 16:52:57

回答

2

爲了解決這個問題,你需要具有所有年/月組合的驅動器表。然後,你需要爲每個代表創建這個。

然後解決方案是將實際數據連接到此驅動程序並彙總所需的時間段。以下是查詢:

with months as (
    select 1 as mon union all select 2 union all select 3 union all select 4 union all 
    select 5 as mon union all select 6 union all select 7 union all select 8 union all 
    select 9 as mon union all select 10 union all select 11 union all select 12 
    ), 
    years as (select 2010 as yr union all select 2011 union all select 2012 union all select 2013 
    ), 
    monthyears as (
    select yr, mon, yr*12+mon as yrmon 
    from months cross join years 
    ), 
    rmy as (
    select * 
    from monthyears my cross join 
      (select distinct rep_id from t 
     ) r 
    ) 
select rmy.rep_id, rmy.yr, rmy.mon, SUM(t.num_sales) as r12_sum 
from rmy join 
    t 
    on rmy.rep_id = t.rep_id and 
     t.year(month_yr)*12 + month(month_yr) between rmy.yrmon - 11 and rmy.yrmon 
group by rmy.rep_id, rmy.yr, rmy.mon 
order by 1, 2, 3 

這沒有經過測試,所以它可能有語法錯誤。此外,它不會將年/月組合轉換回日期,並將值留在單獨的列中。

+0

完美。對我的數據做了一些小的調整,它像魅力一樣工作,或者看起來如此。發佈這個問題後,這個想法突然出現在我的腦海中,通過交叉連接創建所有日期和rep_ids的組合表。您使實現變得簡單。謝謝! – Jeremy 2013-03-21 16:41:37

0

這裏是一個解決方案:

SELECT 
    a.rep_id 
    ,a.month_yr 
    ,SUM(b.R12_Sum) AS R12_TTM 
FROM YourTable a 
    LEFT OUTER JOIN YourTable b 
    ON a.rep_id = b.rep_id 
    AND a.month_yr <= b.month_yr 
    AND a.month_yr >= DATEADD(MONTH, -11, b.month_yr) 
GROUP BY 
    a.rep_id 
    ,a.month_yr 
+0

這不起作用。它執行滾動12,但僅限於表中實際存在的每個rep_id的日期。回到我的示例數據,rep_id 1將只有表中的3個日期的R12值。 – Jeremy 2013-03-21 15:20:12

0

這當然不是漂亮,但比CTE更簡單,數字表或自聯接:

DECLARE @startdt DATETIME 

SET @startdt = '2012-01-01' 

SELECT rep_id, YEAR(month_yr), MONTH(month_yr), SUM(num_sales) 
FROM MyTable WHERE month_yr >= @startdt AND month_yr < DATEADD(MONTH,1,@startdt) 

UNION ALL 

SELECT rep_id, YEAR(month_yr), MONTH(month_yr), SUM(num_sales) 
FROM MyTable WHERE month_yr >= DATEADD(MONTH,1,@startdt) AND month_yr < DATEADD(MONTH,2,@startdt) 

UNION ALL 

SELECT rep_id, YEAR(month_yr), MONTH(month_yr), SUM(num_sales) 
FROM MyTable WHERE month_yr >= DATEADD(MONTH,2,@startdt) AND month_yr < DATEADD(MONTH,3,@startdt) 

UNION ALL 

SELECT rep_id, YEAR(month_yr), MONTH(month_yr), SUM(num_sales) 
FROM MyTable WHERE month_yr >= DATEADD(MONTH,3,@startdt) AND month_yr < DATEADD(MONTH,4,@startdt) 

UNION ALL 

etc etc 
+0

這可能會起作用,但它坦白無法忍受。 – Jeremy 2013-03-21 16:40:36

0

下面演示了使用CTE生成日期的表格,並生成使用CTE的總結報告。當銷售代表沒有適用的銷售時,他們將被忽略。

嘗試跳轉報告參數,例如設置@RollingMonths1,以獲得更多娛樂。

-- Sample data. 
declare @Sales as Table (rep_id Int, month_yr Date, num_sales Int); 
insert into @Sales (rep_id, month_yr, num_sales) values 
    (1, '01/01/2012', 3), 
    (1, '05/01/2012', 1), 
    (1, '11/01/2012', 1), 
    (2, '02/01/2012', 1), 
    (2, '05/01/2012', 2); 
select * from @Sales; 

-- Reporting parameters. 
declare @ReportEnd as Date = DateAdd(day, 1 - Day(GetDate()), GetDate()); -- The first of the current month. 
declare @ReportMonths as Int = 6; -- Number of months to report. 
declare @RollingMonths as Int = 12; -- Number of months in rolling sums. 

-- Report. 
-- A CTE generates a table of month/year combinations covering the desired reporting time period. 
with ReportingIntervals as (
    select DateAdd(month, 1 - @ReportMonths, @ReportEnd) as ReportingInterval, 
    DateAdd(month, 1 - @RollingMonths, DateAdd(month, 1 - @ReportMonths, @ReportEnd)) as FirstRollingMonth 
    union all 
    select DateAdd(month, 1, ReportingInterval), DateAdd(month, 1, FirstRollingMonth) 
    from ReportingIntervals 
    where ReportingInterval < @ReportEnd) 
    -- Join the CTE with the sample data and summarize. 
    select RI.ReportingInterval, S.rep_id, Sum(S.num_sales) as R12_Sum 
    from ReportingIntervals as RI left outer join 
     @Sales as S on RI.FirstRollingMonth <= S.month_yr and S.month_yr <= RI.ReportingInterval 
    group by RI.ReportingInterval, S.rep_id 
    order by RI.ReportingInterval, S.rep_id 
+0

這很酷,非常靈活。小記,如果遇到遞歸限制,可以通過在查詢結尾處添加「option(MAXRECURSION 500)」來增加它。 – batkuip 2013-05-27 08:48:17