Comparando esquemas

En mi empresa, diseñamos la base de datos con designer y luego generamos el esquema en la base de datos.Siempre llega un punto del desarrollo en que es bastante incómodo borrar el esquema y volver a generarlo, sobretodo por volver a llenar las tablas. A partir de ese momento tratamos siempre de sincronizar lo que tenemos en designer con lo que vamos volcando en la bd. Sin embargo esta sincronización es… humana.

Lo que hacemos entonces es generar el esquema de designer en otro usuario en blanco y luego comparamos los dos esquemas, el de desarrollo y el de designer. Para facilitarme esta tarea me he creado un script de informe de tablas y otro de informe de constraints. El resto de objetos no me preocupan porque tanto vistas como triggers como paquetes y demás los tengo en ficheros de texto. Lo que hago es lanzar los informes para las dos versiones de la base de datos y compararlos con algún programilla tipo diff.

Éste es el script para el informe de tablas. Muestra para cada tabla del usuario conectado el nombre de la tabla, un nº que indica el orden del campo en la clave primaria (si el campo pertenece a la clave), el nombre del campo, el tipo de dato con precisión, si es opcional o no y si tiene algún valor por defecto.

/* Fichero: informe_tablas.sql
   http://www.tsoracle.com
*/
SET LINES  100
SET PAGES  20000
SET HEADING ON
SET VERIFY OFF
-------------------------
-- Definición de columnas
-------------------------
COLUMN TABLE_NAME     FORMAT A20
COLUMN CLAVE_PRIMARIA FORMAT A1
COLUMN COLUMN_NAME    FORMAT A20
COLUMN TIPO           FORMAT A15
COLUMN DEFECTO        FORMAT A15

----------
-- Selects
----------
BREAK ON TABLE_NAME
SELECT M.TABLE_NAME,
       P.PK CLAVE_PRIMARIA,
       M.COLUMN_NAME,
       M.DATA_TYPE || DECODE( M.DATA_TYPE,
                              /*************************************/
                              'DATE', NULL, -- Poner aquí los tipos
                              'LONG', NULL, -- de varible para los
                              'BLOB', NULL, -- que no queramos ver
                              'CLOB', NULL, -- la precisión
                              /*************************************/
                              '(' || TO_CHAR( NVL( M.DATA_PRECISION,
                                                   M.DATA_LENGTH))||
                              DECODE( M.DATA_SCALE, NULL, NULL,
                                      ',' ||
                                      TO_CHAR( M.DATA_SCALE ) ) ||
                              ')' ) TIPO,
       M.NULLABLE,
       M.DATA_DEFAULT DEFECTO
FROM   ( SELECT N.TABLE_NAME, L.COLUMN_NAME, L.POSITION PK
         FROM   USER_CONS_COLUMNS L, USER_CONSTRAINTS N
         WHERE  L.CONSTRAINT_NAME = N.CONSTRAINT_NAME
           AND  N.CONSTRAINT_TYPE = 'P' ) P, -- Clave primaria
       USER_TAB_COLUMNS M
WHERE  M.TABLE_NAME  = P.TABLE_NAME  (+)
  AND  M.COLUMN_NAME = P.COLUMN_NAME (+)
ORDER BY M.TABLE_NAME, M.COLUMN_NAME
/

Y este es el informe de constraints. Tiene tres secciones. La primera de foreign keys, donde sólo me interesa el nombre de las dos tablas implicadas. En mi caso puedo descartar la posibilidad de tener diferentes columnas en la FK. Y el nombre me da igual.
La segunda sección es para las check constraints. Como las check de no nulidad ya las contrasto en el informe de tablas, aquí solo me preocupo de la tabla sobre la que se define la CHK y la propia condición.
Por último tengo una sección de claves únicas. En este caso particular me interesa el orden de las columnas ya que me interesa que los índices basados en estas claves sean correctos.
Es bastante pesado de lanzar

/* Fichero: informe_con.sql
   http://www.tsoracle.com
*/
PROMPT CLAVES FORÁNEAS...
BREAK ON TABLE_NAME ON TABLA_FORANEA
SELECT A.TABLE_NAME, B.TABLE_NAME TABLA_FORANEA
FROM   USER_CONSTRAINTS A, USER_CONSTRAINTS B
WHERE  A.R_CONSTRAINT_NAME = B.CONSTRAINT_NAME
  AND  A.CONSTRAINT_TYPE   = 'R'
ORDER BY A.TABLE_NAME, B.TABLE_NAME
/
PROMPT ************************************************************
PROMPT CHECKS
SELECT TABLE_NAME, SEARCH_CONDITION
FROM   USER_CONSTRAINTS
WHERE  CONSTRAINT_TYPE = 'C'
   AND CONSTRAINT_NAME NOT LIKE 'SYS%'
ORDER BY TABLE_NAME, SEARCH_CONDITION
/
PROMPT ************************************************************
PROMPT CLAVES ÚNICAS
BREAK ON TABLE_NAME ON CONSTRAINT_NAME
SELECT A.TABLE_NAME, A.CONSTRAINT_NAME, C.COLUMN_NAME
FROM   USER_CONS_COLUMNS C, USER_CONSTRAINTS A
WHERE  A.CONSTRAINT_NAME   = C.CONSTRAINT_NAME
  AND  A.CONSTRAINT_TYPE   = 'U'
ORDER BY A.TABLE_NAME, A.CONSTRAINT_NAME, C.POSITION
/
Anuncios