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
0 de 3
La solicitud

De Laura Bennett, Directora de Finanzas
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
channelordersnet_revenueshipping_revenuependiente
Tu consulta
Cargando el editor…
Solución de referencia
| order_id | customer_id | order_date | status | channel |
|---|---|---|---|---|
| 1001 | 125 | 2023-01-01 20:51:19 | completed | web |
| 1002 | 156 | 2023-01-02 07:58:46 | completed | web |
| 1003 | 22 | 2023-01-02 10:25:27 | completed | marketplace |
| 1004 | 48 | 2023-01-02 11:21:51 | completed | marketplace |
Mote revisa tu resultado
Presiona Ejecutar. Cada fila que cumple el objetivo se vuelve una luciérnaga en tu linterna.
Lo que recibe Laura, y por qué
Tablas
Datos de la tienda Harbor & Pine, listos para consultar.
orders12,000 filas · 7 columnas
order_idintegercustomer_idintegerorder_datetimestampstatusvarcharchannelvarcharshipping_feedecimalcoupon_codevarchar
| order_id | customer_id | order_date | status | channel | shipping_fee | coupon_code |
|---|---|---|---|---|---|---|
| 1001 | 125 | 2023-01-01 20:51:19 | completed | web | 0.00 | NULL |
| 1002 | 156 | 2023-01-02 07:58:46 | completed | web | 0.00 | NULL |
| 1003 | 22 | 2023-01-02 10:25:27 | completed | marketplace | 4.99 | WELCOME10 |
| 1004 | 48 | 2023-01-02 11:21:51 | completed | marketplace | 4.99 | WELCOME10 |
| 1005 | 82 | 2023-01-02 11:43:36 | completed | web | 0.00 | WELCOME10 |
order_items30,338 filas · 6 columnas
order_item_idintegerorder_idintegerproduct_idintegerquantityintegerunit_pricedecimaldiscount_pctdecimal
| order_item_id | order_id | product_id | quantity | unit_price | discount_pct |
|---|---|---|---|---|---|
| 1 | 1001 | 121 | 9 | 31.99 | 0.00 |
| 2 | 1001 | 154 | 3 | 11.99 | 0.00 |
| 3 | 1002 | 154 | 4 | 11.99 | 0.00 |
| 4 | 1002 | 194 | 1 | 149.00 | 0.00 |
| 5 | 1002 | 193 | 2 | 19.99 | 0.00 |
customers2,018 filas · 9 columnas
customer_idintegerfirst_namevarcharlast_namevarcharemailvarcharcityvarcharstatevarcharsignup_datedatesegmentvarcharreferral_sourcevarchar
| customer_id | first_name | last_name | city | state | signup_date | segment | referral_source | |
|---|---|---|---|---|---|---|---|---|
| 1 | Owen | Hudson | owen.hudson@icloud.com | San Francisco | CA | 2022-06-02 | consumer | search |
| 2 | Douglas | Mendoza | dmendoza69@gmail.com | Atlanta | GA | 2022-06-02 | consumer | NULL |
| 3 | Henry | Brooks | hbrooks@lakesidecafe.com | Los Angeles | CA | 2022-06-04 | business | NULL |
| 4 | Brian | Graham | bgraham@bluecedarhomes.com | Seattle | WA | 2022-06-06 | business | |
| 5 | Kyle | Jimenez | kjimenez27@yahoo.com | Indianapolis | IN | 2022-06-07 | consumer | NULL |
products120 filas · 8 columnas
product_idintegernamevarcharcategoryvarcharsubcategoryvarcharunit_pricedecimalunit_costdecimallaunched_ondateis_activeboolean
| product_id | name | category | subcategory | unit_price | unit_cost | launched_on | is_active |
|---|---|---|---|---|---|---|---|
| 101 | Vale Velvet Loveseat | Furniture | Sofas | 1659.00 | NULL | 2023-09-11 | true |
| 102 | Alder Oak Coffee Table | Furniture | Tables | 919.00 | 503.50 | 2024-05-16 | true |
| 103 | Orchard Rattan Dining Chair | Furniture | Chairs | 789.00 | 429.87 | 2023-05-27 | true |
| 104 | Upland Oak Bookcase | Furniture | Storage | 429.00 | 214.70 | 2022-12-20 | true |
| 105 | Avery Leather Bed Frame | Furniture | Beds | 449.00 | 232.70 | 2021-08-31 | true |
returns1,673 filas · 5 columnas
return_idintegerorder_item_idintegerreturned_ondatereasonvarcharrefund_amountdecimal
| return_id | order_item_id | returned_on | reason | refund_amount |
|---|---|---|---|---|
| 1 | 14 | 2023-01-10 | damaged | 83.69 |
| 2 | 42 | 2023-01-10 | wrong_item | 19.99 |
| 3 | 105 | 2023-01-14 | wrong_item | 10.99 |
| 4 | 24 | 2023-01-16 | changed_mind | 26.99 |
| 5 | 126 | 2023-01-16 | late | 20.99 |
employees60 filas · 8 columnas
employee_idintegerfirst_namevarcharlast_namevarchardepartmentvarchartitlevarcharmanager_idintegerhire_datedatesalaryinteger
| employee_id | first_name | last_name | department | title | manager_id | hire_date | salary |
|---|---|---|---|---|---|---|---|
| 1 | Catherine | Hale | Executive | Chief Executive Officer | NULL | 2016-03-01 | 285000 |
| 2 | Robert | Kim | Executive | Chief Operating Officer | 1 | 2017-01-09 | 235000 |
| 3 | Megan | Collins | Sales | Head of Sales | 1 | 2018-04-16 | 172000 |
| 4 | Chloe | Gutierrez | Sales | Account Executive | 3 | 2020-01-21 | 72000 |
| 5 | Frank | Bell | Sales | Account Executive | 3 | 2023-05-21 | 73000 |
web_sessions40,000 filas · 7 columnas
session_idintegercustomer_idintegerstarted_attimestampdevicevarcharsourcevarcharpages_viewedintegerconvertedboolean
| session_id | customer_id | started_at | device | source | pages_viewed | converted |
|---|---|---|---|---|---|---|
| 1 | NULL | 2023-01-01 23:02:24 | mobile | paid | 1 | false |
| 2 | 18 | 2023-01-01 15:07:49 | desktop | paid | 1 | false |
| 3 | NULL | 2023-01-01 16:55:46 | desktop | direct | 7 | false |
| 4 | NULL | 2023-01-01 12:43:28 | mobile | organic | 3 | false |
| 5 | NULL | 2023-01-01 13:06:21 | mobile | social | 2 | false |
marketing_spend3,276 filas · 3 columnas
spend_datedatechannelvarcharamountdecimal
| spend_date | channel | amount |
|---|---|---|
| 2023-01-01 | paid | 492.99 |
| 2023-01-01 | 37.38 | |
| 2023-01-01 | social | 200.53 |
| 2023-01-02 | paid | 709.13 |
| 2023-01-02 | 64.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 > 0en la consulta externa tras preagregar: la CTE ya lo maneja, y la consulta externa ya no tiene una columnaquantity.
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.
¡Linterna encendida!
Practicaste: debuggingfan outgrainpre aggregatecte
- Resuelto
- Sin pistas
- Al primer intento
