1. Faro

Nivel 9 · Desafío final: foto de rendimiento

La solicitud

De Megan Collins, Directora de Ventas

“Para el retiro de liderazgo necesito tres tablas de números: nuestros productos más vendidos por ingresos, lo que nos cuestan las devoluciones por motivo y qué tan bien convierte cada fuente de tráfico.”

Tu objetivo

Paso 1 de 3. Desde order_items, considerando solo las filas con quantity > 0 (todos los estados de pedido), devuelve los 10 productos principales por ingresos netos con las columnas product_id, units (suma de quantity) y net_revenue (suma de quantity * unit_price * (1 - discount_pct / 100.0), redondeada a 2). Ordena por net_revenue descendente y luego por product_id ascendente.

  • Lee de la tabla order_itemspendiente
  • Muestra exactamente product_id units net_revenuependiente
  • 10 filas, ordenadas como se pidependiente

Paso 1 · tu consulta

SQL

Cargando el editor…

    ResultadoVista previa de order_items · presiona Ejecutar para ver el tuyo
    Vista previa de order_items
    order_item_idorder_idproduct_idquantityunit_price
    11001121931.99
    21001154311.99
    31002154411.99
    410021941149.00

    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 returns · presiona Ejecutar para ver el tuyo
      Vista previa 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

      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 web_sessions · presiona Ejecutar para ver el tuyo
        Vista previa de web_sessions
        session_idcustomer_idstarted_atdevicesource
        1NULL2023-01-01 23:02:24mobilepaid
        2182023-01-01 15:07:49desktoppaid
        3NULL2023-01-01 16:55:46desktopdirect
        4NULL2023-01-01 12:43:28mobileorganic

        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.

        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
        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
        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
        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
        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 todo el capítulo: agregados sobre expresiones, agrupación, ordenamiento de resultados agrupados y filtrado de grupos.

        Paso 1: productos principales por ingresos

        Calcula los ingresos por línea, suma por producto y luego clasifica:

        SELECT product_id,
               SUM(quantity) AS units,
               ROUND(SUM(quantity * unit_price * (1 - discount_pct / 100.0)), 2) AS net_revenue
        FROM order_items
        WHERE quantity > 0
        GROUP BY product_id
        ORDER BY net_revenue DESC, product_id
        LIMIT 10;

        Esto incluye todos los estados de pedido porque el estado del pedido vive en otra tabla. En el capítulo 5 harás un join con orders y contarás solo los pedidos completados, que es lo que finanzas normalmente querría. Cuando se lo entregues a Megan, di qué versión es.

        Paso 2: devoluciones por motivo

        Tres agregados lado a lado. Un patrón útil al presentar: el conteo, el total y el promedio juntos te dicen si un motivo es caro porque es frecuente o porque cada devolución es grande. Las devoluciones por “damaged” pueden ser menos que las de “changed_mind” pero costar más cada una, lo que apunta a un problema de embalaje en lugar de un problema de producto.

        Paso 3: tasa de conversión por fuente

        converted es un booleano. Para contar los valores verdaderos, conviértelo en 1 o 0 y suma:

        SUM(CAST(converted AS INTEGER)) AS conversions

        Esto funciona en Postgres, DuckDB y MySQL. BigQuery lo escribe CAST(converted AS INT64) o COUNTIF(converted). Postgres y DuckDB también admiten el estándar COUNT(*) FILTER (WHERE converted), y todas las bases de datos admiten SUM(CASE WHEN converted THEN 1 ELSE 0 END), que verás en el capítulo 6.

        La tasa de conversión son las conversiones entre las sesiones. Multiplica por 100.0 antes de dividir, para que la división entera de Postgres no convierta cada tasa en 0. Luego HAVING COUNT(*) >= 5000 descarta las fuentes pequeñas, cuyas tasas son demasiado ruidosas para compararlas.

        Los grupos pequeños mienten

        ¿Por qué filtrar los grupos pequeños? Una fuente con 40 sesiones y 4 conversiones muestra una tasa del 10 %, que puede verse mejor que una fuente con 20,000 sesiones al 3 %. La pequeña es sobre todo ruido. Los analistas fijan de forma rutinaria un tamaño de muestra mínimo con HAVING antes de clasificar grupos por una tasa. Menciona el umbral en tus notas para que nadie se pregunte adónde fue una fuente.

        Errores comunes

        • Sumar el precio en lugar del valor de la línea. SUM(unit_price) ignora cuántas unidades se vendieron. Los ingresos son SUM(quantity * unit_price * (1 - discount_pct / 100.0)).
        • Restar el porcentaje como si fuera una fracción. discount_pct guarda 5 para un descuento del 5 %, así que (1 - discount_pct) da ingresos negativos. Divide primero entre 100.0.
        • Dividir antes de multiplicar por 100. En Postgres, SUM(CAST(converted AS INTEGER)) / COUNT(*) * 100 divide dos enteros y devuelve 0. Escribe 100.0 * SUM(...) / COUNT(*).
        • Clasificar tasas sin un tamaño mínimo. Una fuente con 40 sesiones puede quedar primera por suerte. Mantén HAVING COUNT(*) >= 5000 antes de ordenar por la tasa.

        En SQL Server

        El paso 1 usa SELECT TOP 10 ... ORDER BY net_revenue DESC. En el paso 3, converted sería un BIT, y SUM no acepta BIT directamente, así que conviértelo de la misma forma, y mantén 100.0 para que la tasa no se trunque:

        SUM(CAST(converted AS int)) AS conversions,
        ROUND(100.0 * SUM(CAST(converted AS int)) / COUNT(*), 2) AS conversion_pct

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