1. Faro

Nivel 1 · Ingresos por envío que crecieron tras un join

¿Es nuevo para ti? Lee primero el concepto: Una consulta puede ejecutarse y estar mal

La solicitud

De Laura Bennett, Directora de Finanzas

“Esta consulta dice que el marketplace ganó $8,919.83 en cargos de envío en 2025. El procesador de pagos dice mucho menos. Los ingresos cuadran con nuestros libros, el envío no. ¿Puedes averiguar qué está mal y arreglarlo?”

Tu objetivo

Arregla la consulta. Para los pedidos con estado 'completed' realizados en 2025, devuelve una fila por canal con: channel, orders (número de pedidos), net_revenue (suma de quantity * unit_price * (1 - discount_pct / 100.0) sobre líneas con quantity > 0, redondeada a 2) y shipping_revenue (suma del shipping_fee de cada pedido contado una vez por pedido, redondeada a 2).

  • Lee de la tabla orderspendiente
  • Lee de la tabla order_itemspendiente
  • Muestra exactamente channel orders net_revenue shipping_revenuependiente

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

    La columna de ingresos del starter está bien y su columna de envío está mal, en la misma consulta. Esa combinación es la firma de la multiplicación de filas en un join: una suma sobre una columna que vive en el lado “uno” de un join uno a muchos.

    Qué hace realmente la consulta

    orders tiene una fila por pedido y order_items una por línea. Tras el join, un pedido con tres líneas aparece tres veces, y su shipping_fee se copia en las tres filas. El pedido 8235 del marketplace tiene un cargo de $4.99 y cinco líneas, así que el starter suma $24.95 por él.

    Los ingresos de línea están bien, porque el monto de cada línea aparece exactamente una vez. COUNT(DISTINCT o.order_id) también está bien. Solo se repite SUM(o.shipping_fee).

    Cómo detectarlo

    Compara los conteos de filas antes de confiar en una suma. Hay 4,295 pedidos completados en 2025, pero el join devuelve 10,800 filas. Si el grano que necesitas es “una fila por pedido” y el join da 2.5 veces eso, toda suma de una columna a nivel de pedido está inflada.

    Una segunda comprobación es calcular el número sospechoso sin el join:

    SELECT channel, ROUND(SUM(shipping_fee), 2) AS shipping_revenue
    FROM orders
    WHERE status = 'completed'
      AND order_date >= '2025-01-01' AND order_date < '2026-01-01'
    GROUP BY channel;

    Marketplace sale en $3,897.76, no en $8,919.83. Web es $3,890.50 en lugar de $5,588.90, y app $4,309.25 en lugar de $6,532.35.

    La solución: agrega primero el lado “muchos”

    Resume order_items a una fila por pedido en una CTE y luego haz el join. El join es uno a uno, así que ambas sumas son correctas en una sola consulta y el conteo de pedidos es un simple COUNT(*).

    Errores comunes

    • SUM(DISTINCT o.shipping_fee): reduce pedidos distintos que comparten un cargo.
    • Dividir la suma inflada entre el número promedio de líneas: una aproximación que cambia cada vez que cambia el tamaño de la cesta.
    • Filtrar quantity > 0 en la consulta externa tras preagregar: la CTE ya lo maneja, y la consulta externa ya no tiene una columna quantity.

    En SQL Server

    La misma CTE funciona sin cambios en T-SQL. Una diferencia aparece al probar partes: SQL Server no tiene LIMIT, así que mira unas cuantas filas unidas con TOP:

    SELECT TOP 10 o.order_id, o.shipping_fee, i.order_item_id
    FROM orders AS o JOIN order_items AS i ON i.order_id = o.order_id;

    En el trabajo

    “Los ingresos cuadran pero el envío, los impuestos o los descuentos a nivel de pedido no” casi siempre significa multiplicación de filas. Di en voz alta el grano de cada tabla antes de escribir el SELECT.

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