Question

I have a table [production] that contains the following structure:

rep (char(10))    
,cyc_date (datetime) ---- already standardized to mm/01/yyyy
,amt (decimal)

I have data for each rep from 1/1/2011 to 8/1/2013. What I want to be able to do is create a 12 month moving average beginning 1/1/2012 for each rep, as follows:

rep    cyc_dt    12moAvg
-------------------------
A      1/1/2012    10000.01
A      2/1/2012    13510.05
.      ........    ........
A      8/1/2013    22101.32
B      1/1/2012    98328.22
B      ........    ........

where each row represents the 12 month moving average for said rep at stated time. I found some examples that were vaguely close and I tried them to no avail. It seems the addition of a group by rep component is the major departure from other examples.

This is about as far as I got:

SELECT
    rep,
    cyc_date,
    (
        SELECT Avg([amt])
        FROM production Q
        WHERE Q.[cyc_date] BETWEEN DateAdd("yyyy",-1,[cyc_date]+1) AND [cyc_date]
    ) AS 12moavg
FROM production

That query seems to pull an overall average or sum, since there is no grouping in the correlated subquery. When I try to group by, I get an error that it can only return at most one row.

Était-ce utile?

La solution

I think it may work with 2 adjustments to the correlated subquery.

  1. Subtract 11 months in the DateAdd() expression.
  2. Include another WHERE condition to limit the average to the same rep as the current row of the parent (containing) query.
SELECT
    p.rep,
    p.cyc_date,
    (
        SELECT Avg(Q.amt)
        FROM production AS Q
        WHERE
                Q.rep = p.rep
            AND
                Q.cyc_date BETWEEN DateAdd("m", -11, p.cyc_date)
                    AND p.cyc_date
    ) AS [12moavg]
FROM production AS p;

Correlated subqueries can be slow. Make sure to index rep and cyc_date to limit the pain with this one.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top