Buscar..


Introducción

Contrariamente a los malentendidos generalizados (incluso en SO), Oracle permite actualizaciones a través de uniones. Sin embargo, hay algunos requisitos (bastante lógicos). Ilustramos lo que no funciona y lo que hace a través de un ejemplo simple. Otra forma de lograr lo mismo es la declaración MERGE.

Ejemplos: lo que funciona y lo que no.

create table tgt ( id, val ) as 
  select 1, 'a' from dual union all
  select 2, 'b' from dual
;

Table TGT created.

create table src ( id, val ) as 
  select 1, 'x' from dual union all
  select 2, 'y' from dual
;

Table SRC created.

update
  ( select t.val as t_val, s.val as s_val
    from   tgt t inner join src s on t.id = s.id
  )
set t_val = s_val
;

SQL Error: ORA-01779: cannot modify a column which maps to a non key-preserved table
01779. 00000 -  "cannot modify a column which maps to a non key-preserved table"
*Cause:    An attempt was made to insert or update columns of a join view which
           map to a non-key-preserved table.
*Action:   Modify the underlying base tables directly.

Imagine lo que sucedería si tuviéramos el valor 1 en la columna src.id más de una vez, con valores diferentes para src.val . Obviamente, la actualización no tendría sentido (en CUALQUIER base de datos, eso es un problema lógico). Ahora, sabemos que no hay duplicados en src.id , pero el motor de Oracle no sabe que - por lo que se queja. Quizás esta es la razón por la que tantos profesionales creen que Oracle "no tiene ACTUALIZACIÓN con uniones".

Lo que Oracle espera es que src.id sea ​​único y que, Oracle, lo sepa de antemano. ¡Fácilmente arreglado! Tenga en cuenta que lo mismo funciona con claves compuestas (en más de una columna), si la coincidencia para la actualización necesita usar más de una columna. En la práctica, src.id puede ser PK y tgt.id puede ser FK apuntando a esta PK, pero eso no es relevante para las actualizaciones con join; lo que es relevante es la restricción única.

alter table src add constraint src_uc unique (id);

Table SRC altered.

update
  ( select t.val as t_val, s.val as s_val
    from   tgt t inner join src s on t.id = s.id
  )
set t_val = s_val
;

2 rows updated.

select * from tgt;

ID  VAL
--  ---
 1  x
 2  y

El mismo resultado se podría lograr con una declaración MERGE (que merece su propio artículo de Documentación), y personalmente prefiero MERGE en estos casos, pero la razón no es que "Oracle no hace actualizaciones con las combinaciones". Como muestra este ejemplo, Oracle hace actualizaciones con uniones.



Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow