Skip to content
Empieza gratis

¿Cómo saco un promedio móvil de 3 meses en SQL?

Suaviza las ventas de Centro con un promedio de los últimos 3 meses, escribiendo tú el marco de la ventana.

Curso gratis. Tu Maestro, una IA, .

Las ventas mensuales suben y bajan. Un promedio móvil suaviza esos brincos: en cada mes, promedias ese mes y los dos anteriores. Así se ve mejor la tendencia.

Es una ventana con un marco que escribes tú:

  • ROWS BETWEEN 2 PRECEDING AND CURRENT ROW: las dos filas anteriores y la actual, tres en total.

Como en la página anterior, ROWS cuenta filas. Y como Centro tiene un registro por mes, tres filas son tres meses.

SQL · línea 3
AVG(ventas) OVER (
  ORDER BY mes
  ROWS BETWEEN 2 PRECEDING AND CURRENT ROW
)
La línea 3 es el marco: dos filas antes y la actual.

Inténtalo

Calcula el promedio móvil de 3 meses de Centro, redondeado sin decimales con ROUND(...). Antes, contesta la pregunta de abajo. Si tu promedio sale igual al acumulado, pregúntale a tu Maestro.

Comprueba lo que sabes: Antes de correr: ¿qué va a salir en promedio_3_meses en enero, cuando todavía no hay dos meses anteriores?

Para la sucursal Centro, regresa mes, ventas y promedio3meses: el promedio de ese mes y los dos anteriores, con ROUND(...) sin decimales. Ordena por mes. Terminaste cuando ves 12 filas y marzo dice 166500.

Tu turno

Para la sucursal Centro, regresa mes, ventas y promedio_3_meses: el promedio de ese mes y los dos anteriores, con ROUND(...) sin decimales. Ordena por mes. Terminaste cuando ves 12 filas y marzo dice 166500.

Tablas: ventas_mensuales (sucursal, mes, ventas)

ventas_mensuales · 35 filas

ColumnaTipo
sucursal Nombre de la sucursal: Centro, Norte o Sur.VARCHAR
mes Primer día del mes que resume la fila.DATE
ventas Ventas del mes, en pesos.BIGINT

Primeras filas

sucursalmesventas
Centro2025-01-01165100
Centro2025-02-01155700
Centro2025-03-01178700

Cada ejecución empieza con copias nuevas de las tablas del curso, así que puedes probar lo que quieras.

Listo para ejecutar tu consulta.

Ejecútalo tú

Fila por fila

El marco ahora se desliza: no empieza siempre en enero, empieza dos filas antes de la actual. Así se movió en los primeros meses de Centro al correr la solución en el sandbox:

mesventasfilas en el marcopromedio_3_meses
2025-01-01165100enero165100
2025-02-01155700enero y febrero160400
2025-03-01178700enero, febrero y marzo166500
2025-04-01175800febrero, marzo y abril170067

En abril, enero ya salió del marco. Esa es la diferencia con la suma acumulada de hace dos páginas: allá el inicio del marco estaba fijo en UNBOUNDED PRECEDING y aquí se mueve con cada fila.

En la gráfica, la línea de las ventas brinca y la del promedio de 3 meses la sigue más tranquila. La segunda sale de la ventana mean de Vega-Lite con un marco de dos filas antes a la actual.

Datos sintéticos del curso (CC0). El promedio sale de la ventana mean de Vega-Lite con frame [-2, 0].

Fíjate otra vez en enero y febrero: el marco pide "hasta dos filas antes", y al principio no las hay. No sale NULL; sale el promedio de las filas que sí están.

Lo que se rompe en la vida real

Promedios incompletos. Si en tu reporte solo quieres promedios de tres meses completos, cuenta las filas del marco con COUNT(*) sobre la misma ventana y quédate con las que tienen 3. En el sandbox, esta consulta regresó 10 filas, de marzo a diciembre:

SQL · línea 6
SELECT mes, ventas,
       ROUND(AVG(ventas) OVER w) AS promedio_3_meses
FROM ventas_mensuales
WHERE sucursal = 'Centro'
WINDOW w AS (ORDER BY mes ROWS BETWEEN 2 PRECEDING AND CURRENT ROW)
QUALIFY COUNT(*) OVER w = 3
ORDER BY mes;
COUNT(*) sobre el mismo marco dice cuántas filas promediaste. QUALIFY deja solo los marcos completos.

Un mes que falta. En Sur no hay junio. Con ROWS, el marco de julio son las tres filas anteriores que sí existen: abril, mayo y julio. Si lo que quieres son los tres meses del calendario, RANGE acepta una distancia en el valor del ORDER BY: RANGE BETWEEN INTERVAL 2 MONTH PRECEDING AND CURRENT ROW toma las filas cuyo mes está a dos meses o menos. En el sandbox, para Sur salió así:

mesventaspromedio con ROWSpromedio con RANGEfilas en RANGE
2025-05-011196001177671177673
2025-07-011176001194001186002
2025-08-011229001200331202502
2025-09-011145001183331183333

En julio y agosto los dos promedios se separan: RANGE no encuentra junio y promedia dos meses, ROWS se va hasta abril para juntar tres filas. Ninguno está mal; responden preguntas distintas.

Compruébalo tú

Antes, contesta la pregunta de abajo. Si tu RANGE da error o no cambia nada, pregúntale a tu Maestro.

Comprueba lo que sabes: Con RANGE BETWEEN INTERVAL 2 MONTH PRECEDING AND CURRENT ROW, ¿cuántas filas entran en el marco de julio de Sur?

Para la sucursal Sur, regresa mes, ventas, promrows (el promedio con ROWS BETWEEN 2 PRECEDING AND CURRENT ROW), promrange (con RANGE BETWEEN INTERVAL 2 MONTH PRECEDING AND CURRENT ROW) y mesesenrange (COUNT() con el mismo marco de RANGE). Redondea los promedios sin decimales con

Tu turno

Para la sucursal Sur, regresa mes, ventas, prom_rows (el promedio con ROWS BETWEEN 2 PRECEDING AND CURRENT ROW), prom_range (con RANGE BETWEEN INTERVAL 2 MONTH PRECEDING AND CURRENT ROW) y meses_en_range (COUNT(*) con el mismo marco de RANGE). Redondea los promedios sin decimales con ROUND(...) y ordena por mes. Terminaste cuando julio dice 119400, 118600 y 2.

Tablas: ventas_mensuales (sucursal, mes, ventas)

ventas_mensuales · 35 filas

ColumnaTipo
sucursal Nombre de la sucursal: Centro, Norte o Sur.VARCHAR
mes Primer día del mes que resume la fila.DATE
ventas Ventas del mes, en pesos.BIGINT

Primeras filas

sucursalmesventas
Centro2025-01-01165100
Centro2025-02-01155700
Centro2025-03-01178700

Cada ejecución empieza con copias nuevas de las tablas del curso, así que puedes probar lo que quieras.

Listo para ejecutar tu consulta.

Ejecútalo tú

Un promedio centrado. Si el promedio es para mirar la forma de la serie y no para reportar el último dato, puedes poner el mes en medio: ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING. En el sandbox, marzo de Centro dio 170067, el mismo número que el promedio de 3 meses de abril, porque son las mismas tres filas.

La pregunta típica de entrevista es "calcula el promedio móvil de 7 días de los usuarios activos". La trampa es la misma que con Sur: ROWS BETWEEN 6 PRECEDING AND CURRENT ROW cuenta 7 filas, y solo son 7 días si hay una fila por día, sin huecos. Di en voz alta qué supones, y ofrece la versión con RANGE e INTERVAL o rellenar el calendario como en el módulo 3. Si quieres practicar esta pregunta, pídele a tu Maestro que te la haga.

Antes de poner un promedio móvil en un tablero, revisa dos cosas: si los primeros periodos deben mostrarse (o filtrarse con COUNT(*)), y si tu serie tiene huecos. Escribe el marco completo en la consulta, aunque sea el de siempre, para que quien la lea sepa qué decidiste.

SQL · línea 3
ROUND(AVG(ventas) OVER (
  ORDER BY mes
  ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING
)) AS promedio_centrado
Un mes antes, el actual y uno después. En diciembre solo hay uno antes, y promedia dos.

Comprueba lo que sabes: Una función más que depende del marco por omisión: en Centro, ¿qué da LAST_VALUE(ventas) OVER (ORDER BY mes) en la fila de marzo?

Error común: LAST_VALUE y el marco por omisión

Con ORDER BY y sin marco escrito, el marco termina en la fila actual. Por eso LAST_VALUE(ventas) OVER (ORDER BY mes) no da diciembre: en cada fila da las ventas de esa misma fila. En una corrida con los datos de Centro, marzo dio 178700: sus propias ventas. Para el último valor de toda la partición, escribe el marco completo: ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING.

Comprueba lo que sabes: Quieres el promedio de cada mes con los dos anteriores. ¿Qué marco escribes?