Saltar al contenido

DBMS_FLASHBACK: Recuperar tablas y registros en Oracle

¿Quién no ha borrado unos registros sin darse cuenta?  ¿O una tabla?  ¿O necesita recuperar los registros que había en una fecha determinada?

Antes de la versión Oracle 10g la única manera de recuperarlos era con el paquete DBMS_FLASHBACK , os lo describo más abajo superficialmente,  pero ahora podemos realizarlo de una manera más sencilla con FLASHBACK  TABLE.

FLASHBACK TABLE

Cuando borramos un objeto este se encuentra en la vista recyclebin. Lo que hace Oracle es renombrar el objeto borrado y todos los objetos dependientes,  tales como vistas, triggers, índices, constraints etc., usando el prefijo BIN$:

select  * from recyclebin

Todos los objetos que están en esa vista pueden ser consultados, pero con las mismas restricciones que tenían antes de ser borrados, poniendo su nombre entre comillas.
PERO NO SE PUEDEN MODIFICAR.

–  Para recuperar tablas completas:

Si ahora borramos una tabla, podremos recuperarla de los siguientes modos:

drop table PRUEBA;

select OBJECT_NAME , ORIGINAL_NAME, DROPTIME from recyclebin;

OBJECT_NAME                                         ORIGINAL_NAME         DROPTIME

BIN$fPZ1v/pMHx3gRAADusQZ7Q==$0     PRUEBA                       2010-01-12:10:53:11

1. Haciendo un create select  tabla as select :

SQL> create table prueba_nueva as select * from “BIN$fPZ1v/pMHx3gRAADusQZ7Q==$0″;

El nombre de la tabla borrada siempre irá entre comillas.

2. Creando la tabla (CREATE TABLE) y después rellenarla usando INSERT INTO nombre_tabla AS SELECT * FROM nombre_tabla_borrada.

SQL> Insert into prueba_nueva select * from “BIN$fPZ1v/pMHx3gRAADusQZ7Q==$0″;

3. Para recuperar un objeto borrado se puede usar  el comando FLASHBACK TABLE.

De esta manera podemos restaurar la tabla PRUEBA borrada con el mismo nombre que tenía antes.

SQL> flashback table PRUEBA to before drop;

Flashback terminado.

Si existiese ya una tabla con el nombre PRUEBA obtendríamos el error ORA-38312: el nombre original lo ha utilizado un objeto existente).  En este caso usaríamos la cláusula vista anteriormente RENAME TO nuevo_nombre.

También tenemos la opción de  recuperar la tabla en un momento determinado:

SQL>  FLASHBACK TABLE PRUEBA  TO TIMESTAMP (SYSTIMESTAMP – INTERVAL ‘1′ minute);

– Para recuperar registros específicos de una tabla en un momento determinado.

SQL> INSERT INTO PRUEBA ( SELECT * FROM PRUEBA AS OF TIMESTAMP TO_TIMESTAMP(’2010-01-21 09:30:00′, ‘YYYY-MM-DD HH:MI:SS’));

Unas cosillas a tener en cuenta:


– Esta sentencia da el tiempo dentro del cual podemos realizar un flashback o retroceder en el tiempo:
SELECT NAME, VALUE/60 MINUTES_RETAINED FROM V$PARAMETER WHERE NAME = ‘undo_retention’;
– Si en el Recycle Bin tenemos más de una versión de la tabla, tenemos que usar para recuperarla el nombre generado por Oracle (BIN$). Si no lo hacemos recuperará la última versión existente.
– Cuando recuperamos una tabla desde el Recycle Bin, se renombra automáticamente con su nombre original, pero los objetos asociados como los índices, constraints o triggers cuando son restaurados sus nombres originales no se recuperan, lo que significa que siguen siendo de la forma BIN$.

– Olvidaos de recuperar algo de la recyclebin si habéis borrado añadiendo el comando PURGE.

DBMS_FLASHBACK PACKAGE.

Es un paquete bastante extenso, pero para recuperar los datos que necesitamos con esto nos bastarán dos cosillas:

drop table t1;    /*Borramos la tabla t1.*/

Con este paquete podemos retroceder en el tiempo la BBDD a un momento determinado:

EXECUTE DBMS_FLASHBACK.ENABLE_AT_TIME(TO_TIMESTAMP(’12-02-2001 14:35:00′, ‘DD-MM-YYYY HH24:MI:SS’))
SELECT * FROM T1;
EXECUTE dbms_flashback.disable;   Acordaos de dejarla como estaba!!!!!

Con estas dos sentencias podríamos generar  un cursor para recuperar los datos de una tabla:

DECLARE
CURSOR C1 IS SELECT * FROM T1;
CUR_FLASH T1%ROWTYPE;
BEGIN
DBMS_FLASHBACK.ENABLE_AT_TIME(SYSDATE – 15/1440);
OPEN C1;
DBMS_FLASHBACK.DISABLE;
LOOP
FETCH C1 INTO CUR_FLASH;
EXIT WHEN C1%NOTFOUND;
INSERT INTO T1_NUEVA VALUES CUR_FLASH;  /*No podemos realizar esto si antes no desactivamos el FLASHBACK*/
END LOOP;
IF C1%ISOPEN THEN
CLOSE C1;
END IF;
COMMIT;
END;