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. La tercera opción, desde que la versión 11g R2 de Oracle ya no acepta el hint BYPASS_UJVC por considerarlo Deprecated, es ya totalmente desaconsejable para entornos de producción porque aunque ahora funcione por ser versiones anteriores a la 11g, las queries que incorporen este hint fallarán cuando se actualice la base de datos a una versión a partir de la 11g R2.

Otra buena opción para evitar el error ORA-30926 en operaciones de MERGE es modificar la sentencia aplicando un distinct para evitar los duplicados, o utilizando un group by y una función de agregación Min, Max o Sum, por ejemplo, sobre los campos que contengan los valores duplicados.