Databricks DE ยท Topic 4.2

COPY INTO

A SQL command that batch-loads files into a Delta table and skips files it already loaded โ€” idempotent, incremental, no streaming setup. This deep dive walks each capability with the code.

SQL commandidempotentSELECT transformVALIDATEforce reload

The one-liner

COPY INTO loads files from cloud storage / a UC Volume into a Delta table and skips already-loaded files on re-run โ€” the simple, SQL-first, batch sibling of Auto Loader.
๐Ÿฆ Analogy: importing bank statements into a spreadsheet. COPY INTO remembers which files it already imported, so re-running the import won't double-count โ€” it just adds the new statements.

Idempotency โ€” re-run safely

โ–ธ run COPY INTO repeatedly; already-loaded files are skipped

Source empty.

1 ยท Basic load & the idempotency mechanism

COPY INTO tracks loaded files per target table and skips them on re-run โ€” even if the file was later modified (tracked by path, not content). FORMAT_OPTIONS = parsing; COPY_OPTIONS = load behavior.

COPY INTO cat.sch.bronze_sales
FROM '/Volumes/cat/sch/vol/sales/'
FILEFORMAT = CSV
FORMAT_OPTIONS ('header' = 'true', 'inferSchema' = 'true')   -- parsing
COPY_OPTIONS  ('mergeSchema' = 'true');                       -- load behavior

PySpark โ€” COPY INTO is SQL, run via spark.sql

spark.sql("""COPY INTO cat.sch.bronze_sales
  FROM '/Volumes/cat/sch/vol/sales/' FILEFORMAT = CSV
  FORMAT_OPTIONS ('header' = 'true')""")

2 ยท Transform on load with a SELECT

Wrap a SELECT to cast / rename / derive columns during ingestion โ€” type raw strings without a second pass.

COPY INTO cat.sch.bronze_sales
FROM (
  SELECT CAST(order_id AS BIGINT) AS order_id,
         CAST(amount AS DECIMAL(10,2)) AS amount,
         to_date(order_date, 'yyyy-MM-dd') AS order_date
  FROM '/Volumes/cat/sch/vol/sales/'
)
FILEFORMAT = CSV FORMAT_OPTIONS ('header' = 'true');

3 ยท Target files (PATTERN / FILES) & dry-run (VALIDATE)

-- PATTERN and FILES are mutually exclusive; FILES caps at 1000
COPY INTO cat.sch.bronze_sales FROM '/Volumes/cat/sch/vol/sales/'
FILEFORMAT = CSV PATTERN = '2026-*.csv';            -- glob filter

-- Test parsing/schema/constraints WITHOUT writing
COPY INTO cat.sch.bronze_sales FROM '/Volumes/cat/sch/vol/sales/'
FILEFORMAT = CSV VALIDATE 50 ROWS;             -- or VALIDATE ALL

4 ยท Force a reload + evolve schema

COPY INTO cat.sch.bronze_sales FROM '/Volumes/cat/sch/vol/sales/'
FILEFORMAT = CSV
COPY_OPTIONS ('force' = 'true',        -- disable idempotency: reload everything
              'mergeSchema' = 'true');  -- evolve new columns in
๐Ÿ’ก force=true is how you re-ingest after a fix (a modified same-path file is otherwise skipped). mergeSchema=true handles schema drift.

COPY INTO vs Auto Loader โ€” click each

COPY INTO โ€” SQL command, batch/scheduled, tracks loaded files.
  • โœ… Simple, pure SQL, no checkpoint plumbing
  • โœ… Great for periodic loads of modest file volumes
  • โš ๏ธ Less scalable for millions of files
Auto Loader โ€” cloudFiles streaming source, checkpointed.
  • โœ… Scales to millions/billions of files; continuous or availableNow
  • โœ… File-notification / file-events for huge dirs
  • โš ๏ธ More setup (stream + checkpoint)
COPY INTOAuto Loader
InterfaceSQL commandStructured Streaming
ScaleThousands of filesMillions+
StateTracks loaded filesCheckpoint (RocksDB)
Best forSimple periodic loadsLarge-scale continuous

Why it matters

๐Ÿ“„ Real-world use case: a vendor drops a daily CSV into a UC Volume. A scheduled COPY INTO bronze_sales FROM '...' loads each new day's file exactly once โ€” no checkpoint plumbing, just SQL in a job.

Uses, edge cases & limitations

Common gotchas