Comparar la estructura de dos bases de datos
Una aplicación funciona en desarrollo, pero falla al desplegarse porque una columna tiene otra longitud, permite valores nulos o utiliza un tipo diferente en producción. Revisar las tablas una por una hace fácil pasar por alto una diferencia pequeña.
Qué necesitamos distinguir
El esquema es la definición estructural de los objetos de una base. En tipos numéricos, la precisión es la cantidad total de dígitos y la escala, los dígitos decimales; la nulabilidad indica si una columna admite NULL.
Compararemos columnas por esquema, tabla y nombre. El resultado separará columnas ausentes de definiciones diferentes y mostrará tipo, longitud, precisión, escala y nulabilidad.
Consulta
/*
Antes de ejecutar:
Revisa la base activa, los nombres de objetos, los parámetros y los permisos.
Adapta el ejemplo a tu modelo y pruébalo primero en un ambiente controlado.
*/
SET NOCOUNT ON;
GO
-- Consulta
WITH ColumnasOrigen AS
(
SELECT
s.name COLLATE DATABASE_DEFAULT AS Esquema,
t.name COLLATE DATABASE_DEFAULT AS Tabla,
c.name COLLATE DATABASE_DEFAULT AS Columna,
ty.name COLLATE DATABASE_DEFAULT AS Tipo,
c.max_length AS LongitudBytes,
c.precision AS Precision,
c.scale AS Escala,
c.is_nullable AS PermiteNulos
FROM BaseDesarrollo.sys.tables AS t
INNER JOIN BaseDesarrollo.sys.schemas AS s
ON s.schema_id = t.schema_id
INNER JOIN BaseDesarrollo.sys.columns AS c
ON c.object_id = t.object_id
INNER JOIN BaseDesarrollo.sys.types AS ty
ON ty.user_type_id = c.user_type_id
),
ColumnasDestino AS
(
SELECT
s.name COLLATE DATABASE_DEFAULT AS Esquema,
t.name COLLATE DATABASE_DEFAULT AS Tabla,
c.name COLLATE DATABASE_DEFAULT AS Columna,
ty.name COLLATE DATABASE_DEFAULT AS Tipo,
c.max_length AS LongitudBytes,
c.precision AS Precision,
c.scale AS Escala,
c.is_nullable AS PermiteNulos
FROM BaseProduccion.sys.tables AS t
INNER JOIN BaseProduccion.sys.schemas AS s
ON s.schema_id = t.schema_id
INNER JOIN BaseProduccion.sys.columns AS c
ON c.object_id = t.object_id
INNER JOIN BaseProduccion.sys.types AS ty
ON ty.user_type_id = c.user_type_id
)
SELECT
COALESCE(o.Esquema, d.Esquema) AS Esquema,
COALESCE(o.Tabla, d.Tabla) AS Tabla,
COALESCE(o.Columna, d.Columna) AS Columna,
CASE
WHEN o.Columna IS NULL THEN N'Solo en destino'
WHEN d.Columna IS NULL THEN N'Solo en origen'
ELSE N'Definición diferente'
END AS Diferencia,
o.Tipo AS TipoOrigen,
d.Tipo AS TipoDestino,
o.LongitudBytes AS LongitudOrigen,
d.LongitudBytes AS LongitudDestino,
o.Precision AS PrecisionOrigen,
d.Precision AS PrecisionDestino,
o.Escala AS EscalaOrigen,
d.Escala AS EscalaDestino,
o.PermiteNulos AS NulosOrigen,
d.PermiteNulos AS NulosDestino
FROM ColumnasOrigen AS o
FULL OUTER JOIN ColumnasDestino AS d
ON d.Esquema = o.Esquema
AND d.Tabla = o.Tabla
AND d.Columna = o.Columna
WHERE o.Columna IS NULL
OR d.Columna IS NULL
OR EXISTS
(
SELECT
o.Tipo, o.LongitudBytes, o.Precision,
o.Escala, o.PermiteNulos
EXCEPT
SELECT
d.Tipo, d.LongitudBytes, d.Precision,
d.Escala, d.PermiteNulos
)
ORDER BY
Esquema,
Tabla,
Columna;
GO
Parámetros o permisos
Sustituye BaseDesarrollo y BaseProduccion por bases de la misma instancia. Ejecuta la consulta desde una base cuya intercalación pueda utilizarse para comparar los nombres; COLLATE DATABASE_DEFAULT evita un conflicto común cuando las bases usan intercalaciones distintas. Se necesita visibilidad de metadatos en ambas bases. max_length se expresa en bytes: en nvarchar y nchar, salvo max, normalmente corresponde al doble del número de caracteres.
Cómo leer el resultado
EXCEPT compara proyecciones completas y devuelve las filas presentes en el primer conjunto pero no en el segundo.
Una columna presente en una sola base aparece como “Solo en origen” o “Solo en destino”. Si existe en ambas, se muestra únicamente cuando al menos una propiedad comparada cambia. EXCEPT permite comparar también valores nulos sin construir una condición separada por propiedad. Las columnas de ambos SELECT conservan el mismo orden y tipos compatibles. La consulta compara estructura de columnas, no datos. Tampoco intenta generar instrucciones ALTER; primero necesitamos decidir cuál definición es la esperada y qué impacto tendría modificarla.
Qué conclusión sí permite obtener
Permite localizar columnas faltantes y diferencias en las propiedades estructurales incluidas entre dos bases accesibles de la misma instancia.
Qué conclusión todavía no permite obtener
No compara IDENTITY, columnas calculadas, índices, llaves, restricciones, valores predeterminados, triggers, permisos ni código SQL. Los tipos definidos por el usuario también requieren revisar su esquema y definición, no solo el nombre mostrado.
Siguiente comprobación razonable
Clasifica cada diferencia como esperada o pendiente de despliegue. Después revisa dependencias, datos existentes y scripts de migración antes de proponer un cambio de estructura.