2013-03-21 51 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