问题
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
WHERE
condition to limit the average to the samerep
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.
来源:https://stackoverflow.com/questions/19299039/12-month-moving-average-by-person-date