1. Faro

Nivel 4 · Crecimiento mes a mes

La solicitud

De Megan Collins, Directora de Ventas

“Para cada mes de 2025, ¿cómo cambiaron los ingresos completados respecto al mes anterior, en dólares y en porcentaje? Enero debe compararse con diciembre de 2024.”

Tu objetivo

Usando pedidos completados y líneas con quantity > 0, calcula los ingresos netos mensuales (suma de quantity * unit_price * (1 - discount_pct / 100.0)) de todos los meses. Devuelve solo los 12 meses de 2025 con: month (primer día, como DATE), net_revenue (redondeado a 2), prev_revenue (los ingresos netos del mes calendario anterior, redondeados a 2; para enero de 2025 es diciembre de 2024) y mom_growth_pct ((net_revenue - prev_revenue) / prev_revenue * 100, redondeado a 1). Ordena por month ascendente.

  • Lee de la tabla orderspendiente
  • Lee de la tabla order_itemspendiente
  • Muestra exactamente month net_revenue prev_revenue mom_growth_pctpendiente

Tu consulta

SQL

Cargando el editor…

    ResultadoVista previa de orders · presiona Ejecutar para ver el tuyo
    Vista previa de orders
    order_idcustomer_idorder_datestatuschannel
    10011252023-01-01 20:51:19completedweb
    10021562023-01-02 07:58:46completedweb
    1003222023-01-02 10:25:27completedmarketplace
    1004482023-01-02 11:21:51completedmarketplace

    Mote revisa tu resultado

    Presiona Ejecutar. Cada fila que cumple el objetivo se vuelve una luciérnaga en tu linterna.

    Tablas

    Datos de la tienda Harbor & Pine, listos para consultar.

    orders12,000 filas · 7 columnas
    • order_idinteger
    • customer_idinteger
    • order_datetimestamp
    • statusvarchar
    • channelvarchar
    • shipping_feedecimal
    • coupon_codevarchar
    Primeras 5 filas de orders
    order_idcustomer_idorder_datestatuschannelshipping_feecoupon_code
    10011252023-01-01 20:51:19completedweb0.00NULL
    10021562023-01-02 07:58:46completedweb0.00NULL
    1003222023-01-02 10:25:27completedmarketplace4.99WELCOME10
    1004482023-01-02 11:21:51completedmarketplace4.99WELCOME10
    1005822023-01-02 11:43:36completedweb0.00WELCOME10
    order_items30,338 filas · 6 columnas
    • order_item_idinteger
    • order_idinteger
    • product_idinteger
    • quantityinteger
    • unit_pricedecimal
    • discount_pctdecimal
    Primeras 5 filas de order_items
    order_item_idorder_idproduct_idquantityunit_pricediscount_pct
    11001121931.990.00
    21001154311.990.00
    31002154411.990.00
    410021941149.000.00
    51002193219.990.00
    customers2,018 filas · 9 columnas
    • customer_idinteger
    • first_namevarchar
    • last_namevarchar
    • emailvarchar
    • cityvarchar
    • statevarchar
    • signup_datedate
    • segmentvarchar
    • referral_sourcevarchar
    Primeras 5 filas de customers
    customer_idfirst_namelast_nameemailcitystatesignup_datesegmentreferral_source
    1OwenHudsonowen.hudson@icloud.comSan FranciscoCA2022-06-02consumersearch
    2DouglasMendozadmendoza69@gmail.comAtlantaGA2022-06-02consumerNULL
    3HenryBrookshbrooks@lakesidecafe.comLos AngelesCA2022-06-04businessNULL
    4BrianGrahambgraham@bluecedarhomes.comSeattleWA2022-06-06businesspinterest
    5KyleJimenezkjimenez27@yahoo.comIndianapolisIN2022-06-07consumerNULL
    products120 filas · 8 columnas
    • product_idinteger
    • namevarchar
    • categoryvarchar
    • subcategoryvarchar
    • unit_pricedecimal
    • unit_costdecimal
    • launched_ondate
    • is_activeboolean
    Primeras 5 filas de products
    product_idnamecategorysubcategoryunit_priceunit_costlaunched_onis_active
    101Vale Velvet LoveseatFurnitureSofas1659.00NULL2023-09-11true
    102Alder Oak Coffee TableFurnitureTables919.00503.502024-05-16true
    103Orchard Rattan Dining ChairFurnitureChairs789.00429.872023-05-27true
    104Upland Oak BookcaseFurnitureStorage429.00214.702022-12-20true
    105Avery Leather Bed FrameFurnitureBeds449.00232.702021-08-31true
    returns1,673 filas · 5 columnas
    • return_idinteger
    • order_item_idinteger
    • returned_ondate
    • reasonvarchar
    • refund_amountdecimal
    Primeras 5 filas de returns
    return_idorder_item_idreturned_onreasonrefund_amount
    1142023-01-10damaged83.69
    2422023-01-10wrong_item19.99
    31052023-01-14wrong_item10.99
    4242023-01-16changed_mind26.99
    51262023-01-16late20.99
    employees60 filas · 8 columnas
    • employee_idinteger
    • first_namevarchar
    • last_namevarchar
    • departmentvarchar
    • titlevarchar
    • manager_idinteger
    • hire_datedate
    • salaryinteger
    Primeras 5 filas de employees
    employee_idfirst_namelast_namedepartmenttitlemanager_idhire_datesalary
    1CatherineHaleExecutiveChief Executive OfficerNULL2016-03-01285000
    2RobertKimExecutiveChief Operating Officer12017-01-09235000
    3MeganCollinsSalesHead of Sales12018-04-16172000
    4ChloeGutierrezSalesAccount Executive32020-01-2172000
    5FrankBellSalesAccount Executive32023-05-2173000
    web_sessions40,000 filas · 7 columnas
    • session_idinteger
    • customer_idinteger
    • started_attimestamp
    • devicevarchar
    • sourcevarchar
    • pages_viewedinteger
    • convertedboolean
    Primeras 5 filas de web_sessions
    session_idcustomer_idstarted_atdevicesourcepages_viewedconverted
    1NULL2023-01-01 23:02:24mobilepaid1false
    2182023-01-01 15:07:49desktoppaid1false
    3NULL2023-01-01 16:55:46desktopdirect7false
    4NULL2023-01-01 12:43:28mobileorganic3false
    5NULL2023-01-01 13:06:21mobilesocial2false
    marketing_spend3,276 filas · 3 columnas
    • spend_datedate
    • channelvarchar
    • amountdecimal
    Primeras 5 filas de marketing_spend
    spend_datechannelamount
    2023-01-01paid492.99
    2023-01-01email37.38
    2023-01-01social200.53
    2023-01-02paid709.13
    2023-01-02email64.13

    La lección

    LAG(x) devuelve el valor de x de la fila anterior en el orden de la ventana. LEAD(x) devuelve el de la fila siguiente. Hacen trivial comparar un periodo con el anterior:

    SELECT
      month,
      net_revenue,
      LAG(net_revenue) OVER (ORDER BY month) AS prev_revenue
    FROM monthly;

    El crecimiento es entonces simple aritmética: (net_revenue - prev_revenue) / prev_revenue * 100.

    Filtra después de la ventana, no antes

    Esta es la trampa en la petición de Megan. Si la CTE monthly solo contuviera 2025, enero no tendría fila anterior y prev_revenue sería NULL. Las funciones de ventana solo ven las filas que sobreviven al WHERE. Entonces:

    1. Construye los ingresos mensuales de todos los meses.
    2. Calcula LAG sobre todos ellos.
    3. Filtra a 2025 en la consulta externa.

    Enero de 2025 se compara entonces correctamente con diciembre de 2024. El mismo principio se aplica a los totales acumulados, las medias móviles y los rankings: filtrar pronto cambia lo que ve la ventana.

    Opciones de LAG

    LAG(net_revenue, 12) OVER (ORDER BY month)     -- same month last year (year-over-year)
    LAG(net_revenue, 1, 0) OVER (ORDER BY month)   -- default 0 instead of NULL
    LEAD(net_revenue) OVER (ORDER BY month)        -- next month

    LAG(x, 12) para año a año solo funciona si todos los meses están presentes. LAG cuenta filas, no meses calendario: si falta un mes, “12 filas atrás” son 13 meses atrás. Con datos dispersos, haz primero un join con un calendario generado (capítulo 6), o une cada mes con month - INTERVAL 1 YEAR.

    Evita el valor por defecto 0 en los cálculos de crecimiento. Dividir entre un cero falso es un error o infinito, y un crecimiento NULL en el primer periodo es la respuesta honesta.

    Por grupo

    Añade PARTITION BY para comparar dentro de cada grupo, por ejemplo los días desde el pedido anterior de cada cliente:

    CAST(order_date AS DATE)
      - LAG(CAST(order_date AS DATE)) OVER (PARTITION BY customer_id ORDER BY order_date) AS days_since_prev

    Estacionalidad

    El crecimiento mes a mes es ruidoso en un negocio estacional. Harbor & Pine vende mucho más en noviembre y diciembre, así que enero siempre parece un desplome junto a diciembre. Por eso los equipos de finanzas suelen preferir el crecimiento año a año del mismo mes, que compara cosas equivalentes.

    Porcentaje vs puntos porcentuales

    Si la tasa de conversión pasa de 2.0% a 2.5%, eso son +0.5 puntos porcentuales, o +25% de crecimiento relativo. Di cuál de los dos quieres decir en un informe; la gente los confunde constantemente.

    Nota de entrevista

    “Calcula el crecimiento mes a mes” es una pregunta estándar de entrevista de analista. Las buenas respuestas agregan a meses en una CTE, usan LAG, explican qué pasa con el primer mes y mencionan que LAG cuenta filas, así que los meses faltantes necesitan un calendario.

    Errores comunes

    • Filtrar a 2025 antes del LAG. Enero se queda entonces sin fila anterior y su crecimiento es NULL. Calcula LAG sobre todos los meses y luego filtra en la consulta externa.
    • Dividir entre el mes equivocado. El crecimiento es (net_revenue - prev_revenue) / prev_revenue, no / net_revenue.
    • Darle a LAG un valor por defecto de 0. LAG(net_revenue, 1, 0) hace que el primer mes divida entre cero. Deja el valor por defecto en NULL.
    • Usar LAG(x, 12) para año a año cuando faltan meses. LAG cuenta filas, no meses calendario, así que un hueco desplaza todas las comparaciones posteriores.

    En SQL Server

    LAG(net_revenue, 1) OVER (ORDER BY month) es idéntico. Protege la tasa de crecimiento con NULLIF(prev_revenue, 0), que SQL Server también tiene, y recuerda que dividir dos enteros trunca.

    Elige qué puede ejecutarse en este sitio. Puedes cambiarlo cuando quieras desde "Configurar cookies", al pie de cada página.