Nivel 1 · Una clave por ubicación
¿Es nuevo para ti? Lee primero el concepto: Datos limpios significan un significado, una escritura
0 de 3
La solicitud

De Ryan Cooper, Gerente Regional de Ventas
Tu objetivo
Para los clientes cuya ciudad no es NULL, construye location_key como CONCAT(UPPER(TRIM(state)), '-', LOWER(TRIM(city))), por ejemplo 'NY-new york'. Devuelve location_key, customers (número de clientes) y raw_spellings (número de combinaciones distintas de ciudad y estado en bruto que terminan en esa clave). Conserva solo las claves con más de una grafía en bruto. Ordena por customers descendente y luego por location_key ascendente.
- Lee de la tabla
customerspendiente - Muestra exactamente
location_keycustomersraw_spellingspendiente - 47 filas, ordenadas como se pidependiente
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 Ryan, 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 |
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 |
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 |
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
El capítulo 6 limpió una columna: UPPER(TRIM(state)). Los informes reales suelen agrupar por varias columnas
desordenadas a la vez, así que necesitas una clave: un valor estandarizado que identifica lo que estás
contando, construido a partir de partes limpias.
Construir una clave
Una clave tiene tres ingredientes: limpiar cada parte, elegir una sola capitalización y unir las partes con un separador que no pueda aparecer dentro de ellas.
CONCAT(UPPER(TRIM(state)), '-', LOWER(TRIM(city))) -- 'NY-new york'
TRIM quita los espacios al principio y al final, UPPER y LOWER arreglan las mayúsculas, y CONCAT
pega las piezas. Minúsculas es una buena elección para la parte de la ciudad: es una clave, no una
etiqueta para mostrar. DuckDB no tiene INITCAP, así que poner bonito el título es trabajo de la capa de
informes.
¿Por qué incluir el estado? Porque Harbor & Pine tiene clientes tanto en Portland, Oregon como en Portland, Maine. Con la ciudad sola como clave se fusionarían en una ubicación.
Medir el desorden
Cuenta los valores en bruto dentro de cada grupo limpio para ver cuánto hizo la limpieza:
SELECT
CONCAT(UPPER(TRIM(state)), '-', LOWER(TRIM(city))) AS location_key,
COUNT(*) AS customers,
COUNT(DISTINCT city || '|' || state) AS raw_spellings
FROM customers
WHERE city IS NOT NULL
GROUP BY 1;
Con estos datos, los 2,004 clientes con ciudad tienen 168 pares distintos de ciudad y estado en bruto, que
se reúnen en 62 ubicaciones. NY-new york tiene 181 clientes repartidos en 5 grafías, y TX-houston
tiene 8. Los 14 clientes con ciudad NULL se dejan fuera a propósito: un NULL es un dato que falta, no una
grafía, y recibe su propio tratamiento en el nivel 3.
Errores comunes
- Sin separador.
COUNT(DISTINCT city || state)devuelve 163 en lugar de 168, porque'Houston' || ' TX'y'Houston ' || 'TX'producen la misma cadena. Pon un carácter como|entre las partes, o cuenta el par directamente conCOUNT(DISTINCT (city, state)). - Limpiar en el SELECT, agrupar en bruto. Si haces
GROUP BY city, statey solo limpias en el SELECT, obtienes varias filas que muestran la misma clave, cada una con un conteo parcial. - Limpiar de más. Quitar todos los espacios convertiría “San Jose” en “sanjose”. Recorta los extremos, conserva el interior.
En el trabajo
Guarda una lista de las grafías en bruto que reuniste y envíasela a quien sea dueño del formulario del CRM. Arreglar la entrada (un menú desplegable en lugar de texto libre) es mejor que limpiar el mismo desorden en cada consulta para siempre. En una entrevista, “¿cómo contarías los clientes por ciudad?” es una prueba de si revisas primero el texto.
En SQL Server
TRIM, UPPER, LOWER y CONCAT existen con los mismos nombres (TRIM desde SQL Server 2017; el
código más antiguo usa LTRIM(RTRIM(city))). Usa + o CONCAT para unir cadenas. Ojo con LEN: ignora
los espacios finales, así que LEN('Boston ') es 6, mientras que DATALENGTH cuenta bytes.
SELECT CONCAT(UPPER(TRIM(state)), '-', LOWER(TRIM(city))) AS location_key, COUNT(*) AS customers
FROM customers WHERE city IS NOT NULL
GROUP BY CONCAT(UPPER(TRIM(state)), '-', LOWER(TRIM(city))); ¡Linterna encendida!
Practicaste: data cleaningtrimupperlowerconcatgrouping key
- Resuelto
- Sin pistas
- Al primer intento
