La solicitud

De Brian Mitchell, Analista de Finanzas
Tu objetivo
Para los pedidos con status 'completed', devuelve una fila por canal con: channel, orders (número de pedidos), shipping_revenue (suma de shipping_fee, contando cada pedido una vez, redondeada a 2) y merchandise_revenue (suma de los ingresos netos por línea quantity * unit_price * (1 - discount_pct / 100.0) sobre las líneas con quantity > 0, redondeada a 2).
- Lee de la tabla
orderspendiente - Lee de la tabla
order_itemspendiente - Muestra exactamente
channelordersshipping_revenuemerchandise_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 Brian, 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 consulta de Brian es un caso de manual del fan-out del capítulo 5. shipping_fee vive en orders, un
valor por pedido. Tras unir con order_items, la tarifa de cada pedido se copia en todas las líneas, y
SUM(o.shipping_fee) la suma una vez por línea. Ejecuta el código inicial: el envío sale aproximadamente 1.5 veces demasiado
alto en web y app y unas 2.4 veces demasiado alto en marketplace, donde los pedidos que pagan tarifa suelen tener
más líneas. La inflación ni siquiera es un factor constante que puedas dividir. Los ingresos por mercancía están bien, porque es un número a nivel de línea sumado a nivel de línea.
La solución: agrega primero el lado muchos
Lleva order_items al grano de orders (una fila por pedido) antes de unir:
WITH line_totals AS (
SELECT order_id,
SUM(quantity * unit_price * (1 - discount_pct / 100.0)) AS merchandise
FROM order_items
WHERE quantity > 0
GROUP BY order_id
)
SELECT o.channel,
COUNT(*) AS orders,
ROUND(SUM(o.shipping_fee), 2) AS shipping_revenue,
ROUND(SUM(COALESCE(l.merchandise, 0)), 2) AS merchandise_revenue
FROM orders AS o
LEFT JOIN line_totals AS l ON l.order_id = o.order_id
WHERE o.status = 'completed'
GROUP BY o.channel;
Ahora cada pedido coincide con como máximo una fila de line_totals. El join no puede multiplicar nada, así que ambas sumas
son correctas y COUNT(*) vuelve a contar pedidos.
Por qué LEFT JOIN y COALESCE
Un pedido cuyas líneas fueron todas filtradas (por ejemplo, solo cantidades erróneas) no tiene fila en line_totals.
Un inner join descartaría ese pedido y su tarifa de envío. El LEFT JOIN lo conserva, y COALESCE(l.merchandise, 0)
trata su mercancía faltante como cero. Aquí cero es un valor por defecto verdadero: el pedido no tuvo mercancía válida,
así que este es el uso legítimo de COALESCE del capítulo 6, no esconder un valor desconocido.
La receta general
Cuando necesitas medidas de dos tablas con granos distintos:
- Decide el grano de salida (aquí: canal).
- Agrega cada tabla “muchos” hasta la clave del join (aquí: por pedido) en su propio CTE.
- Une los CTE uno a uno y luego agrega al grano de salida.
Con dos tablas hijas, por ejemplo líneas y devoluciones por pedido, la receta importa aún más. Unir ambas tablas en bruto con orders multiplica líneas por devoluciones, y todos los números salen mal. Preagrega cada una por separado y luego haz el join.
Concilia
La comprobación de finanzas es sencilla: SELECT SUM(shipping_fee) FROM orders WHERE status = 'completed' debe
ser igual a la suma de shipping_revenue entre los canales. Si lo es, el fan-out ha desaparecido. Incorpora este tipo de
verificación cruzada a tu rutina para cualquier número que vaya a finanzas.
Nota de entrevista
Este patrón, “agrega antes de unir”, es una de las señales más claras de experiencia en una entrevista de analista. Si te piden combinar pedidos, artículos y pagos o sesiones, di desde el principio qué grano tiene cada tabla y cómo evitarás el doble conteo. A menudo importa más que la sintaxis final.
Errores comunes
- Sumar el envío tras un join en bruto con
order_items. Cada tarifa se suma una vez por línea. Lleva las líneas a una fila por pedido en un CTE y luego haz el join. - Dividir el total inflado entre el promedio de líneas por pedido. La inflación difiere por canal, así que ningún factor único lo arregla.
- Usar un inner join con los totales de línea. Los pedidos cuyas líneas fueron todas filtradas desaparecen, y también sus
tarifas de envío. Usa
LEFT JOINconCOALESCE(l.merchandise, 0). - Unir dos tablas hijas a la vez. Las líneas y las devoluciones unidas juntas a orders se multiplican entre sí. Preagrega cada una en su propio CTE.
En SQL Server
ISNULL(l.merchandise, 0) es la versión de dos argumentos de COALESCE en SQL Server. Una diferencia: ISNULL
devuelve el tipo de datos de su primer argumento, COALESCE el tipo más amplio de todos los argumentos, así que prefiere COALESCE
cuando los tipos difieren.
¡Linterna encendida!
Practicaste: ctefan outpre aggregationleft joincoalesce
- Resuelto
- Sin pistas
- Al primer intento
