First Migration Record

A medium SQL interview practice problem on DataDriven. Write the query and run it against a real database, with instant feedback.

Domain
SQL
Difficulty
medium
Seniority
L3
Asked in
Google

Problem

Nobody agrees where each database's schema history starts: some rows in migrations carry no applied date, and the dates that are there do not follow the order the migrations ran in. For the platform team's baseline report, pull each database's first migration, the one with the smallest migration ID, with every field it records.

The very first migration. Where it all began.

Tables

migrations

Columns: migr_id INTEGER, version TEXT, status TEXT, applied TEXT, rollback TEXT, dur_ms INTEGER, author TEXT, db_name TEXT

migrations: 10 of 200 rows
migr_idversionstatusappliedrollbackdur_msauthordb_name
123002_add_userspending2026-02-02 01:00:00DROP TABLE IF EXISTS tbl_141bobstaging_main
146003_add_ordersfailed2026-03-03 02:00:00DROP TABLE IF EXISTS tbl_272charlieanalytics
169004_indexesrolled_back2026-04-04 03:00:00DROP TABLE IF EXISTS tbl_3103danareporting
192005_add_productsApplied2026-05-05 04:00:00DROP TABLE IF EXISTS tbl_4134migration-botarchive
215006_add_sessionsPENDINGNULLDROP TABLE IF EXISTS tbl_5NULLAliceprod_main
238007_add_eventsapplied2026-07-07 06:00:00DROP TABLE IF EXISTS tbl_6196alicestaging_main
261008_add_searchpending2026-08-08 07:00:00NULL227bobanalytics
284v009_paymentsfailed2026-09-09 08:00:00DROP TABLE IF EXISTS tbl_8258charliereporting
307V010_analyticsrolled_back2026-01-10 09:00:00DROP TABLE IF EXISTS tbl_9289danaarchive
330001_initAppliedNULLDROP TABLE IF EXISTS tbl_10NULLmigration-botprod_main

Expected output

First 5 of 5 rows
migr_idversionstatusappliedrollbackdur_msauthordb_name
123002_add_userspending2026-02-02 01:00:00DROP TABLE IF EXISTS tbl_141bobstaging_main
146003_add_ordersfailed2026-03-03 02:00:00DROP TABLE IF EXISTS tbl_272charlieanalytics
169004_indexesrolled_back2026-04-04 03:00:00DROP TABLE IF EXISTS tbl_3103danareporting
192005_add_productsApplied2026-05-05 04:00:00DROP TABLE IF EXISTS tbl_4134migration-botarchive
215006_add_sessionsPENDINGNULLDROP TABLE IF EXISTS tbl_5NULLAliceprod_main

Worked solution and explanation

This is a per-group argmin dressed up as a release audit: for every database, find the row whose migr_id is smallest inside that database and return the whole row. Everyone knows MIN(migr_id). What separates candidates is where the minimum is scoped. Run the subquery over the whole table and you get one row, migration 123 on 'staging_main', while four databases quietly lose their baseline. Use the earliest applied date instead and 'prod_main' disappears, because not one of its migrations has an applied date.

Walking to the answer

Step 1: Decide what first means before writing anything

The applied column cannot be trusted: 40 rows are NULL, every 'prod_main' row among them, and the backfilled rows dated 2022 to 2025 carry the largest IDs. Migrations run in ID order, so a database's first migration is its smallest migr_id. Asking this out loud is half the interview.

Step 2: Scope the minimum to the outer row's database

The subquery SELECT MIN(db_peer.migr_id) FROM migrations AS db_peer WHERE db_peer.db_name = mig.db_name reads mig.db_name from the outer row, so for every candidate row it answers one question: what is the smallest ID in my own database?

Step 3: Keep the row that equals its database's minimum

The outer WHERE mig.migr_id = (...) keeps a row only when it is its database's minimum. Because migr_id is unique, exactly one row per database survives: five rows, each with all eight columns intact.

First migration of each database
SELECT
    mig.migr_id,
    mig.version,
    mig.status,
    mig.applied,
    mig.rollback,
    mig.dur_ms,
    mig.author,
    mig.db_name
FROM migrations AS mig
WHERE mig.migr_id = (
    SELECT MIN(db_peer.migr_id)
    FROM migrations AS db_peer
    WHERE db_peer.db_name = mig.db_name
)

The correlated db_peer.db_name = mig.db_name is the whole problem; everything else is a lookup.

Table-wide minimum
WHERE migr_id = (SELECT MIN(migr_id) FROM migrations) returns only migration 123. 'analytics', 'reporting', 'archive' and 'prod_main' have no baseline in the report, and nothing errors.
Minimum per database
Correlating on db_name returns 123, 146, 169, 192 and 215: one baseline per database, with each database's own version, status and author.
The single-row version that looks right
SELECT mig.migr_id, mig.version, mig.status, mig.applied,
       mig.rollback, mig.dur_ms, mig.author, mig.db_name
FROM migrations AS mig
WHERE mig.migr_id = (SELECT MIN(migr_id) FROM migrations)

Uncorrelated, so it answers 'first migration anywhere', not 'first per database'.

Common follow-up questions