🚧 Under construction — VoTechWorks is being built. A free tech program — complimentary, as our commitment to get America working.
voTechWorksGrade 13 · a vocational technology learning center, by urbanicity
newSchoolWorks.com › VoTechWorks › Technology & Design › Data Management / Database Administration › ETL Pipelines: Extract, Transform, and Load for Database Administration › Lesson 4
TEC-DATA86-06 · Lesson 4 · 12.5 clock hours · lab

Load Strategies: Truncate-Reload, Upsert, and Incremental Load

Objective. Students will implement three distinct load patterns against a PostgreSQL target database and verify data integrity using row counts, checksums, and a duplicate-check query after each load.

⚠ Pending professional review

This lesson, its worked examples and its practice questions has not yet been verified by an industry-certified professional or by a certification or approval body. It is a study draft and may contain errors. Do not use it as instructions for work on a job site or on live equipment. Always follow your instructor, your supervising professional, and current official references and regulations.

VoTechWorks program approval and accreditation are still in progress. Credentials are issued only by the certifying bodies named in each program, after their own exams.

Load Strategies: Truncate-Reload, Upsert, and Incremental Load

Once data has been extracted and transformed, it must be written into the target database correctly. Choosing the wrong load strategy can corrupt data, create duplicates, or cause unacceptable downtime. This lesson covers the three patterns you will use most often as a database administrator: truncate-reload, upsert, and incremental load.

---

Why Load Strategy Matters

Every load operation must satisfy two properties. First, it must be correct: the target table should contain exactly the rows the business expects after the load completes. Second, it must be idempotent where possible: running the same load twice should not leave the table worse off than running it once. Checking row counts, checksums, and duplicate queries after each load gives you objective evidence that both properties hold.

---

Pattern 1 – Truncate-Reload

Truncate-reload is the simplest strategy. You delete every row from the target table and replace it with a fresh full copy of the source data. It is appropriate for dimension tables or small reference tables that are republished in full every cycle — for example, a daily product-category snapshot.

How it works in PostgreSQL:

1. Open a transaction with `BEGIN`.

2. Issue `TRUNCATE target_table;` — this removes all rows but keeps the table structure. Inside the same transaction, the truncated rows are invisible to other sessions until you commit, so the table is never empty from the outside if you hold the transaction open.

3. Load the clean file with `COPY target_table FROM '/path/to/file.csv' CSV HEADER;`.

4. Verify the row count with `SELECT COUNT(*) FROM target_table;`.

5. `COMMIT`.

Because the TRUNCATE and COPY share a transaction, a failure at step 3 causes the whole operation to roll back, leaving the old data intact. This is a critical safety property.

Idempotency test: Rerun the exact same script. You should see the same row count and the same checksum. If you see double the rows, the table is missing its TRUNCATE — a logic error you must catch before production.

---

Pattern 2 – Upsert

An upsert merges new and changed rows without touching rows that have not changed, and without creating duplicates. It is the right choice for master data tables (customers, employees, accounts) that receive delta files containing both new records and corrections to existing ones.

PostgreSQL implements upsert with `INSERT … ON CONFLICT`. The general form is:

```sql

INSERT INTO customer (customer_id, name, email, updated_at)

VALUES (%s, %s, %s, %s)

ON CONFLICT (customer_id)

DO UPDATE SET

name = EXCLUDED.name,

email = EXCLUDED.email,

updated_at = EXCLUDED.updated_at;

```

The `ON CONFLICT` clause targets the primary key or a unique constraint. `EXCLUDED` is a special table alias that refers to the row that was just rejected by the conflict. Setting columns equal to `EXCLUDED.column` applies the incoming values.

Validation: After loading the initial batch and then the delta batch, query for duplicates with `SELECT customer_id, COUNT() FROM customer GROUP BY customer_id HAVING COUNT() > 1;`. An empty result set means no duplicates exist. Also spot-check a changed row to confirm the update was applied.

---

Pattern 3 – Incremental Load

For large fact tables (sales transactions, sensor readings, log events), loading a full extract every cycle is too slow. An incremental load appends only the rows that are new since the last load.

How it works:

1. Query the target table for the latest loaded record date: `SELECT MAX(record_date) FROM sales_fact;`. Call this value `last_load_date`.

2. Extract only source rows where `record_date > last_load_date`.

3. Append those rows with `COPY` or a batch `INSERT`.

4. Validate with `SELECT COUNT(*)` and a `SUM` checksum (e.g., `SELECT SUM(sale_amount) FROM sales_fact WHERE record_date > last_load_date`) and compare against the same aggregation run on the source extract.

Key risk: If the source system allows late-arriving data — records that carry an older `record_date` but arrive after your cutoff — a strict `MAX`-based watermark will miss them. Always confirm with the source system owner whether late arrivals are possible, and add an appropriate buffer or use a separate audit column if needed.

---

Data Integrity Checks

For all three patterns, run these checks after every load:

Document expected values before the load and compare programmatically. Manual eyeballing is not sufficient for production pipelines.

---

Safety and Professional Practice

Always run destructive operations (TRUNCATE, DELETE) inside a transaction so a failure can be rolled back. Keep the transaction as short as possible to avoid locking the table for long periods, which blocks other users. Never run a load directly against a production table until you have tested it in the student schema. Back up or snapshot any table you are about to truncate in a production context — your organization's change-control policy will specify the exact procedure. Protect connection credentials: do not hard-code passwords in scripts; use environment variables or a secrets manager.

Key terms8

Truncate-ReloadA load pattern that removes all rows from the target table and replaces them with a complete fresh copy of the source data, typically executed inside a transaction for safety.
UpsertA load pattern that inserts new rows and updates existing rows in a single statement, using PostgreSQL's INSERT … ON CONFLICT syntax, preventing duplicates in master data tables.
Incremental LoadA load pattern that appends only the rows that are newer than the maximum value already present in the target table, reducing load time for large fact tables.
IdempotencyThe property of a load operation whereby running it multiple times produces the same result as running it once, preventing duplicate or corrupted data on reruns.
EXCLUDEDA special table alias in PostgreSQL's ON CONFLICT … DO UPDATE clause that refers to the incoming row that was rejected due to a conflict, allowing its values to be applied as an update.
WatermarkA stored high-water mark value — typically a MAX date or MAX ID — used in incremental loads to determine which source rows have not yet been loaded into the target.
Checksum (ETL context)An aggregate value — such as a SUM of a numeric column or an MD5 hash of concatenated rows — computed on both source and target after a load to verify that data was not altered or lost in transit.
COPY (PostgreSQL)A PostgreSQL command that bulk-loads data from a file or standard input directly into a table, significantly faster than row-by-row INSERT for large datasets.
In class: Implement a truncate-reload load for a daily-snapshot dimension table: TRUNCATE the target table inside a transaction, COPY the clean file in, verify row count, and COMMIT; then intentionally rerun and confirm idempotent behavior. · Implement an upsert load using INSERT … ON CONFLICT (target_pk) DO UPDATE SET … for a customer master table; load an initial batch, then load a delta batch containing new rows and changed rows, and query the table to confirm updated values and no duplicates. · Implement a date-range incremental load for a large fact table: query the target for the MAX load date, extract only source rows with a record_date greater than that value, and append them; validate with a COUNT and a SUM checksum against the source.
Materials: Student laptops, PostgreSQL 15 target database (student schema on instructor VM), psycopg2, instructor-prepared clean staging files for each pattern, PostgreSQL COPY documentation, DP-300 study guide section on data loading patterns
Check: Post-load SQL queries (provided by instructor) return row counts and checksums that match expected values for all three patterns; pass = all three patterns pass with zero discrepancy

Practice check8

Answer each question, then check it. Nothing is recorded; this is your own practice.

Data loading patterns and transaction management
1. A DBA runs a truncate-reload script that issues TRUNCATE and then COPY inside a single transaction. The COPY fails midway due to a malformed row. What is the state of the target table after the failure?
PostgreSQL DML and upsert patterns
2. Which PostgreSQL clause is used to update an existing row when an INSERT would violate a primary key constraint?
Data integrity validation and SQL
3. After an upsert load into a customer master table, a DBA wants to confirm no duplicate customer IDs were created. Which query correctly checks for duplicates?
Incremental load design and ETL patterns
4. A fact table currently contains sales records up to and including 2024-06-15. An incremental load script queries SELECT MAX(record_date) FROM sales_fact and receives '2024-06-15'. Which rows should the script extract from the source?
ETL pipeline reliability and idempotency
5. A truncate-reload script is rerun a second time with the same input file. If the script is correctly implemented, what should the row count in the target table be after the second run?
Incremental load design and data quality
6. In the context of an incremental load, what is the primary risk of using a MAX(record_date) watermark when the source system allows late-arriving data?
ETL architecture and load strategy selection
7. Which load strategy is most appropriate for a large transactional fact table containing hundreds of millions of rows when only a small percentage of rows are new each day?
Data integrity validation and ETL quality assurance
8. After completing an incremental load of new sales rows into a fact table, a DBA wants to verify that the loaded amounts are correct, not just that the right number of rows arrived. Which validation technique is most appropriate?
Record this lesson on my transcript. Sign in with your key and enrollment email to record lessons (enroll free if you have no key). This page stays open to read and practise.