Las cadenas sucias son el pan de cada dia de un analista: espacios sobrantes de las importaciones, telefonos llenos de guiones, codigos con mayusculas y minusculas mezcladas. Tres funciones — TRIM, SUBSTRING y REPLACE — cubren casi toda esa limpieza rutinaria. Las veremos sobre un esquema con users(id, email, name, country, created_at), orders(id, user_id, amount, status, created_at) y employees(id, name, manager_id, dept, salary).
TRIM: quitar espacios y basura
Por defecto, TRIM elimina los espacios de ambos extremos. Es lo primero que conviene aplicar a cualquier campo de texto que venga de una fuente externa.
SELECT TRIM(name) AS clean_name
FROM users;
Puedes recortar solo un lado e incluso indicar tu propio conjunto de caracteres:
SELECT TRIM(LEADING FROM name) AS no_left,
TRIM(TRAILING FROM name) AS no_right
FROM users;
SELECT TRIM(BOTH '0' FROM '00description') AS no_zeros;
Parientes utiles: LTRIM y RTRIM para recortar un solo lado, y BTRIM en PostgreSQL como sinonimo corto de TRIM(BOTH ...).
TRIM solo quita los caracteres de los extremos, nunca los internos: 'a b' conserva su doble espacio en el medio.
- Los caracteres invisibles — tabuladores (
\t), saltos de linea, el espacio de no separacion — quedan intactos con un TRIM simple. Para ellos, combinalo con REPLACE o REGEXP_REPLACE.
SUBSTRING: cortar por posicion
SUBSTRING extrae un trozo de una cadena. La sintaxis estandar canonica usa las palabras clave FROM (inicio, empezando en 1) y FOR (longitud):
SELECT SUBSTRING(country FROM 1 FOR 3) AS region_prefix
FROM users;
La forma posicional con comas da el mismo resultado; es mas corta y le resulta familiar a mucha gente:
SELECT SUBSTRING(country, 1, 3) AS region_prefix
FROM users;
Un truco habitual es sacar el dominio de un correo localizando la posicion de @ con POSITION:
SELECT SUBSTRING(email FROM POSITION('@' IN email) + 1) AS domain
FROM users;
REPLACE: sustituir subcadenas
REPLACE(source, from, to) reemplaza TODAS las apariciones de un literal. Es perfecto para quitar formato — por ejemplo, convertir un telefono en digitos limpios:
SELECT REPLACE(REPLACE(name, '-', ''), ' ', '') AS compact
FROM users;
REPLACE trabaja solo con cadenas literales, sin patrones. Si necesitas expresiones regulares, recurre a REGEXP_REPLACE en PostgreSQL:
SELECT REGEXP_REPLACE(name, '[^0-9]', '', 'g') AS digits_only
FROM users;
Construir una clave normalizada
La verdadera potencia esta en combinarlas. Una tarea tipica es construir una clave estable para deduplicar o para joins: minusculas, sin espacios, sin separadores.
SELECT o.id,
LOWER(TRIM(u.country)) || '_' ||
REPLACE(LOWER(o.status), ' ', '_') AS norm_key
FROM orders o
JOIN users u ON u.id = o.user_id;
Para un informe por departamentos puedes ensamblar un codigo prolijo a partir del nombre y el departamento:
SELECT id,
UPPER(SUBSTRING(TRIM(dept) FROM 1 FOR 3)) || '-' ||
UPPER(SUBSTRING(TRIM(name) FROM 1 FOR 2)) AS emp_code
FROM employees;
Diferencias entre motores
- PostgreSQL: admite tanto
SUBSTRING(x FROM a FOR b) como SUBSTRING(x, a, b); SUBSTR existe como sinonimo. Empieza en 1.
- MySQL:
SUBSTRING y SUBSTR son equivalentes, y la sintaxis FROM ... FOR tambien funciona. Admite un inicio negativo — cuenta desde el final de la cadena.
- ClickHouse: la funcion es
substring(s, offset, length), solo en forma posicional; replaceAll en lugar de REPLACE, y trimBoth/trimLeft/trimRight en lugar de TRIM.
El gran tropiezo: la indexacion de cadenas en SQL empieza en 1, no en 0. SUBSTRING(x FROM 0 FOR 3) se comporta de forma poco intuitiva — la posicion cero se come un caracter de la longitud. Cuenta siempre desde uno y FROM 1 FOR n te dara exactamente los primeros n caracteres.
Las cadenas sucias son el pan de cada dia de un analista: espacios sobrantes de las importaciones, telefonos llenos de guiones, codigos con mayusculas y minusculas mezcladas. Tres funciones —
TRIM,SUBSTRINGyREPLACE— cubren casi toda esa limpieza rutinaria. Las veremos sobre un esquema conusers(id, email, name, country, created_at),orders(id, user_id, amount, status, created_at)yemployees(id, name, manager_id, dept, salary).TRIM: quitar espacios y basura
Por defecto,
TRIMelimina los espacios de ambos extremos. Es lo primero que conviene aplicar a cualquier campo de texto que venga de una fuente externa.SELECT TRIM(name) AS clean_name FROM users;Puedes recortar solo un lado e incluso indicar tu propio conjunto de caracteres:
-- Leading vs trailing SELECT TRIM(LEADING FROM name) AS no_left, TRIM(TRAILING FROM name) AS no_right FROM users; -- Strip a specific character, not just spaces SELECT TRIM(BOTH '0' FROM '00description') AS no_zeros; -- 'description'Parientes utiles:
LTRIMyRTRIMpara recortar un solo lado, yBTRIMen PostgreSQL como sinonimo corto deTRIM(BOTH ...).TRIMsolo quita los caracteres de los extremos, nunca los internos:'a b'conserva su doble espacio en el medio.\t), saltos de linea, el espacio de no separacion — quedan intactos con unTRIMsimple. Para ellos, combinalo conREPLACEoREGEXP_REPLACE.SUBSTRING: cortar por posicion
SUBSTRINGextrae un trozo de una cadena. La sintaxis estandar canonica usa las palabras claveFROM(inicio, empezando en 1) yFOR(longitud):-- First 3 chars of the country code SELECT SUBSTRING(country FROM 1 FOR 3) AS region_prefix FROM users;La forma posicional con comas da el mismo resultado; es mas corta y le resulta familiar a mucha gente:
SELECT SUBSTRING(country, 1, 3) AS region_prefix FROM users;Un truco habitual es sacar el dominio de un correo localizando la posicion de
@conPOSITION:SELECT SUBSTRING(email FROM POSITION('@' IN email) + 1) AS domain FROM users;REPLACE: sustituir subcadenas
REPLACE(source, from, to)reemplaza TODAS las apariciones de un literal. Es perfecto para quitar formato — por ejemplo, convertir un telefono en digitos limpios:-- Strip dashes and spaces from a phone-like field SELECT REPLACE(REPLACE(name, '-', ''), ' ', '') AS compact FROM users;REPLACE trabaja solo con cadenas literales, sin patrones. Si necesitas expresiones regulares, recurre a
REGEXP_REPLACEen PostgreSQL:-- Keep digits only SELECT REGEXP_REPLACE(name, '[^0-9]', '', 'g') AS digits_only FROM users;Construir una clave normalizada
La verdadera potencia esta en combinarlas. Una tarea tipica es construir una clave estable para deduplicar o para joins: minusculas, sin espacios, sin separadores.
-- A normalized join key from country + status SELECT o.id, LOWER(TRIM(u.country)) || '_' || REPLACE(LOWER(o.status), ' ', '_') AS norm_key FROM orders o JOIN users u ON u.id = o.user_id;Para un informe por departamentos puedes ensamblar un codigo prolijo a partir del nombre y el departamento:
SELECT id, UPPER(SUBSTRING(TRIM(dept) FROM 1 FOR 3)) || '-' || UPPER(SUBSTRING(TRIM(name) FROM 1 FOR 2)) AS emp_code FROM employees;Diferencias entre motores
SUBSTRING(x FROM a FOR b)comoSUBSTRING(x, a, b);SUBSTRexiste como sinonimo. Empieza en 1.SUBSTRINGySUBSTRson equivalentes, y la sintaxisFROM ... FORtambien funciona. Admite un inicio negativo — cuenta desde el final de la cadena.substring(s, offset, length), solo en forma posicional;replaceAllen lugar deREPLACE, ytrimBoth/trimLeft/trimRighten lugar deTRIM.El gran tropiezo: la indexacion de cadenas en SQL empieza en 1, no en 0.
SUBSTRING(x FROM 0 FOR 3)se comporta de forma poco intuitiva — la posicion cero se come un caracter de la longitud. Cuenta siempre desde uno yFROM 1 FOR nte dara exactamente los primerosncaracteres.