La solicitud

De Ashley Rivera, Responsable de Contenido Web
Tu objetivo
Arregla la consulta. Para los clientes sin ninguna fila en web_sessions, devuelve una fila por segmento con: segment, customers (número de esos clientes) y with_orders (cuántos de ellos tienen al menos un pedido de cualquier estado).
- Lee de la tabla
customerspendiente - Lee de la tabla
orderspendiente - Muestra exactamente
segmentcustomerswith_orderspendiente
Tu consulta
Cargando el editor…
Solución de referencia
| customer_id | first_name | last_name | city | |
|---|---|---|---|---|
| 1 | Owen | Hudson | owen.hudson@icloud.com | San Francisco |
| 2 | Douglas | Mendoza | dmendoza69@gmail.com | Atlanta |
| 3 | Henry | Brooks | hbrooks@lakesidecafe.com | Los Angeles |
| 4 | Brian | Graham | bgraham@bluecedarhomes.com | Seattle |
Mote revisa tu resultado
Presiona Ejecutar. Cada fila que cumple el objetivo se vuelve una luciérnaga en tu linterna.
Lo que recibe Ashley, y por qué
Tablas
Datos de la tienda Harbor & Pine, listos para consultar.
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 |
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 |
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 |
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 |
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 |
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 |
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
Un resultado vacío también es un resultado. El starter dice que ningún cliente se saltó nunca el sitio web,
y eso es exactamente como se ve un fallo de NOT IN.
Por qué un NULL vacía el resultado
x NOT IN (a, b, c) significa x <> a AND x <> b AND x <> c. Si uno de los valores es NULL, x <> NULL
no es verdadero ni falso sino desconocido, y una cadena de AND que contiene un desconocido nunca puede
ser verdadera. La fila se filtra.
web_sessions tiene 23,002 sesiones anónimas con customer_id NULL. Así que para cada cliente,
customer_id NOT IN (SELECT customer_id FROM web_sessions) es desconocido, y la consulta no devuelve nada.
Ten en cuenta que IN no tiene este problema: una coincidencia es una coincidencia, sea lo que sea que
haya más en la lista. Por eso la columna with_orders del starter está bien.
Cómo detectarlo
- Un anti-join (
NOT IN, “nunca”, “sin”) que devuelve cero filas es sospechoso por sí solo. - Comprueba si la columna de la subconsulta tiene NULL:
SELECT COUNT(*) FROM web_sessions WHERE customer_id IS NULLdevuelve 23,002. - Cuenta el otro lado: 1,813 clientes distintos tienen una sesión, de 2,018 clientes. La respuesta no puede ser cero.
La solución
NOT EXISTS busca una fila coincidente, y un NULL nunca coincide:
WHERE NOT EXISTS (
SELECT 1 FROM web_sessions AS w
WHERE w.customer_id = c.customer_id
)
El resultado: 205 clientes, 29 de empresa y 176 consumidores. De ellos, 20 clientes de empresa y 101 consumidores han hecho un pedido, así que compran sin aparecer nunca en el seguimiento web (en la app o en un marketplace, por ejemplo).
Filtrar los NULL también funciona: NOT IN (SELECT customer_id FROM web_sessions WHERE customer_id IS NOT NULL) devuelve los mismos 205. Un LEFT JOIN ... WHERE w.session_id IS NULL también funciona,
pero NOT EXISTS expresa la intención con más claridad.
Errores comunes
- Añadir
COALESCE(customer_id, 0)dentro de la subconsulta: solo funciona mientras ningún id real sea 0. - Probar el
NOT INcon una muestra pequeña sin sesiones anónimas, donde parece funcionar. - Reportar “cero” sin comprobarlo. Un anti-join vacío merece la misma sospecha que un total que se duplicó.
En SQL Server
El comportamiento es idéntico con el ANSI_NULLS ON por defecto: un NULL en la lista y NOT IN no
devuelve nada. El mismo NOT EXISTS funciona tal cual, e ISNULL(x, 0) es el primo de dos argumentos de
COALESCE en T-SQL, con la misma salvedad de arriba.
Nota de entrevista
“¿Por qué esta consulta con NOT IN no devuelve filas?” es un clásico. La respuesta es la lógica de tres
valores con NULL, y la solución es NOT EXISTS.
¡Linterna encendida!
Practicaste: debuggingnot innullsnot existsanti join
- Resuelto
- Sin pistas
- Al primer intento
