La solicitud

De Lauren Hayes, Gerente de Email Marketing
Tu objetivo
Devuelve customer_id, email y signup_date de todos los clientes que no tienen ninguna fila en orders.
- Lee de la tabla
customerspendiente - Lee de la tabla
orderspendiente - Muestra exactamente
customer_idemailsignup_datependiente
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 Lauren, 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 |
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 |
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
LEFT JOIN conserva todas las filas de la tabla izquierda, encuentren o no una coincidencia. Cuando no hay
coincidencia, las columnas de la tabla derecha se rellenan con NULL:
SELECT c.customer_id, c.email, o.order_id
FROM customers AS c
LEFT JOIN orders AS o ON o.customer_id = c.customer_id;
Un cliente con cinco pedidos aparece cinco veces. Un cliente sin pedidos aparece una vez, con
order_id NULL. Compáralo con JOIN, que descartaría a ese cliente por completo.
Encontrar lo que falta
Como las filas sin coincidencia tienen NULL en el lado derecho, puedes quedarte solo con esas:
SELECT c.customer_id, c.email, c.signup_date
FROM customers AS c
LEFT JOIN orders AS o ON o.customer_id = c.customer_id
WHERE o.order_id IS NULL;
Este patrón se llama anti-join: filas de A sin coincidencia en B. Los analistas lo usan constantemente: clientes que nunca pidieron, productos que nunca se vendieron, sesiones sin cliente, pedidos sin envío.
Comprueba una columna que no puede ser NULL en una coincidencia
Revisa la clave de la tabla derecha (o.order_id) o la columna del join (o.customer_id), nunca una columna
opcional. Si escribieras WHERE o.coupon_code IS NULL, también obtendrías a todos los clientes cuyos pedidos
simplemente no tenían cupón, que son la mayoría. Una clave primaria nunca es NULL en una coincidencia real, así que su
NULL significa “sin coincidencia” y nada más.
Otras formas de escribirlo
-- NOT EXISTS: often the clearest, and safe with NULLs
SELECT c.customer_id, c.email, c.signup_date
FROM customers AS c
WHERE NOT EXISTS (
SELECT 1 FROM orders AS o WHERE o.customer_id = c.customer_id
);
NOT EXISTS se cubre en el capítulo 7. Evita WHERE customer_id NOT IN (SELECT customer_id FROM orders)
cuando la columna de la subconsulta pueda contener NULL: un solo NULL hace que NOT IN no devuelva ninguna fila.
RIGHT y FULL joins
RIGHT JOIN es un LEFT JOIN con las tablas intercambiadas. La mayoría de los equipos nunca lo usan y escriben primero la tabla
que quieren conservar. FULL OUTER JOIN conserva las filas sin coincidencia de ambos lados, útil para
conciliar dos fuentes (“qué pedidos están en el sistema del almacén pero no en facturación, y al
revés”). MySQL no admite FULL OUTER JOIN; se emula con un UNION de un LEFT y un
RIGHT join.
Errores comunes
- Usar
JOINy luego buscar NULL. Un inner join nunca produce filas sin coincidencia, así que el resultado siempre está vacío. - Contar “clientes” tras un LEFT JOIN con
COUNT(*). Los clientes con varios pedidos se cuentan varias veces. UsaCOUNT(DISTINCT c.customer_id).
En SQL Server
LEFT JOIN ... WHERE o.order_id IS NULL, NOT EXISTS y NOT IN funcionan todos igual. LEFT OUTER JOIN
es la forma larga de LEFT JOIN allí como en todas partes; la palabra OUTER es opcional.
¡Linterna encendida!
Practicaste: left joinanti joinis null
- Resuelto
- Sin pistas
- Al primer intento
