Oracle Database
Actualizar con uniones
Buscar..
Introducción
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.