Flashback
Flashback is Oracle's set of features for recovering and querying past states of your data — without restoring from backup. You can drop a table by mistake and bring it back in seconds; you can query a table "as it looked yesterday at 3 PM"; you can audit who changed what and when.
These features use the database's existing undo and redo data, so they work on data that's already in the database — they're not a substitute for backups, but they're a much faster recovery path for many common mistakes.
The Flashback Family
Oracle ships several Flashback features that solve different problems:
| Feature | Purpose | Granularity |
|---|---|---|
| Flashback Drop (recycle bin) | Undo a DROP TABLE |
Whole table |
| Flashback Query | See data as of a past time / SCN | Per-query (read-only) |
| Flashback Version Query | See all versions of rows between two points | Per-query, multi-version |
| Flashback Transaction Query | Audit which transaction changed which rows | Per-transaction |
| Flashback Table | Rewind a table to a past state | Whole table (writes) |
| Flashback Database | Rewind the entire database | Database-wide (DBA only) |
| Flashback Data Archive | Retain history beyond undo retention | Per-table, configurable |
The first five work with existing undo data and have practical limits (undo retention is usually hours, not days). Flashback Data Archive is the long-term option for tables that need compliance-grade history.
Part 1 — Flashback Drop and the Recycle Bin
What Happens When You DROP TABLE
When you run DROP TABLE employees, Oracle does not immediately delete the table. By default it renames the table and moves it into your recycle bin. The space is freed for reuse but the data is recoverable.
-- Drop a table
DROP TABLE old_employees;
-- See what's in the recycle bin
SELECT object_name, original_name, type, droptime
FROM recyclebin;
Result:
| object_name | original_name | type | droptime |
|---|---|---|---|
| BIN$NyP0kZ4...gZA==$0 | OLD_EMPLOYEES | TABLE | 2024-03-15:14:22:01 |
The renamed object lives in the recycle bin until it's purged or until Oracle reclaims its space for new data.
Recovering with FLASHBACK TABLE ... TO BEFORE DROP
FLASHBACK TABLE old_employees TO BEFORE DROP;
The table reappears with its original name and data. If you need a different name:
FLASHBACK TABLE old_employees TO BEFORE DROP RENAME TO old_emp_recovered;
If multiple objects with the same original name exist (you dropped and recreated the table several times), use the bin name explicitly:
FLASHBACK TABLE "BIN$NyP0kZ4...gZA==$0" TO BEFORE DROP;
Purging the Recycle Bin
-- Permanently delete a specific dropped table (irrecoverable)
PURGE TABLE old_employees;
-- Empty your entire recycle bin
PURGE RECYCLEBIN;
-- DBA: purge the system-wide recycle bin
PURGE DBA_RECYCLEBIN;
To bypass the recycle bin and drop a table immediately:
DROP TABLE old_employees PURGE;
Limitations
Flashback Drop has limits:
- Only works on non-SYS tables in a locally-managed tablespace
- Doesn't recover tables dropped with
PURGE - Doesn't preserve foreign keys (you must recreate them)
- Indexes and triggers come back, but bitmap join indexes do not
Part 2 — Flashback Query
Querying the Past
The AS OF clause queries a table at a specific point in the past:
-- See employees as they existed an hour ago
SELECT employee_id, first_name, salary
FROM employees
AS OF TIMESTAMP SYSTIMESTAMP - INTERVAL '1' HOUR;
You can use a TIMESTAMP (wall-clock time) or an SCN (system change number — Oracle's internal monotonic time):
-- By SCN
AS OF SCN 1234567
-- By specific timestamp
AS OF TIMESTAMP TO_TIMESTAMP('2024-03-15 14:00:00', 'YYYY-MM-DD HH24:MI:SS')
-- Relative
AS OF TIMESTAMP SYSTIMESTAMP - INTERVAL '30' MINUTE
Comparing Past and Present
Combine a flashback query with the current state to see what changed:
-- Rows that have been deleted in the past hour
SELECT * FROM employees AS OF TIMESTAMP SYSTIMESTAMP - INTERVAL '1' HOUR
MINUS
SELECT * FROM employees;
-- Rows where salary changed in the past hour
SELECT old.employee_id,
old.salary AS old_salary,
cur.salary AS new_salary
FROM employees AS OF TIMESTAMP SYSTIMESTAMP - INTERVAL '1' HOUR old
JOIN employees cur ON old.employee_id = cur.employee_id
WHERE old.salary <> cur.salary;
Recovering Deleted Data
When someone accidentally deletes rows, flashback query is often the fastest recovery:
-- 1. Identify the deleted rows
SELECT * FROM employees AS OF TIMESTAMP SYSTIMESTAMP - INTERVAL '15' MINUTE
MINUS
SELECT * FROM employees;
-- 2. Re-insert them
INSERT INTO employees
SELECT * FROM employees AS OF TIMESTAMP SYSTIMESTAMP - INTERVAL '15' MINUTE
MINUS
SELECT * FROM employees;
This recovers all rows that existed 15 minutes ago but no longer exist now. Much faster than restoring from backup.
How Far Back Can You Go?
Flashback Query depends on undo retention — how long Oracle keeps undo data. The DBA configures this:
SELECT * FROM v$undostat; -- usage statistics
SELECT name, value FROM v$parameter
WHERE name IN ('undo_retention', 'undo_management');
Typical default: 900 seconds (15 minutes). Production databases often set this to a few hours. Anything older than undo_retention is best-effort — Oracle will keep it if there's room, but new transactions can overwrite older undo.
If a flashback fails:
ORA-01555: snapshot too old: rollback segment number X with name "X" too small
The undo you need has been overwritten. The data isn't recoverable from undo at this point — you'll need a backup.
Part 3 — Flashback Version Query
VERSIONS BETWEEN shows you every committed state a row passed through between two points in time:
SELECT employee_id,
salary,
VERSIONS_STARTTIME,
VERSIONS_ENDTIME,
VERSIONS_OPERATION
FROM employees
VERSIONS BETWEEN TIMESTAMP
(SYSTIMESTAMP - INTERVAL '1' DAY)
AND SYSTIMESTAMP
WHERE employee_id = 100;
Result:
| employee_id | salary | versions_starttime | versions_endtime | versions_operation |
|---|---|---|---|---|
| 100 | 24000 | (NULL) | 2024-03-15 09:00:00 | (NULL) |
| 100 | 25000 | 2024-03-15 09:00:00 | 2024-03-15 14:00:00 | U |
| 100 | 26000 | 2024-03-15 14:00:00 | (NULL) | U |
Three rows = three versions of this employee's salary. The VERSIONS_OPERATION is I (insert), U (update), or D (delete).
VERSIONS_STARTTIME = NULL means "this version existed at the start of the time window".
VERSIONS_ENDTIME = NULL means "this version is the current state".
Pseudocolumns available in version queries:
VERSIONS_STARTSCN,VERSIONS_ENDSCN— SCNsVERSIONS_STARTTIME,VERSIONS_ENDTIME— timestampsVERSIONS_OPERATION— I/U/DVERSIONS_XID— transaction ID that produced this version (link to FLASHBACK_TRANSACTION_QUERY)
Part 4 — Flashback Transaction Query
Once you have a VERSIONS_XID (transaction ID), you can look up details of that transaction:
SELECT xid, operation, table_name, undo_sql
FROM FLASHBACK_TRANSACTION_QUERY
WHERE xid = HEXTORAW('06000A0023040000');
Result:
| xid | operation | table_name | undo_sql |
|---|---|---|---|
| 06000A0023040000 | UPDATE | EMPLOYEES | UPDATE "HR"."EMPLOYEES" SET "SALARY" = '24000' WHERE ROWID = '...' |
The undo_sql column gives you the exact SQL that would reverse this transaction — invaluable for forensic recovery.
Permissions: requires SELECT ANY TRANSACTION privilege (DBA only).
Part 5 — Flashback Table (Rewind)
Unlike Flashback Query (read-only), FLASHBACK TABLE ... TO TIMESTAMP actually modifies the table to undo recent changes:
-- Required setup: enable row movement
ALTER TABLE employees ENABLE ROW MOVEMENT;
-- Rewind the table to 1 hour ago
FLASHBACK TABLE employees TO TIMESTAMP SYSTIMESTAMP - INTERVAL '1' HOUR;
After this, the table looks like it did an hour ago. The changes are undone, not deleted from history — you could flashback "forward" again if you change your mind, as long as undo retention permits.
ENABLE ROW MOVEMENT is required because flashback may need to update ROWIDs.
-- Disable row movement again if desired
ALTER TABLE employees DISABLE ROW MOVEMENT;
Use with care. Other users may have made changes you don't want to lose. Flashback Table is destructive in the sense that it rolls back all changes since the chosen point.
Part 6 — Flashback Data Archive (Total Recall)
For data that needs to be retained for months or years, undo retention is impractical. Flashback Data Archive (FDA), historically called "Total Recall", stores history in dedicated archive tablespaces with configurable retention.
-- DBA: create the archive
CREATE FLASHBACK ARCHIVE compliance_archive
TABLESPACE archive_ts
RETENTION 7 YEAR;
-- Attach a table to the archive
ALTER TABLE financial_transactions FLASHBACK ARCHIVE compliance_archive;
Now VERSIONS BETWEEN and AS OF TIMESTAMP work for the table going back 7 years.
-- Query as it was a year ago
SELECT * FROM financial_transactions
AS OF TIMESTAMP SYSTIMESTAMP - INTERVAL '1' YEAR;
FDA stores its history independently of undo, so it survives backups, retention policy changes, and ordinary undo cycling. The trade-off is disk space — every change is logged.
Common use cases:
- Regulatory compliance (SOX, GDPR right-to-history)
- Audit trails for financial records
- Change tracking on configuration tables
FDA Limitations
- Cannot flashback the archived table itself (only query)
- Some DDL operations require special handling (
ALTER TABLE ... NO FLASHBACK ARCHIVEtemporarily) - Comes with licensing implications (Advanced Compression option for some Oracle editions)
Permissions and Setup
| Feature | Required Permission |
|---|---|
| Flashback Drop | Own the table (or DBA) |
| Flashback Query (AS OF) | FLASHBACK on the table, or FLASHBACK ANY TABLE |
| Flashback Version Query | Same as Flashback Query |
| Flashback Transaction Query | SELECT ANY TRANSACTION, EXECUTE on DBMS_FLASHBACK |
| Flashback Table | FLASHBACK on the table + ROW MOVEMENT enabled |
| Flashback Database | SYSDBA privilege, database must be in FLASHBACK ON mode |
| Flashback Data Archive | FLASHBACK ARCHIVE system privilege |
Grant the user-level privilege:
GRANT FLASHBACK ON employees TO hr_user;
GRANT FLASHBACK ANY TABLE TO super_user;
Worked Example — Recovering from "Oops, I Deleted All Salaries"
Friday 4:55 PM. A developer runs:
UPDATE employees SET salary = 0;
COMMIT;
It's a hot system; you can't restore from backup without 4 hours of downtime. Flashback to the rescue.
Step 1 — Confirm the damage:
SELECT employee_id, first_name, salary
FROM employees
WHERE salary = 0;
-- Returns 107 rows (everyone)
Step 2 — Check that the data still exists in undo:
SELECT employee_id, salary
FROM employees
AS OF TIMESTAMP SYSTIMESTAMP - INTERVAL '10' MINUTE
WHERE ROWNUM <= 5;
-- Returns 5 rows with real salaries
Step 3 — Restore the salaries with an UPDATE driven by flashback:
UPDATE employees cur
SET cur.salary = (
SELECT old.salary
FROM employees AS OF TIMESTAMP SYSTIMESTAMP - INTERVAL '10' MINUTE old
WHERE old.employee_id = cur.employee_id
);
COMMIT;
Salaries restored in seconds with no downtime. Total elapsed time from "oh no" to "fixed" is under five minutes.
Step 4 — Lesson learned:
ALTER USER developer QUOTA 0 ON USERS; -- jk
The real fix: change management, code review, and a WHERE clause review checklist.
Common Errors
| Error | Cause | Fix |
|---|---|---|
| ORA-01555: snapshot too old | The undo you're querying has been overwritten | Reduce the flashback timeframe; ask DBA to increase undo retention; consider FDA for long-term needs |
| ORA-02181: invalid option to ROLLBACK WORK | Tried to FLASHBACK after a long-running session | Check the session state; some flashback ops require a clean state |
| ORA-08189: cannot flashback the table because row movement is not enabled | FLASHBACK TABLE on a table without row movement |
ALTER TABLE x ENABLE ROW MOVEMENT; |
| ORA-38301: can not perform DDL/DML operation on objects in the Recycle Bin | Tried to query a recycle bin object directly | Either flashback the table first or use the bin name in quotes |
| ORA-38712: table being flashed back is part of a referential constraint | FK constraint blocks the flashback | Disable FK constraints temporarily; flashback; re-enable |
| ORA-38754: FLASHBACK DATABASE not enabled | Trying database-level flashback without setup | ALTER DATABASE FLASHBACK ON; first (DBA, with the DB in MOUNT state) |
| ORA-30087: Adding more than one TIMESTAMP WITH LOCAL TZ column is not allowed | When adding columns to FDA-tracked tables | Specific FDA constraint; see FDA documentation for workaround |
Interview Corner
▶ Show answer
FLASHBACK TABLE ... TO BEFORE DROP:
FLASHBACK TABLE employees TO BEFORE DROP;
Three things to verify first:
Was
PURGEused?DROP TABLE x PURGEskips the recycle bin and is irreversible via flashback. You'd need a backup.Is the table actually in the recycle bin?
SELECT * FROM recyclebin WHERE original_name = 'EMPLOYEES';If not, the recycle bin may have been purged (manually or automatically due to space pressure).
Have multiple tables had this name? If so, specify by recycle bin name:
FLASHBACK TABLE "BIN$NyP0kZ4...gZA==$0" TO BEFORE DROP;
Caveats:
- Foreign keys referencing this table are NOT restored
- Bitmap join indexes are NOT restored
- Trigger and constraint names may need to be renamed if collisions exist
After recovery, verify everything is intact, then re-enable any FK constraints from other tables that pointed at this one.
▶ Show answer
Source of historical data:
- Flashback Query reads from the database's existing undo data. Undo is short-lived (minutes to hours by default) — designed for transaction rollback, not long-term history.
- Flashback Data Archive (FDA) stores changes in a dedicated tablespace, independent of undo. Retention is configurable (typically years).
Use cases:
- Flashback Query — recovering from recent mistakes ("undo the past 30 minutes"), debugging today's bugs, comparing now vs an hour ago. Quick and free, but bounded by undo retention.
- FDA — regulatory compliance, audit trails, "show me how this customer's record changed over the past year". Permanent history, costs disk space.
Cost:
- Flashback Query — essentially free; uses the undo Oracle already maintains.
- FDA — each change is logged to archive tablespace, plus license cost (Advanced Compression).
ORA-01555 risk:
- Flashback Query — yes, when the requested moment is older than undo retention.
- FDA — no, the archive is permanent.
Rule of thumb: Flashback Query for operational recovery. FDA for compliance and long-term audit.
▶ Show answer
VERSIONS BETWEEN shows every committed state a row passed through — invaluable for forensic analysis and change tracking without dedicated history tables.
Common scenarios:
"Who changed this customer's email three times in one hour?"
SELECT customer_id, email, VERSIONS_STARTTIME, VERSIONS_XID FROM customers VERSIONS BETWEEN TIMESTAMP SYSTIMESTAMP - INTERVAL '1' HOUR AND SYSTIMESTAMP WHERE customer_id = 1234;Then look up each
VERSIONS_XIDinFLASHBACK_TRANSACTION_QUERYto find the user and statement.Bug hunting — a value is wrong; was it always wrong or recently changed?
SELECT account_id, balance, VERSIONS_STARTTIME, VERSIONS_OPERATION FROM accounts VERSIONS BETWEEN TIMESTAMP ... AND ... WHERE account_id = 999 ORDER BY VERSIONS_STARTTIME;Audit reconciliation — count how many updates happened per day:
SELECT TRUNC(VERSIONS_STARTTIME), COUNT(*) FROM employees VERSIONS BETWEEN TIMESTAMP ... WHERE VERSIONS_OPERATION = 'U' GROUP BY TRUNC(VERSIONS_STARTTIME);
Caveat: Bounded by undo retention. For audit work beyond a few hours, FDA is more reliable.
Related Topics
- DML Commands — flashback recovers from accidental UPDATE/DELETE
- DDL Commands — flashback drop recovers from accidental DROP TABLE
- Transactions & Locks — undo retention drives flashback availability
- Performance — long flashback queries on large tables can be slow; tune accordingly
- Constraints — FK constraints affect what flashback can/cannot restore