La solicitud

De Lauren Hayes, Gerente de Email Marketing
Tu objetivo
Usando pedidos completados y líneas con quantity > 0, calcula primero los ingresos netos por pedido (suma de quantity * unit_price * (1 - discount_pct / 100.0)). Luego devuelve los 10 mejores clientes con: customer_id, orders (número de pedidos completados), lifetime_revenue (suma de los ingresos de los pedidos, redondeada a 2) y avg_order_value (promedio de los ingresos por pedido, redondeado a 2). Ordena por lifetime_revenue descendente y luego por customer_id ascendente.
- Lee de la tabla
orderspendiente - Lee de la tabla
order_itemspendiente - Muestra exactamente
customer_idorderslifetime_revenueavg_order_valuependiente
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 Lauren, 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
Una expresión de tabla común (CTE) es una subconsulta con nombre que defines al inicio con WITH y luego usas como
una tabla:
WITH order_revenue AS (
SELECT o.order_id, o.customer_id,
SUM(i.quantity * i.unit_price * (1 - i.discount_pct / 100.0)) AS revenue
FROM orders AS o
JOIN order_items AS i ON i.order_id = o.order_id
WHERE o.status = 'completed' AND i.quantity > 0
GROUP BY o.order_id, o.customer_id
)
SELECT customer_id, COUNT(*) AS orders, SUM(revenue) AS lifetime_revenue
FROM order_revenue
GROUP BY customer_id;
Hace el mismo trabajo que una tabla derivada en FROM, pero se lee de arriba abajo, como explicarías la lógica en voz alta: “primero obtén los ingresos por pedido, luego súmalos por cliente”.
Por qué el valor promedio de pedido necesita dos pasos
El valor promedio de pedido (AOV) es el promedio de los totales de pedido. Si calcularas
AVG(quantity * unit_price ...) directamente sobre las líneas unidas, obtendrías el valor promedio de
línea, un número mucho más pequeño. El CTE fija el grano en una fila por pedido, así que AVG(revenue) es un
AOV real. Esto es lo más útil que hacen los CTE para los analistas: hacer explícito el grano de cada paso.
Varios CTE
Sepáralos con comas. Los posteriores pueden leer a los anteriores:
WITH order_revenue AS (
...
),
customer_value AS (
SELECT customer_id, SUM(revenue) AS lifetime_revenue
FROM order_revenue
GROUP BY customer_id
)
SELECT *
FROM customer_value
WHERE lifetime_revenue > 10000;
Pon a los CTE el nombre de lo que representa una fila (order_revenue, customer_value, monthly_sales). Así
cualquiera puede leer el plan de la consulta solo con los nombres.
Depurar con CTE
Mientras desarrollas, termina la consulta con SELECT * FROM order_revenue LIMIT 20 para mirar cualquier paso
de forma aislada. Eso hace el código inicial. Comprueba el conteo de filas de cada paso con lo que esperas
(aquí, una fila por pedido completado) antes de construir sobre él.
Notas por dialecto
Los CTE se admiten en Postgres, DuckDB, BigQuery, Snowflake, SQL Server y MySQL 8+ (no en MySQL 5.7).
Postgres antes de la versión 12 siempre materializaba los CTE, lo que podía hacerlos más lentos que las subconsultas; en
las versiones actuales el optimizador los integra en línea, como hacen DuckDB y BigQuery. WITH RECURSIVE es una
función aparte para recorrer jerarquías.
Nota de entrevista
En las entrevistas de SQL en vivo, estructurar tu respuesta con CTE casi siempre es buena idea. Muestra tu forma de pensar, facilita que el entrevistador te siga y te permite probar cada paso. Una consulta larga con tres niveles de subconsultas anidadas también sirve, pero es mucho más difícil de explicar bajo presión.
Errores comunes
- Promediar valores de línea y llamarlo AOV.
AVG(quantity * unit_price ...)sobre las líneas unidas es el promedio de línea. Suma primero cada pedido en un CTE y luego tomaAVG(revenue). - Escribir
WITHdos veces.WITH a AS (...) WITH b AS (...)es un error de sintaxis. Usa un solo WITH y separa los CTE con comas:WITH a AS (...), b AS (...). - Seleccionar una columna por la que el CTE no agrupó. Si
order_revenueagrupa solo pororder_id,o.customer_idno puede aparecer en su SELECT. Agrupa poro.order_id, o.customer_id. - Dejar la línea de depuración.
SELECT * FROM order_revenue LIMIT 20sirve para mirar un paso; la consulta final debe resumir el CTE a una fila por cliente.
En SQL Server
WITH funciona igual, pero la sentencia anterior debe terminar con punto y coma, por eso los scripts suelen
empezar con ;WITH. Para echar un vistazo a un paso, usa SELECT TOP 20 * FROM order_revenue.
¡Linterna encendida!
Practicaste: ctewithmulti stepaverage order valuelifetime value
- Resuelto
- Sin pistas
- Al primer intento
