miércoles, 23 de marzo de 2011

El error ORA-30926 como resultado de una operación Merge

El error ORA-30926 suele producirse cuando se realizan operaciones Merge, y lo normal es que nos deje algo descolocados, ya que la descripción del mismo no da demasiada información sobre lo que está pasando:
ORA-30926: unable to get a stable set of rows in the source tables.
Normalmente este error se produce cuando en la operación Merge a una fila destino que hay que actualizar le corresponden más de una fila en la tabla origen. Como el motor no sabe qué registro escoger devuelve un error. Es un problema de duplicidad en la tabla origen.
Ejemplo:
  • Tenemos:
    TABLA_ORIGEN con los valores
    ID    Descripcion
    1     'El primer valor'
    1     'El valor con id duplicado'
    2     'Otro valor' Y TABLA_DESTINO con los valores
    ID   Descripcion
    1    'Valor a actualizar'
    2    'Este no dará problemas'
    3    'Este se queda igual'
     
  • Queremos hacer un merge utilizando la siguiente sentencia:
MERGE into TABLA_DESTINO dest
USING TABLA_ORIGEN ori
ON (dest.ID = ori.ID)
WHEN MATCHED THEN UPDATE SET a.Descripcion = b.Descripcion;
Con estos datos obtendríamos el siguiente error sobre TABLA_ORIGEN:
ORA-30926: no se ha podido obtener un juego de filas estable en las tablas de origen

  • Ante este error tenemos 3 opciones: 1-. Eliminar los registros duplicados de la tabla origen:
 DELETE FROM TABLA_ORIGEN WHERE id=1 AND Descripcion='El valor con id duplicado'
 
2-. Revisar las claves por las que hacemos la join en el merge:
Si utilizamos también el campo Descripcion en el enlace ya sólo habrá cero o un registro origen para cada destino:

MERGE into TABLA_DESTINO dest
USING TABLA_ORIGEN ori
ON (dest.ID = ori.ID AND
dest.Descripcion=ori.Descripcion)WHEN MATCHED THEN UPDATE SET a.Descripcion = b.Descripcion;
(En este ejemplo no tiene mucho sentido porque la tabla son sólo estos dos campos, y además la join no encontrará coincidencias)

3-. Utilizar en lugar del MERGE un UPDATE con JOIN y el HINT /*+BYPASS_UJVC */  para saltarnos la validación del motor, y cruzar los dedos:
UPDATE /*+ BYPASS_UJVC */
 ( SELECT ori.ID ori_ID,
                  ori.Descripcion ori_Descripcion,
                  dest.ID dest_ID,
                  dest.Descripcion dest_Descripcion
    FROM TABLA_ORIGEN ori, TABLA_DESTINO dest
    WHERE ori.ID = dest.ID)
SET dest_Descripcion = ori_Descripcion;

Obviamente las más recomendables son la primera o la segunda, según el caso.

No hay comentarios:

Publicar un comentario