问题
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.
回答1:
I think it may work with 2 adjustments to the correlated subquery.
- Subtract 11 months in the DateAdd()expression.
- Include another WHEREcondition to limit the average to the samerepas 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.
来源:https://stackoverflow.com/questions/19299039/12-month-moving-average-by-person-date