1. Qué es
= compara texto exacto. Cuando no sabes el valor entero —quieres "los que empiezan por A", "los que contienen Manager"— hace falta un operador de patrón.
PostgreSQL tiene tres niveles, de menos a más potencia:
| Operador | Potencia | Cuándo |
|---|---|---|
LIKE / ILIKE |
Dos comodines | El 90% de los casos |
SIMILAR TO |
Regex disfrazada de LIKE |
Casi nunca — ver la sección 5 |
~ / ~* |
Expresión regular completa | Cuando LIKE no llega |
Empieza siempre por LIKE. Solo cuando se quede corto, sube.
2. Sintaxis
2.1 LIKE — dos comodines y ya
| Comodín | Significa |
|---|---|
% |
Cualquier cosa, incluida nada |
_ |
Exactamente un carácter |
| Patrón | Encuentra |
|---|---|
'A%' |
Empieza por A |
'%ez' |
Termina en ez |
'%Chef%' |
Contiene Chef |
'_h%' |
Segunda letra es h |
'___' |
Exactamente tres caracteres |
NOT LIKE niega. ILIKE es igual que LIKE pero ignora mayúsculas (la I es de insensitive) — y es exclusivo de PostgreSQL.
2.2 Regex — lo mínimo que hace falta
| Operador | Significa |
|---|---|
~ |
Coincide con la regex |
~* |
Coincide, ignorando mayúsculas |
!~ |
No coincide |
| Símbolo | Significa |
|---|---|
^ |
Principio del texto |
$ |
Final del texto |
[CB] |
Una letra, C o B |
[^CB] |
Una letra que no sea C ni B |
[0-9] |
Un dígito |
. |
Cualquier carácter |
+ * ? |
Una o más / cero o más / cero o una |
Diferencia clave con LIKE: la regex busca dentro del texto por defecto. LIKE 'Ch%' significa "empieza por Ch"; ~ 'Ch' significa "contiene Ch". Para anclar hay que poner ^.
3. Ejemplos sobre Northwind
Pregunta: ¿qué clientes tienen un nombre de empresa que empieza por A?
SELECT
company_name
FROM
customers
WHERE
company_name LIKE 'A%'
ORDER BY
company_name;
company_name
------------------------------------
Alfreds Futterkiste
Ana Trujillo Emparedados y helados
Antonio Moreno Taquería
Around the Horn
(4 filas)
4 de 91 clientes. LIKE 'A%' se lee "empieza por A y sigue lo que sea".
Pregunta: ¿qué clientes de Alemania tienen a algún tipo de gerente (Manager) como contacto?
SELECT
company_name,
country,
contact_title
FROM
customers
WHERE
contact_title LIKE '%Manager%'
AND country = 'Germany'
ORDER BY
contact_title, company_name;
company_name | country | contact_title
--------------------+---------+--------------------
QUICK-Stop | Germany | Accounting Manager
Frankenversand | Germany | Marketing Manager
Toms Spezialitäten | Germany | Marketing Manager
(3 filas)
Mira la columna contact_title: ninguno dice literalmente "Manager" a secas — dice "Accounting Manager" o "Marketing Manager". %Manager% los encuentra a todos sin que tengas que enumerar cada variante: el % a ambos lados significa "y lo que sea antes, y lo que sea después".
Pregunta: ¿qué productos tienen la letra h justo en la segunda posición del nombre?
SELECT
product_name
FROM
products
WHERE
product_name LIKE '_h%'
ORDER BY
product_name;
product_name
------------------------------
Chai
Chang
Chartreuse verte
Chef Anton's Cajun Seasoning
Chef Anton's Gumbo Mix
Chocolade
Rhönbräu Klosterbier
Thüringer Rostbratwurst
(8 filas)
8 productos. _ ocupa exactamente un hueco: ni cero, ni dos.
3.1 Mayúsculas: LIKE vs ILIKE
Pregunta: ¿cuántos clientes tienen un nombre que empieza por "a", escrita tal cual la escribiría alguien sin pensarlo, en minúscula?
SELECT
count(*)
FROM
customers
WHERE
company_name LIKE 'a%';
count
-------
0
(1 fila)
Cero. Los cuatro clientes de la sección anterior existen, pero LIKE distingue mayúsculas y ninguno empieza por a minúscula. Con ILIKE, que la ignora, aparecen los mismos 4:
SELECT
count(*)
FROM
customers
WHERE
company_name ILIKE 'a%';
count
-------
4
Y el caso que enseña de verdad por qué importa:
Pregunta: ¿qué clientes NO tienen la letra "a" en su nombre?
SELECT
company_name
FROM
customers
WHERE
company_name NOT LIKE '%a%'
ORDER BY
company_name
LIMIT 5;
company_name
--------------------------
Alfreds Futterkiste
Around the Horn
Blondesddsl père et fils
Chop-suey Chinese
Comércio Mineiro
Alfreds Futterkiste aparece en la lista de "no contiene la letra a". Y es correcto: contiene A, no a. Si lo que querías era "sin la letra a", el patrón correcto era NOT ILIKE '%a%'.
3.2 Los acentos son otro carácter
SELECT
'Antonio Moreno Taquería' LIKE '%Taqueria%' AS sin_tilde,
'Antonio Moreno Taquería' LIKE '%Taquería%' AS con_tilde;
sin_tilde | con_tilde
-----------+-----------
f | t
Ni LIKE ni ILIKE ignoran acentos. Northwind está lleno de Taquería, Côte de Blaye, Rhönbräu, Comércio. Un buscador que exija la tilde exacta es un buscador roto.
Resolverlo bien no es trivial: tilde aguda, diéresis y circunflejo son marcas distintas, y un patrón que cubra una se sigue rompiendo con otra. La extensión unaccent —específica de PostgreSQL, no existe en SQL Server ni MySQL— lo resuelve de raíz quitando cualquier marca diacrítica sin tener que enumerarlas.
3.3 Buscar un comodín literal
Si el texto contiene _ o % de verdad, hay que escaparlo con \:
SELECT
'lote_2024' LIKE '%\_%' AS busca_guion_bajo,
'lote 2024' LIKE '%\_%' AS con_espacio,
'lote 2024' LIKE '%_%' AS comodin;
busca_guion_bajo | con_espacio | comodin
------------------+-------------+---------
t | f | t
La tercera columna es la trampa: '%_%' no busca un guion bajo, busca "cualquier texto de al menos un carácter", así que es cierto para casi todo.
3.4 Cuando LIKE se queda corto: regex
Pregunta: ¿qué productos del catálogo empiezan por C o por B?
Con LIKE harían falta dos condiciones separadas por OR. Con regex, una sola clase de caracteres:
SELECT
product_name
FROM
products
WHERE
product_name ~ '^[CB]'
ORDER BY
product_name;
product_name
------------------------------
Boston Crab Meat
Camembert Pierrot
Carnarvon Tigers
Chai
Chang
Chartreuse verte
Chef Anton's Cajun Seasoning
Chef Anton's Gumbo Mix
Chocolade
Côte de Blaye
(10 filas)
10 productos de 77 empiezan por B o por C.
Pregunta: ¿y si además no importan las mayúsculas — qué productos empiezan por "ch" en cualquier combinación?
SELECT
product_name
FROM
products
WHERE
product_name ~* '^ch'
ORDER BY
product_name;
product_name
------------------------------
Chai
Chang
Chartreuse verte
Chef Anton's Cajun Seasoning
Chef Anton's Gumbo Mix
Chocolade
(6 filas)
Los mismos 6 de la lista anterior que empiezan por Ch, ni uno más — ~* es a ~ lo que ILIKE es a LIKE.
3.5 NOT LIKE y los nulos: no es un complemento real
Pregunta: ¿qué clientes alemanes tienen un fax que no sea de Berlín (código 030)?
Alemania tiene 11 clientes.
SELECT
company_name,
fax
FROM
customers
WHERE
country = 'Germany'
AND fax NOT LIKE '030%'
ORDER BY
company_name;
company_name | fax
--------------------------+--------------
Blauer See Delikatessen | 0621-08924
Die Wandernde Kuh | 0711-035428
Drachenblut Delikatessen | 0241-059428
Frankenversand | 089-0877451
Lehmanns Marktstand | 069-0245874
Ottilies Käseladen | 0221-0765721
Toms Spezialitäten | 0251-035695
(7 filas)
7, y parece razonable. Solo uno de los 11 tiene fax 030% (Alfreds Futterkiste), así que "los que no son de Berlín" debería ser el resto: 10. Faltan 3.
Los 3 que faltan son Königlich Essen, Morgenstern Gesundkost y QUICK-Stop — y no aparecen porque no tienen fax en absoluto. Aquí está la trampa: es fácil asumir que "no contiene 030" ya cubre a los que no tienen nada que contener — total, si no hay fax, mal puede empezar por 030. Pero para el motor no es así: NULL NOT LIKE '030%' no evalúa a TRUE, evalúa a UNKNOWN, y el WHERE lo descarta igual que si hubiera dado FALSE. La consulta no dice "estos 3 no calificaron"; simplemente los hace desaparecer.
Si el objetivo real incluye a los que no tienen fax —tiene sentido, porque no tener fax también significa "no es de Berlín"—, hay que decirlo explícitamente:
SELECT
company_name,
fax
FROM
customers
WHERE
country = 'Germany'
AND (fax NOT LIKE '030%' OR fax IS NULL)
ORDER BY
company_name;
company_name | fax
--------------------------+--------------
Blauer See Delikatessen | 0621-08924
Die Wandernde Kuh | 0711-035428
Drachenblut Delikatessen | 0241-059428
Frankenversand | 089-0877451
Königlich Essen |
Lehmanns Marktstand | 069-0245874
Morgenstern Gesundkost |
Ottilies Käseladen | 0221-0765721
QUICK-Stop |
Toms Spezialitäten | 0251-035695
(10 filas)
Regla: NOT LIKE (igual que <>) nunca es un verdadero complemento de LIKE cuando la columna admite nulos — deja fuera lo que no cumple y lo que no se pudo evaluar, sin distinguir entre ambos. Si quieres el complemento real, súmale OR columna IS NULL a propósito. Más sobre por qué pasa esto en null-y-la-logica-de-tres-valores.
4. Errores comunes
- Usar
=con comodines.WHERE nombre = 'A%'busca el texto literalA%. No da error; devuelve cero filas. - Olvidar que
LIKEdistingue mayúsculas. Ver el caso deAlfreds Futterkiste. - Olvidar los acentos. Igual de silencioso.
- Creer que
_significa guion bajo. Significa un carácter cualquiera. - Poner
%al principio y esperar velocidad.LIKE 'A%'puede usar un índice;LIKE '%A%'no puede, obliga a leer la tabla entera. Con 91 clientes da igual; con 20 millones, no. La solución en ese caso es un índicepg_trgm— ver indices. - Aplicar
LIKEa una columna con nulos y esperar el complemento.NOT LIKEdeja fuera losNULL, igual que<>. Ver § 3.5.
5. Diferencias con SQL Server
Esta es la sección más útil del tema, porque es donde más se separan los dos motores.
| Necesidad | SQL Server | PostgreSQL |
|---|---|---|
| Empieza por A | LIKE 'A%' |
LIKE 'A%' — igual |
| Ignorar mayúsculas | Automático (según collation) | ILIKE, explícito |
| Un carácter de un conjunto | LIKE '[CB]%' |
❌ No existe en LIKE → ~ '^[CB]' |
| Un carácter fuera del conjunto | LIKE '[^CB]%' |
❌ → ~ '^[^CB]' |
| Un rango | LIKE '[A-M]%' |
❌ → ~ '^[A-M]' |
| Regex completa | No hay operador nativo | ~, ~*, !~ |
Los corchetes de LIKE son una extensión de SQL Server, no del estándar SQL. En PostgreSQL, LIKE '[CB]%' no da error: busca literalmente un texto que empiece por el carácter [. Devuelve cero filas y no avisa. Es exactamente el tipo de consulta que se copia de un curso de SQL Server, parece funcionar y no funciona.
SIMILAR TO sí acepta corchetes y es la traducción literal:
SELECT
product_name
FROM
products
WHERE
product_name SIMILAR TO '[CB]%'
ORDER BY
product_name;
Da los mismos 10 productos que ~ '^[CB]'. Aun así, usa la regex: SIMILAR TO es un híbrido raro (comodines de LIKE + sintaxis de regex) que casi nadie lee bien, y la propia documentación de PostgreSQL desaconseja su uso.
6. Ejercicios
- Clientes cuyo nombre de empresa termina en
s. - Productos que contienen la palabra
ChocoladeoChocolate, sin importar mayúsculas. ¿Cuántos hay de cada uno? - Empleados cuyo cargo (
title) contieneSales. Lista su nombre completo y su cargo. - Traduce a PostgreSQL esta consulta de SQL Server, que busca clientes cuya ciudad empieza por una letra entre la A y la C:
sql SELECT * FROM customers WHERE city LIKE '[A-C]%'; - Clientes cuyo código postal es exactamente de 5 caracteres. Hazlo con
LIKEy luego con regex, y di cuál prefieres.
7. Pregunta de negocio
Marketing quiere lanzar una campaña a los clientes "de tipo restaurante o comida": cualquiera cuyo nombre de empresa sugiera que está en hostelería. Te piden la lista.
No hay una columna que diga "sector". Hay que fabricarla desde el texto — y decir en qué no te fías.