1. Faro

Nivel 9 · Desafío final: perfil de la base de clientes

La solicitud

De Jordan Reyes, Director de Marketing

“Estoy planeando el presupuesto de adquisición del próximo año. Necesito los registros mensuales de 2025 divididos en consumidores y empresas, los principales proveedores de correo que usan nuestros clientes y un desglose de fuentes de referencia donde las fuentes desconocidas estén etiquetadas, no en blanco.”

Tu objetivo

Paso 1 de 3. Para los clientes con signup_date en 2025, devuelve una fila por mes con: month (primer día del mes, como DATE), consumer_signups (segment 'consumer'), business_signups (segment 'business') y total_signups. Ordena por month ascendente.

  • Lee de la tabla customerspendiente
  • Muestra exactamente month consumer_signups business_signups total_signupspendiente
  • 12 filas, ordenadas como se pidependiente

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

        Este Desafío final combina las herramientas del capítulo en un perfil con el que marketing puede planificar.

        Paso 1: registros por mes y segmento

        Es un pivot pequeño: meses en vertical, segmentos en horizontal. DATE_TRUNC construye la clave de mes y la agregación condicional divide el conteo:

        SUM(CASE WHEN segment = 'business' THEN 1 ELSE 0 END) AS business_signups

        signup_date ya es un DATE, así que el rango semiabierto se compara limpiamente. Incluir total_signups permite al lector verificar que las dos columnas de segmento suman, una pequeña cortesía que genera confianza.

        Paso 2: dominios de correo

        El dominio es todo lo que va después de la @. DuckDB y Postgres tienen SPLIT_PART(s, delimitador, n), que divide una cadena y devuelve la n-ésima parte (empezando en 1):

        SPLIT_PART(LOWER(TRIM(email)), '@', 2) AS domain

        Limpia primero y divide después: ' Owen@ICloud.com' y 'owen@icloud.com' deben caer en el mismo grupo. Los dialectos varían mucho aquí:

        base de datos dominio de un correo
        DuckDB, Postgres, Snowflake SPLIT_PART(email, '@', 2)
        BigQuery SPLIT(email, '@')[SAFE_OFFSET(1)] (empieza en 0)
        MySQL SUBSTRING_INDEX(email, '@', -1)
        Cualquiera SUBSTRING(email FROM POSITION('@' IN email) + 1)

        Un conteo de filas de clientes por dominio es un primer vistazo, no una respuesta final: los registros de clientes duplicados lo inflan un poco. Deduplicarás clientes correctamente en el capítulo 7.

        Paso 3: etiquetar lo desconocido

        COALESCE(a, b, ...) devuelve su primer argumento que no es NULL. Es la forma estándar de dar una etiqueta a un NULL en un informe:

        COALESCE(referral_source, 'unknown') AS referral_source

        Agrupar por el valor con COALESCE convierte el grupo NULL en una fila “unknown” legible. Esa fila importa: si un tercio de los clientes no tiene fuente registrada, los datos de atribución tienen un hueco, y Jordan debería saberlo antes de repartir un presupuesto por fuente. No la elimines con un WHERE.

        Usa COALESCE para etiquetas y para valores por defecto reales (un descuento que falta de verdad es 0). No lo uses para esconder números desconocidos: COALESCE(unit_cost, 0) haría que los productos de costo desconocido parecieran 100 % rentables.

        Nota de dialecto

        COALESCE es estándar y funciona en todas partes. También verás IFNULL(a, b) en MySQL y BigQuery, NVL en Oracle y Snowflake, e ISNULL en SQL Server. Reciben exactamente dos argumentos; COALESCE recibe cualquier cantidad.

        Errores comunes

        • Dividir antes de limpiar. SPLIT_PART(email, '@', 2) pone ICloud.com e icloud.com en grupos distintos. Limpia primero: SPLIT_PART(LOWER(TRIM(email)), '@', 2).
        • Contar con un ELSE 0. COUNT(CASE WHEN segment = 'business' THEN 1 ELSE 0 END) cuenta todas las filas, porque 0 no es NULL. Usa SUM con ELSE 0, o COUNT sin ELSE.
        • Descartar las fuentes desconocidas. WHERE referral_source IS NOT NULL oculta el hueco que Jordan necesita ver. Etiquétalas con COALESCE(referral_source, 'unknown') en su lugar.
        • Usar COALESCE con números realmente desconocidos. COALESCE(unit_cost, 0) convierte un costo que falta en un producto gratis. Reserva COALESCE para etiquetas y valores por defecto reales.

        En SQL Server

        No hay SPLIT_PART. Obtén el dominio con SUBSTRING(email, CHARINDEX('@', email) + 1, LEN(email)). ISNULL(referral_source, 'unknown') funciona como el COALESCE de dos argumentos, y la clave de mes es DATEFROMPARTS(YEAR(signup_date), MONTH(signup_date), 1).

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