1. Faro

Nivel 7 · Desafío final: la revisión de retención

La solicitud

De Robert Kim, Director de Operaciones

“La semana que viene presento la retención ante la junta. Necesito tres cosas que pueda defender: cuántos de los clientes del año pasado volvieron a comprar este año, si el canal por el que un cliente compró por primera vez cambia qué tan probable es que se vaya, y qué parte de las ventas de 2025 vino de clientes que conservamos frente a los nuevos.”

Tu objetivo

Paso 1 de 3. Retención año contra año. Para cada año Y en 2023 y 2024, devuelve from_year (Y), customers (clientes con un pedido registrado en Y), retained (de ellos, clientes que también tienen un pedido registrado en Y + 1) y retention_pct (retained × 100 / customers, redondeado a 1), ordenado por from_year.

  • Lee de la tabla customerspendiente
  • Lee de la tabla orderspendiente
  • Muestra exactamente from_year customers retained retention_pctpendiente

Paso 1 · tu consulta

SQL

Cargando el editor…

    ResultadoVista previa de customers · presiona Ejecutar para ver el tuyo
    Vista previa de customers
    customer_idfirst_namelast_nameemailcity
    1OwenHudsonowen.hudson@icloud.comSan Francisco
    2DouglasMendozadmendoza69@gmail.comAtlanta
    3HenryBrookshbrooks@lakesidecafe.comLos Angeles
    4BrianGrahambgraham@bluecedarhomes.comSeattle

    Mote revisa tu resultado

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

    Paso 2 · tu consulta

    SQL

    Cargando el editor…

      ResultadoVista previa de customers · presiona Ejecutar para ver el tuyo
      Vista previa de customers
      customer_idfirst_namelast_nameemailcity
      1OwenHudsonowen.hudson@icloud.comSan Francisco
      2DouglasMendozadmendoza69@gmail.comAtlanta
      3HenryBrookshbrooks@lakesidecafe.comLos Angeles
      4BrianGrahambgraham@bluecedarhomes.comSeattle

      Mote revisa tu resultado

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

      Paso 3 · tu consulta

      SQL

      Cargando el editor…

        ResultadoVista previa de customers · presiona Ejecutar para ver el tuyo
        Vista previa de customers
        customer_idfirst_namelast_nameemailcity
        1OwenHudsonowen.hudson@icloud.comSan Francisco
        2DouglasMendozadmendoza69@gmail.comAtlanta
        3HenryBrookshbrooks@lakesidecafe.comLos Angeles
        4BrianGrahambgraham@bluecedarhomes.comSeattle

        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.

        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
        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
        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

        Tres preguntas, tres definiciones

        Una revisión de retención para una junta responde tres preguntas, y cada una necesita su propia definición escrita en la diapositiva:

        1. ¿Los clientes del año pasado vuelven a comprar? Retención año contra año: de los clientes activos en el año Y, la proporción que también está activa en Y + 1.
        2. ¿Quién se va? Abandono con una ventana de silencio fija, dividido por algo sobre lo que puedas actuar.
        3. ¿De dónde viene el dinero de este año? Ventas divididas entre clientes nuevos, retenidos y que regresan.

        Las tres usan solo pedidos registrados, como el resto del capítulo.

        Paso 1: retención año contra año

        Haz una fila por cliente y año, y luego une esa lista consigo misma desplazada un año:

        FROM active a
        LEFT JOIN active n ON n.customer_id = a.customer_id AND n.yr = a.yr + 1

        COUNT(*) cuenta a todos los activos en Y; COUNT(n.customer_id) cuenta solo a los que coincidieron en Y + 1, porque las filas sin coincidencia tienen NULL ahí. 2025 no tiene un año siguiente en los datos, así que no es un año de partida.

        Esta tasa es fácil de explicar, pero mezcla a clientes de toda la vida con personas que compraron por primera vez en diciembre. Una caída puede significar “más clientes nuevos”, no “peor retención”.

        Paso 2: abandono por primer canal

        arg_min(value, key) de DuckDB devuelve el valor de la fila con la menor clave: el canal del primer pedido de cada cliente. Luego reutiliza la regla del nivel 4: son elegibles los clientes que compraron por primera vez antes del 2025-07-04, y han abandonado los que no han comprado nada desde entonces.

        Paso 3: de dónde vinieron las ventas de 2025

        Etiqueta a cada comprador de 2025 según su historial. Nuevo: su primer pedido registrado es de 2025. Retenido: compró en 2024. Reactivado: compró antes de 2024, se saltó 2024 y regresó. Prueba “new” de forma explícita: el último pedido de un cliente nuevo antes de 2025 es NULL, y sin esa rama caería en el ELSE.

        La columna de proporción necesita un total junto a cada grupo. Una ventana sobre el resultado agrupado lo hace en una sola pasada:

        SUM(net_sales) * 100.0 / SUM(SUM(net_sales)) OVER ()

        Errores comunes

        • Inner join para la retención. Elimina a los clientes que no volvieron, y la retención pasa a ser 100%.
        • Abandono sobre todos los clientes. Conserva el filtro de elegibilidad del nivel 4.
        • Sin rama “new”. Sin una prueba sobre first_at, los clientes nuevos caen en “reactivated”.

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