sqlpostgresqlstatisticsaggregation

REGR_SLOPE y REGR_INTERCEPT en PostgreSQL: linea de tendencia y prediccion en una consulta

Construye una linea de minimos cuadrados en SQL con REGR_SLOPE y REGR_INTERCEPT, cuida el orden (y, x), revisa REGR_COUNT y predice sin un paquete estadistico externo.

3 min de lecturaReferencesql · postgresql · statistics · aggregation · analytics · forecasting

REGR_SLOPE y REGR_INTERCEPT son funciones de agregacion que ajustan una recta por minimos cuadrados dentro de la propia consulta. Juntas dan la ecuacion y = slope * x + intercept, es decir, una linea de tendencia y una formula de prediccion lista, sin exportar los datos a Python o R.

Sintaxis y orden de los argumentos

Ambas funciones reciben dos argumentos, y aqui se esconde la trampa principal. El orden es: primero la variable dependiente y (lo que predices), luego la independiente x (a partir de la cual predices).

SELECT
    REGR_SLOPE(amount, extract(epoch from created_at)) AS slope,
    REGR_INTERCEPT(amount, extract(epoch from created_at)) AS intercept,
    REGR_COUNT(amount, extract(epoch from created_at)) AS n
FROM orders
WHERE status = 'paid';

Que hace cada parte:

  • REGR_SLOPE(y, x) -- la pendiente: cuanto cambia y en promedio por cada aumento de una unidad en x.
  • REGR_INTERCEPT(y, x) -- donde la recta corta el eje y (su valor en x = 0).
  • REGR_COUNT(y, x) -- el numero de pares donde ambos valores no son NULL. Ese es tu tamano de muestra.

Trampa: el orden es (y, x), no (x, y). Si los inviertes, ajustas la relacion inversa y la prediccion se desvia. Recuerdalo por el significado: "lo que predecimos" va primero.

Tendencia de ingresos por dia

Convierte la marca de tiempo en un numero (segundos de epoch) y pregunta si el pedido medio crece con el tiempo. Una pendiente escalada a dias se lee mejor que una por segundo:

SELECT
    REGR_SLOPE(amount, extract(epoch from created_at)) * 86400 AS amount_per_day,
    REGR_COUNT(amount, extract(epoch from created_at)) AS sample_size
FROM orders
WHERE status = 'paid';

Un amount_per_day positivo significa que los importes de los pedidos tienden a subir dia tras dia; uno negativo, que bajan. Manten REGR_COUNT al lado: una pendiente sobre tres puntos es ruido, no una tendencia.

Prediccion sin un paquete externo

Como ya tienes slope e intercept, predecir es solo sustituir un x en la ecuacion de la recta. Calcula los coeficientes una vez en un CTE y predice los ingresos en una fecha futura:

WITH model AS (
    SELECT
        REGR_SLOPE(amount, extract(epoch from created_at)) AS slope,
        REGR_INTERCEPT(amount, extract(epoch from created_at)) AS intercept
    FROM orders
    WHERE status = 'paid'
)
SELECT
    slope * extract(epoch from TIMESTAMP '2026-12-31') + intercept AS forecast_amount
FROM model;

El mismo truco no se limita al tiempo. Toma el salario en funcion del tamano del equipo de un jefe -- un ajuste lineal por departamento:

SELECT
    dept,
    REGR_SLOPE(salary, reports) AS salary_per_report,
    REGR_INTERCEPT(salary, reports) AS base_salary
FROM (
    SELECT
        e.dept,
        e.salary,
        count(r.id) AS reports
    FROM employees e
    LEFT JOIN employees r ON r.manager_id = e.id
    GROUP BY e.id, e.dept, e.salary
) s
GROUP BY dept;

Calidad del ajuste y trampas

La pendiente por si sola no dice nada sobre que tan bien describe la recta los datos. Para eso tienes REGR_R2 (el coeficiente de determinacion, de 0 a 1) y CORR (correlacion):

SELECT
    REGR_R2(amount, extract(epoch from created_at)) AS r_squared,
    CORR(amount, extract(epoch from created_at)) AS correlation
FROM orders
WHERE status = 'paid';

Cosas que conviene tener presentes:

  • Un R2 cercano a cero significa que la recta es casi inutil; la prediccion no merece confianza.
  • Si todos los x son identicos (varianza cero), la pendiente queda indefinida y la funcion devuelve NULL en vez de fallar.
  • Las filas donde y o x es NULL se descartan -- por eso siempre cotejas con REGR_COUNT.
  • La regresion lineal solo ve una recta. Aplanara la estacionalidad y el crecimiento exponencial y te enganara.

Diferencias entre motores

  • MySQL no tiene funciones REGR_*. Calcula la pendiente a mano: slope = (n*SUM(x*y) - SUM(x)*SUM(y)) / (n*SUM(x*x) - SUM(x)*SUM(x)), e intercept = (SUM(y) - slope*SUM(x)) / n.
  • ClickHouse ofrece simpleLinearRegression(x, y), y aqui el orden de los argumentos es inverso -- x va primero. Devuelve una tupla (slope, intercept).
  • BigQuery no tiene REGR_SLOPE ni REGR_INTERCEPT integradas -- la pendiente y el intercepto se calculan a mano con SUM, AVG y COVAR_POP/VAR_POP, o se entrena un modelo con CREATE MODEL ... OPTIONS(model_type='linear_reg') en BigQuery ML. Snowflake, en cambio, si soporta los estandar REGR_SLOPE(y, x) y REGR_INTERCEPT(y, x), igual que PostgreSQL.

Cuando quieres una linea de tendencia rapida o una prediccion barata dentro de la base de datos, REGR_SLOPE y REGR_INTERCEPT te ahorran todo un viaje a una herramienta analitica externa -- solo manten el orden de los argumentos claro y revisa el tamano de la muestra.

Practica con ejercicios reales

Resuelve ejercicios en el entrenador de SQL con corrección instantánea y pistas.

Abrir el entrenador