La solicitud

De Brian Mitchell, Analista de Finanzas
Tu objetivo
Para los pedidos con status 'completed' hechos en 2025, une con order_items (líneas con quantity > 0) y devuelve una fila por mes con: month (el primer día del mes, como DATE), orders (pedidos distintos) y net_revenue (suma de quantity * unit_price * (1 - discount_pct / 100.0), redondeada a 2). Ordena por month ascendente.
- Lee de la tabla
orderspendiente - Lee de la tabla
order_itemspendiente - Muestra exactamente
monthordersnet_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
“Ingresos por mes” quizá sea la consulta de analista más común. El truco es convertir cada timestamp en una clave de mes y luego agrupar por ella.
DATE_TRUNC
DATE_TRUNC('month', ts) redondea un timestamp hacia abajo hasta el inicio de su mes:
2025-03-18 14:22:05 se convierte en 2025-03-01 00:00:00. Todo pedido de marzo se asigna al mismo valor, así que
agrupar por él da una fila por mes.
SELECT
CAST(DATE_TRUNC('month', order_date) AS DATE) AS month,
COUNT(*) AS orders
FROM orders
GROUP BY 1
ORDER BY 1;
Otras unidades funcionan igual: 'day', 'week' (las semanas empiezan el lunes en Postgres y DuckDB),
'quarter', 'year'.
En DuckDB y Postgres, truncar un timestamp devuelve un timestamp. El CAST(... AS DATE) convierte el
resultado en una fecha limpia, que queda mejor en gráficos y hojas de cálculo.
¿Por qué no EXTRACT(MONTH …)?
EXTRACT(MONTH FROM order_date) devuelve de 1 a 12. Si agrupas por eso en tres años de datos, marzo de 2023,
2024 y 2025 quedan juntos en una fila. DATE_TRUNC conserva el año, así que es la clave correcta para una serie
de tiempo. Usa EXTRACT (o DATE_PART) para preguntas de estacionalidad como “¿qué mes del año es el
más ocupado?”.
Dialectos
| base de datos | clave de mes |
|---|---|
| DuckDB, Postgres, Snowflake | DATE_TRUNC('month', order_date) |
| BigQuery | DATE_TRUNC(order_date, MONTH) (o TIMESTAMP_TRUNC para timestamps) |
| MySQL | DATE_FORMAT(order_date, '%Y-%m-01'), o DATE_SUB(DATE(order_date), INTERVAL DAY(order_date) - 1 DAY) |
| SQL Server | DATETRUNC(month, order_date) (2022+) o DATEFROMPARTS(YEAR(d), MONTH(d), 1) |
Ponerlo todo junto
Los ingresos necesitan las líneas, el estado necesita el pedido. Tras el join, el grano son las líneas de pedido, así que cuenta
pedidos con COUNT(DISTINCT o.order_id) (recuerda el fan-out del capítulo 5). Filtra el año con un rango
semiabierto sobre la columna original, no sobre la truncada, para que la base de datos pueda saltarse datos
de forma eficiente.
Meses faltantes
Si un mes no tuvo pedidos completados, simplemente no aparecería. Para un gráfico, un mes faltante es engañoso: la línea salta directamente de febrero a abril. Genera un calendario y haz LEFT JOIN sobre él:
SELECT CAST(m AS DATE) AS month
FROM generate_series(DATE '2025-01-01', DATE '2025-12-01', INTERVAL 1 MONTH) AS t(m);
generate_series existe en Postgres y DuckDB. BigQuery usa GENERATE_DATE_ARRAY. Harbor & Pine
tiene ventas todos los meses, así que aquí no lo necesitas, pero con datos dispersos (un producto, una región pequeña)
sí lo harás.
Errores comunes
- Agrupar por el timestamp en bruto: una fila por segundo, no por mes.
- Dar formato de texto al mes, como
'Mar 2025', y luego ordenarlo: abril se ordena antes que enero. Conserva una fecha real para ordenar y da formato al final del todo, o en la herramienta de gráficos.
En SQL Server
DATETRUNC(month, o.order_date) existe desde SQL Server 2022. En versiones anteriores construye el primer día con
DATEFROMPARTS(YEAR(o.order_date), MONTH(o.order_date), 1). EOMONTH(o.order_date) devuelve el último día del
mes, que algunos informes financieros usan como clave de mes en su lugar.
¡Linterna encendida!
Practicaste: date trunctime seriesgroup byrevenue
- Resuelto
- Sin pistas
- Al primer intento
