Uso básico de la instrucción MERGE en Oracle

La instrucción MERGE en Oracle permite combinar operaciones de inserción y actualización en una sola sentencia SQL, basándose en cnodiciones de coincidencia. Es particularmente útil para sincronizar datos entre tablas durante migraciones o inicializaciones.

Ejemplo básico donde se insertan registros de una tabla origen en una tabla destino cuando no existe coincidencia en el identificador de departamento:

MERGE INTO TABLA_DESTINO TD
USING (SELECT * FROM TABLA_ORIGEN) TO
ON (TD.ID_DEPARTAMENTO = TO.ID_DEPART)
WHEN NOT MATCHED THEN
INSERT (
    TD.ID_DEPARTAMENTO,
    TD.NOMBRE_DEPT,
    TD.UBICACION
) VALUES (
    TO.ID_DEPART,
    TO.NOMBRE,
    TO.LOCALIDAD
)

En un caso real de inicialización de datos para una tabla de información de alquileres, se utilizó MERGE para cargar aproximadamente 400,000 registros desde una tabla temporal. La estructura incluía transformación de fechas y validaciones de campos. Inicialmante, el código presentaba un errer ORA-02064 relacionado con operaciones distribuidas al usar un DB_LINK.

El primer intento de código generaba el error mencionado al intentar realizar una inserción directa sin manejar la transacción distribuida:

MERGE INTO INFO_ALQUILER IA
USING (
  SELECT RES.*,
         TO_DATE(SUBSTR(RES.FECHA_REG, 1, 4) || '-' || SUBSTR(RES.FECHA_REG, 5, 2) || '-' ||
                 SUBSTR(RES.FECHA_REG, 7, 2),
                 'yyyy-MM-dd') AS INICIO_ALQUILER,
         TO_DATE(SUBSTR(RES.FECHA_CREACION, 1, 4) || '-' || SUBSTR(RES.FECHA_CREACION, 5, 2) || '-' ||
                 SUBSTR(RES.FECHA_CREACION, 7, 2),
                 'yyyy-MM-dd') AS FECHA_CREAR
    FROM RESIDENTES_TEMPORALES RES
   WHERE RES.ESTADO = '0'
     AND SUBSTR(RES.FECHA_REG, 5, 2) BETWEEN 1 AND 12
) ORIG
ON (IA.ID_PERSONA = ORIG.ID_DOCUMENTO)
WHEN NOT MATCHED THEN
INSERT(
    IA.ID_INFO, IA.COD_MUNICIPIO, IA.COD_POLICIA, IA.ZONA, IA.CALLE, IA.TIPO_PROPIEDAD,
    IA.DIRECCION, IA.ESTADO_ALQUILER, IA.TIPO_VIVIENDA, IA.ESTRUCTURA, IA.NUM_HABITACIONES, IA.AREA,
    IA.INICIO_ALQUILER, IA.FIN_ALQUILER, IA.NOMBRE_INQUILINO, IA.TELEFONO, IA.DIRECCION_RESPONSABLE,
    IA.OBSERVACIONES, IA.ELIMINADO, IA.FECHA_CREAR, IA.DEPARTAMENTO_CREACION, IA.USUARIO_CREACION,
    IA.FECHA_ACTUALIZACION, IA.DEPARTAMENTO_ACTUALIZACION, IA.USUARIO_ACTUALIZACION, IA.ID_PERSONA
)
VALUES(
    SECUENCIA_INFO_ALQUILER.NEXTVAL,
    ORIG.COD_MUNICIPIO, ORIG.COD_POLICIA, ORIG.ZONA, ORIG.CALLE, ORIG.TIPO_PROPIEDAD,
    ORIG.DIRECCION, ORIG.ESTADO, ORIG.TIPO_VIVIENDA, ORIG.ESTRUCTURA, ORIG.NUM_HABITACIONES, ORIG.AREA,
    ORIG.INICIO_ALQUILER, NULL, ORIG.NOMBRE_INQUILINO, ORIG.TELEFONO, ORIG.DIRECCION_RESPONSABLE,
    NULL, '0', ORIG.FECHA_CREAR, ORIG.COD_POLICIA, NULL, NULL, NULL, NULL, ORIG.ID_DOCUMENTO
);

Para resolver el error ORA-02064, se modificó la sintaxis para incluir explícitamente una cláusula de actualización, incluso si no se pretendía modificar datos existentes. Se añadió un campo irrelevante en la sección WHEN MATCHED para cumplir con la estructura requerida. Esto evita el problema de transacciones distribuidas en Oracle 10g cuando se trabaja con enlaces de base de datos.

MERGE INTO INFO_ALQUILER IA
USING (
  SELECT RES.*,
         TO_DATE(SUBSTR(RES.FECHA_REG, 1, 4) || '-' || SUBSTR(RES.FECHA_REG, 5, 2) || '-' ||
                 SUBSTR(RES.FECHA_REG, 7, 2),
                 'yyyy-MM-dd') AS INICIO_ALQUILER,
         TO_DATE(SUBSTR(RES.FECHA_CREACION, 1, 4) || '-' || SUBSTR(RES.FECHA_CREACION, 5, 2) || '-' ||
                 SUBSTR(RES.FECHA_CREACION, 7, 2),
                 'yyyy-MM-dd') AS FECHA_CREAR
    FROM RESIDENTES_TEMPORALES RES
   WHERE RES.ESTADO = '0'
     AND SUBSTR(RES.FECHA_REG, 5, 2) BETWEEN 1 AND 12
) ORIG
ON (IA.ID_PERSONA = ORIG.ID_DOCUMENTO)
WHEN MATCHED THEN
     UPDATE SET IA.COD_MUNICIPIO = ORIG.COD_MUNICIPIO
WHEN NOT MATCHED THEN
INSERT(
    IA.ID_INFO, IA.COD_MUNICIPIO, IA.COD_POLICIA, IA.ZONA, IA.CALLE, IA.TIPO_PROPIEDAD,
    IA.DIRECCION, IA.ESTADO_ALQUILER, IA.TIPO_VIVIENDA, IA.ESTRUCTURA, IA.NUM_HABITACIONES, IA.AREA,
    IA.INICIO_ALQUILER, IA.FIN_ALQUILER, IA.NOMBRE_INQUILINO, IA.TELEFONO, IA.DIRECCION_RESPONSABLE,
    IA.OBSERVACIONES, IA.ELIMINADO, IA.FECHA_CREAR, IA.DEPARTAMENTO_CREACION, IA.USUARIO_CREACION,
    IA.FECHA_ACTUALIZACION, IA.DEPARTAMENTO_ACTUALIZACION, IA.USUARIO_ACTUALIZACION, IA.ID_PERSONA
)
VALUES(
    SECUENCIA_INFO_ALQUILER.NEXTVAL,
    ORIG.COD_MUNICIPIO, ORIG.COD_POLICIA, ORIG.ZONA, ORIG.CALLE, ORIG.TIPO_PROPIEDAD,
    ORIG.DIRECCION, ORIG.ESTADO, ORIG.TIPO_VIVIENDA, ORIG.ESTRUCTURA, ORIG.NUM_HABITACIONES, ORIG.AREA,
    ORIG.INICIO_ALQUILER, NULL, ORIG.NOMBRE_INQUILINO, ORIG.TELEFONO, ORIG.DIRECCION_RESPONSABLE,
    NULL, '0', ORIG.FECHA_CREAR, ORIG.COD_POLICIA, NULL, NULL, NULL, NULL, ORIG.ID_DOCUMENTO
);

Referencia técnica: Documentación oficial de Oracle sobre la instrucción MERGE.

Etiquetas: Oracle SQL MERGE Transacciones Distribuidas enlaces de base de datos

Publicado el 6-26 01:07