IN

El operador IN comprueba si un valor coincide con cualquiera de los valores de una lista. Es una forma concisa de escribir múltiples condiciones OR sobre la misma columna.

Sintaxis

SELECT columnas
FROM tabla
WHERE columna IN (valor1, valor2, valor3, ...);

La lista de valores va entre paréntesis, separados por comas. Si el valor de la columna coincide con alguno de los valores de la lista, la condición es verdadera y la fila se incluye en el resultado.

IN con valores numéricos

Para obtener los productos de las categorías Smartphones (6), Portátiles (7) y Accesorios electrónicos (8):

SELECT nombre, precio, categoria_id
FROM productos
WHERE categoria_id IN (6, 7, 8);
nombrepreciocategoria_id
iPhone 15 Pro1299.996
Samsung Galaxy S24899.996
Google Pixel 8699.006
Xiaomi 14599.996
MacBook Air M31399.007
Lenovo ThinkPad X11549.007
ASUS ROG Zephyrus1899.997
Funda iPhone silicona49.998
Cargador USB-C 65W35.998
Cable USB-C a Lightning19.998

Esto es equivalente a escribir WHERE categoria_id = 6 OR categoria_id = 7 OR categoria_id = 8, pero mucho más legible, especialmente cuando la lista tiene muchos valores.

IN con cadenas de texto

IN funciona también con cadenas. Para buscar clientes de tres ciudades concretas:

SELECT nombre, apellidos, ciudad
FROM clientes
WHERE ciudad IN ('Madrid', 'Barcelona', 'Sevilla');
nombreapellidosciudad
MaríaGarcía LópezMadrid
CarlosRodríguez MartínBarcelona
AnaMartínez RuizSevilla
PedroFernández CastroMadrid
LauraLópez SánchezBarcelona

Los valores de texto se comparan respetando la collation de la columna. Con la collation por defecto de MySQL (utf8mb4_0900_ai_ci), la comparación no distingue mayúsculas y minúsculas, así que 'madrid' y 'Madrid' se tratan como iguales.

IN con subconsultas

Una de las funcionalidades más potentes de IN es que la lista de valores puede venir de otra consulta. En lugar de escribir los valores a mano, usas una subconsulta que los genera dinámicamente:

SELECT nombre, precio
FROM productos
WHERE categoria_id IN (
    SELECT id
    FROM categorias
    WHERE categoria_padre_id = 1
);
nombreprecio
iPhone 15 Pro1299.99
Samsung Galaxy S24899.99
Google Pixel 8699.00
Xiaomi 14599.99
MacBook Air M31399.00
Lenovo ThinkPad X11549.00
ASUS ROG Zephyrus1899.99
Funda iPhone silicona49.99
Cargador USB-C 65W35.99
Cable USB-C a Lightning19.99

La subconsulta obtiene los IDs de las subcategorías de Electrónica (categoría padre 1), que son 6, 7 y 8. Después, la consulta principal filtra los productos que pertenecen a esas categorías. El resultado es el mismo que el primer ejemplo, pero esta vez no necesitamos conocer los IDs de antemano.

Otro ejemplo: productos que han aparecido en al menos un pedido:

SELECT DISTINCT nombre, precio
FROM productos
WHERE id IN (
    SELECT producto_id
    FROM detalle_pedidos
)
ORDER BY nombre;

La subconsulta devuelve los IDs de todos los productos que están en algún detalle de pedido. La consulta principal muestra solo esos productos.

IN con valores numéricos mixtos

IN acepta cualquier expresión, no solo constantes:

SELECT nombre, precio
FROM productos
WHERE precio IN (19.99, 29.99, 39.99, 49.99);
nombreprecio
Funda iPhone silicona49.99
Cable USB-C a Lightning19.99
Sartén antiadherente 28cm39.99
Esterilla yoga premium29.99
Banda elástica set x519.99
Clean Code39.99
Diseño de APIs29.99

Todos los productos que cuestan exactamente alguno de esos precios.

IN y NULL

Es importante entender cómo se comporta IN con valores NULL. Si la lista contiene un NULL, no afecta a las filas con valores no nulos, pero si el valor de la columna es NULL, el resultado es NULL (no verdadero):

SELECT nombre, telefono
FROM clientes
WHERE telefono IN ('612345678', NULL);
nombretelefono
María612345678

Solo aparece María (cuyo teléfono coincide con el valor de la lista). Los clientes con telefono = NULL no aparecen, porque NULL IN (...) devuelve NULL, no TRUE. Para incluir valores nulos necesitas IS NULL explícitamente:

WHERE telefono IN ('612345678') OR telefono IS NULL

Rendimiento de IN

Con listas pequeñas (decenas de valores), IN es muy eficiente. MySQL puede usar índices sobre la columna para evaluar la condición rápidamente.

Con subconsultas, el rendimiento depende de cómo MySQL optimice la consulta. En versiones modernas (8.0+), MySQL suele convertir las subconsultas de IN en semi-joins internamente, lo que las hace comparables en rendimiento a un JOIN explícito. En versiones muy antiguas, las subconsultas correlacionadas dentro de IN podían ser lentas.

Si la lista tiene miles de valores, considera usar una tabla temporal o un JOIN en lugar de un IN con una lista enorme.

IN vs OR

Estas dos consultas son equivalentes:

-- Con IN
WHERE estado IN ('pendiente', 'procesando', 'enviado')
 
-- Con OR
WHERE estado = 'pendiente'
   OR estado = 'procesando'
   OR estado = 'enviado'

IN es preferible por legibilidad cuando comparas la misma columna contra varios valores. OR es necesario cuando las condiciones involucran diferentes columnas o expresiones.

Practica con IN

Usa el editor para probar IN con distintas listas de valores. Intenta filtrar productos por categoría o pedidos por estado:

Simulador SQL
Ctrl+Enter para ejecutar

En el siguiente artículo veremos NOT IN, la negación de IN.

Escrito por Eduardo Lázaro