Algoritmo de Merge con Delete
En ciertas ocasiones debemos actualizar un conjunto de datos de tal forma que queden idénticos al resultado de una query. Como requisito adicional, tanto los datos de la query origen como la tabla destino tienen un mismo conjunto de columnas que podría ser considerada llave primaria, es decir, que no tienen valores nulos y que no producen registros duplicados.
El siguiente es un algoritmo genérico de MERGE-DELETE escrito en PL/SQL:
Por ejemplo: hay una tabla con transacciones diarias y es posible que después de cargar las transacciones haya que reprocesar los datos por algún motivo en particular. En este ejemplo, es claro que no existe la alternativa de truncar la tabla original y cargar los datos a partir de la tabla de paso ya que no solo se estarían truncando los registros que se van a cargar sino que también se truncarían los registros de otros días.
Otro ejemplo: una tabla debe ser refrescada todos los días. Algunos registros son nuevos, otros se mantienen y otros desaparecen. De los que se mantienen, una gran mayoría queda intacto y unos pocos cambian de valores en algunas columnas.
Las alternativas para implementar este tipo de requerimientos son:
- DELETE-INSERT: eliminar el conjunto de datos en la tabla destino y agregar los datos desde la query. (Tiene una gran carga escritura en redolog y segmentos de undo)
- MERGE: usar la sentencia merge de Oracle y luego eliminar los registros que no tengan relación con los registros de la query. (Obliga a recorrer la query origen y tabla destino 2 veces).
- Algoritmo de MERGE-DELETE: hacer un recorrido ordenado por el conjunto de columnas que forman la llave primaria teoríca tanto de la query origen como de la tabla destino e ir eliminando, insertando y actualizando registros según corresponda. (Recorre una sola vez la vez la query origen y tabla destino)
El siguiente es un algoritmo genérico de MERGE-DELETE escrito en PL/SQL:
select ...
from ...
...
order by (columnas equivalentes a la primaria de la tabla destino);
cursor CurDestino is
select d.rowid, ...
from TablaDestino d ...
...
order by (columnas de la primaria de la tabla destino);
RegOrigen CurOrigen%rowtype;
RegDestino CurDestino%rowtype;
ClaveOrigen varchar2(4000);
ClaveDestino varchar2(4000);
begin
open CurOrigen;
open CurDestino;
fetch CurOrigen into RegOrigen;
fetch CurDestino into RegDestino;
While (CurOrigen%found or CurDestino%found) loop
if CurOrigen%found then
ClaveOrigen:=(concatenado de las columnas de la clave primaria obtenido del cursor origen);
end if;
if CurDestino%found then
ClaveDestino:=(concatenado de las columnas de la clave primaria obtenido del cursor Destino);
end if;
if CurOrigen%found and CurDestino%found and ClaveOrigen = ClaveDestino then
if RegOrigen.columna1 <> RegDestino.columna1
or RegOrigen.columna2 <> RegDestino.columna2
... then
update TablaDestino
set columna1=RegOrigen.columna1, columna2=RegOrigen.columna2
...
where rowid = RegDestino.rowid;
end if;
fetch CurOrigen into RegOrigen;
fetch CurDestino into RegDestino;
elsif CurOrigen%found and (CurDestino%notfound or ClaveOrigen < ClaveDestino) then
insert into TablaDestino (columna1, columna2, ...)
values (RegOrigen.columna1, RegOrigen.columna2, ...);
fetch CurOrigen into RegOrigen;
else
delete from TablaDestino
where rowid = RegDestino.rowid;
fetch CurDestino into RegDestino;
end if;
end loop;
close CurOrigen;
close CurDestino;
commit;
end;
Comentarios
Publicar un comentario