Comparar tablas
Comparar los datos entre dos tablas es una necesidad habitual: verificar que una migración fue completa, encontrar diferencias entre un entorno de producción y uno de pruebas, o detectar registros que existen en una tabla pero no en otra. MySQL no tiene un operador EXCEPT o MINUS como otros motores de bases de datos, pero hay varias técnicas efectivas para lograr el mismo resultado.
Encontrar filas que están en una tabla pero no en otra
La técnica más común usa LEFT JOIN con una condición IS NULL para encontrar registros huérfanos:
-- Productos que están en la tabla origen pero no en destino
SELECT o.*
FROM productos_origen o
LEFT JOIN productos_destino d ON o.id = d.id
WHERE d.id IS NULL;| id | nombre | precio |
|---|---|---|
| 45 | Auriculares Bluetooth | 89.99 |
| 78 | Funda tablet 10" | 24.99 |
| 112 | Cable HDMI 2.1 | 15.99 |
Estos son los productos que existen en productos_origen pero faltan en productos_destino. El LEFT JOIN incluye todas las filas de la tabla izquierda, y cuando no hay correspondencia en la derecha, las columnas de la derecha son NULL.
Para encontrar las diferencias en ambas direcciones:
-- Filas que solo están en la tabla origen
SELECT 'solo en origen' AS ubicacion, o.id, o.nombre
FROM productos_origen o
LEFT JOIN productos_destino d ON o.id = d.id
WHERE d.id IS NULL
UNION ALL
-- Filas que solo están en la tabla destino
SELECT 'solo en destino', d.id, d.nombre
FROM productos_destino d
LEFT JOIN productos_origen o ON d.id = o.id
WHERE o.id IS NULL;| ubicacion | id | nombre |
|---|---|---|
| solo en origen | 45 | Auriculares Bluetooth |
| solo en origen | 78 | Funda tablet 10" |
| solo en destino | 203 | Cargador inalámbrico |
Comparar con NOT EXISTS
Una alternativa a LEFT JOIN que puede ser más legible:
SELECT *
FROM productos_origen o
WHERE NOT EXISTS (
SELECT 1
FROM productos_destino d
WHERE d.id = o.id
);El resultado es idéntico al LEFT JOIN ... IS NULL, y en la mayoría de los casos el rendimiento también es equivalente. MySQL suele optimizar ambas formas al mismo plan de ejecución.
Encontrar filas con datos diferentes
Cuando ambas tablas tienen los mismos registros pero con valores distintos en algunas columnas:
SELECT
o.id,
o.nombre AS nombre_origen,
d.nombre AS nombre_destino,
o.precio AS precio_origen,
d.precio AS precio_destino
FROM productos_origen o
JOIN productos_destino d ON o.id = d.id
WHERE o.nombre != d.nombre
OR o.precio != d.precio
OR o.stock != d.stock;| id | nombre_origen | nombre_destino | precio_origen | precio_destino |
|---|---|---|---|---|
| 3 | Google Pixel 8 | Google Pixel 8 Pro | 699.00 | 899.00 |
| 15 | Camiseta algodón | Camiseta algodón básica | 24.99 | 24.99 |
Este enfoque muestra lado a lado los valores que difieren, lo que facilita identificar exactamente qué cambió.
Manejar valores NULL en la comparación
El operador != no funciona con NULL porque NULL != NULL devuelve NULL, no TRUE. Usa el operador null-safe <=> o COALESCE:
SELECT o.id, o.nombre
FROM productos_origen o
JOIN productos_destino d ON o.id = d.id
WHERE NOT (o.nombre <=> d.nombre)
OR NOT (o.precio <=> d.precio)
OR NOT (o.descripcion <=> d.descripcion);El operador <=> devuelve TRUE cuando ambos valores son iguales o ambos son NULL, y FALSE en cualquier otro caso. Negarlo con NOT detecta cualquier diferencia, incluyendo cambios de NULL a un valor o viceversa.
Comparar conteos rápidamente
Para una verificación rápida de alto nivel, compara los conteos de filas:
SELECT
'origen' AS tabla,
COUNT(*) AS total_filas
FROM productos_origen
UNION ALL
SELECT
'destino',
COUNT(*)
FROM productos_destino;| tabla | total_filas |
|---|---|
| origen | 150 |
| destino | 147 |
Si los conteos difieren, sabes inmediatamente que hay diferencias. Si son iguales, todavía podrían haber diferencias en los valores individuales.
Comparar usando CHECKSUM TABLE
Para una verificación rápida de integridad, MySQL ofrece CHECKSUM TABLE:
CHECKSUM TABLE productos_origen;
CHECKSUM TABLE productos_destino;| Table | Checksum |
|---|---|
| tienda_mysql.productos_origen | 2345678901 |
| Table | Checksum |
|---|---|
| tienda_mysql.productos_destino | 2345678901 |
Si los checksums coinciden, las tablas son idénticas. Si difieren, hay al menos una diferencia. El checksum no te dice cuál es la diferencia, pero es una forma rápida de confirmar que dos tablas son iguales.
Comparar tablas en servidores diferentes
Cuando las tablas están en servidores diferentes, no puedes hacer un JOIN directo. Usa mysqldump con --skip-extended-insert para generar archivos comparables:
# Exportar ambas tablas con formato comparable
mysqldump --skip-extended-insert --compact --no-create-info \
-h servidor1 -u admin -p tienda_mysql productos | sort > /tmp/tabla1.sql
mysqldump --skip-extended-insert --compact --no-create-info \
-h servidor2 -u admin -p tienda_mysql productos | sort > /tmp/tabla2.sql
# Comparar con diff
diff /tmp/tabla1.sql /tmp/tabla2.sqlEl flag --skip-extended-insert genera una sentencia INSERT por fila, lo que hace que diff pueda identificar exactamente qué filas difieren. El sort ordena las líneas para que la comparación no se vea afectada por diferencias en el orden de exportación.
Resumen comparativo de técnicas
| Técnica | Detecta faltantes | Detecta diferencias | Maneja NULL | Rendimiento |
|---|---|---|---|---|
| LEFT JOIN ... IS NULL | Si | No | Si | Bueno |
| NOT EXISTS | Si | No | Si | Bueno |
| JOIN + WHERE != | No | Si | Necesita <=> | Bueno |
| CHECKSUM TABLE | Solo igualdad total | Solo igualdad total | Si | Excelente |
| mysqldump + diff | Si | Si | Si | Lento |
La combinación adecuada depende de tu escenario. Para verificaciones rápidas, CHECKSUM TABLE es ideal. Para análisis detallados de diferencias, combina la búsqueda de filas faltantes con la comparación de valores modificados.
Escrito por Eduardo Lázaro
