Time Travel and RESTORE -- Inspect Before You Recover

Recover from an accidental bulk UPDATE by time-travelling through versions, picking the last good snapshot, and restoring the table with a single RESTORE TO VERSION command.

Category: delta

Syntax

-- SETUP
CREATE ZONE IF NOT EXISTS demo_zone TYPE EXTERNAL
    COMMENT 'External and Delta tables -- demo datasets';

CREATE SCHEMA IF NOT EXISTS demo_zone.delta_demos
    COMMENT 'Delta table management tutorial demos';

CREATE DELTA TABLE IF NOT EXISTS demo_zone.delta_demos.course_grades (
    record_id    INT,
    student_name VARCHAR,
    course       VARCHAR,
    grade        INT,
    semester     VARCHAR
) LOCATION '~/delta-data/course_grades';

INSERT INTO demo_zone.delta_demos.course_grades VALUES
    (1,  'Alice', 'CS101',    82, 'Fall-2025'),
    (2,  'Bob',   'CS101',    71, 'Fall-2025'),
    (3,  'Carol', 'CS101',    90, 'Fall-2025'),
    (4,  'David', 'CS101',    65, 'Fall-2025'),
    (5,  'Eve',   'CS101',    88, 'Fall-2025'),
    (6,  'Alice', 'CS201',    78, 'Fall-2025'),
    (7,  'Bob',   'CS201',    84, 'Fall-2025'),
    (8,  'Carol', 'CS201',    73, 'Fall-2025'),
    (9,  'David', 'CS201',    91, 'Fall-2025'),
    (10, 'Eve',   'CS201',    69, 'Fall-2025'),
    (11, 'Alice', 'MATH101',  95, 'Fall-2025'),
    (12, 'Bob',   'MATH101',  62, 'Fall-2025'),
    (13, 'Carol', 'MATH101',  88, 'Fall-2025'),
    (14, 'David', 'MATH101',  74, 'Fall-2025'),
    (15, 'Eve',   'MATH101',  81, 'Fall-2025'),
    (16, 'Alice', 'PHYS101',  70, 'Fall-2025'),
    (17, 'Bob',   'PHYS101',  86, 'Fall-2025'),
    (18, 'Carol', 'PHYS101',  77, 'Fall-2025'),
    (19, 'David', 'PHYS101',  83, 'Fall-2025'),
    (20, 'Eve',   'PHYS101',  92, 'Fall-2025'),
    (21, 'Alice', 'ENG101',   88, 'Fall-2025'),
    (22, 'Bob',   'ENG101',   79, 'Fall-2025'),
    (23, 'Carol', 'ENG101',   94, 'Fall-2025'),
    (24, 'David', 'ENG101',   68, 'Fall-2025'),
    (25, 'Eve',   'ENG101',   85, 'Fall-2025');

-- QUERIES
-- V2: legitimate curve -- CS101 +5
UPDATE demo_zone.delta_demos.course_grades
SET grade = grade + 5
WHERE course = 'CS101';

-- V3: ACCIDENT -- a script zeros every grade
UPDATE demo_zone.delta_demos.course_grades
SET grade = 0;

-- Inspect V1: original, pre-curve
SELECT course, ROUND(AVG(grade), 2) AS avg_grade, COUNT(*) AS students
FROM demo_zone.delta_demos.course_grades VERSION AS OF 1
GROUP BY course
ORDER BY course;

-- Inspect V2: last known good state (curve applied)
SELECT course, ROUND(AVG(grade), 2) AS avg_grade, COUNT(*) AS students
FROM demo_zone.delta_demos.course_grades VERSION AS OF 2
GROUP BY course
ORDER BY course;

-- Inspect V3: confirm the accident -- all zeroes
SELECT COUNT(*) AS zero_count
FROM demo_zone.delta_demos.course_grades VERSION AS OF 3
WHERE grade = 0;

-- RESTORE TO VERSION 2 -- creates V4, a new commit replicating V2's snapshot
RESTORE demo_zone.delta_demos.course_grades TO VERSION 2;

-- Verify recovery: averages now match V2 exactly
SELECT course,
       ROUND(AVG(grade), 2) AS avg_grade,
       COUNT(*) AS students
FROM demo_zone.delta_demos.course_grades
GROUP BY course
ORDER BY course;

-- The bad V3 commit is STILL reachable -- log is append-only
SELECT COUNT(*) AS zero_count
FROM demo_zone.delta_demos.course_grades VERSION AS OF 3
WHERE grade = 0;

-- CLEANUP
DROP DELTA TABLE IF EXISTS demo_zone.delta_demos.course_grades WITH FILES;
DROP SCHEMA IF EXISTS demo_zone.delta_demos;
DROP ZONE IF EXISTS demo_zone;

Description

## When to Use Reach for this pattern whenever someone points the wrong job at a production table. Delta keeps every committed snapshot addressable by integer version (and by timestamp), so you can open any historical view read-only via VERSION AS OF, compare it against the current state, and only then -- once you are sure you picked the right target -- use RESTORE to replay that snapshot as a new commit. This is Delta's built-in undo. The scenario: a teaching assistant runs a grade-reset script against the wrong table, zeroing 25 student grades. You time-travel to V1 (pre-curve), V2 (post-curve -- the last good state) and V3 (the accident) before deciding. The right target is V2 because V1 would discard a legitimate CS101 curve that you want to keep. ## What You Will Learn 1. How every DML statement bumps the Delta version and how to read the version ladder 2. How VERSION AS OF <n> lets you query any historical snapshot without touching the table 3. Why you should always inspect several versions before recovering -- the "last good" version is rarely the oldest one 4. How RESTORE TO VERSION appends a NEW commit (V4) that materialises the target snapshot, rather than rewriting history 5. That the bad commit (V3) stays reachable via time travel after RESTORE -- the log is append-only 6. How to use ASSERT VALUE ... WHERE to verify aggregates at specific recovery checkpoints 7. Delta also supports TIMESTAMP AS OF '2024-01-15 10:00:00' if you prefer wall-clock recovery ## Prerequisites None -- the setup seeds 25 grade rows. The demo deliberately performs a destructive UPDATE inside the queries.sql to simulate the accident you need to recover from.

Parameters

NameTypeDescription
TABLE_PATHFilesystem or object-store location for the Delta table.
TARGET_VERSIONVersion number to restore to. Inspect candidates via VERSION AS OF before running RESTORE.

Pitfalls

Open in interactive docs →   DeltaForge home →