🚧 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 Science & Analytics › Data Cleaning and Preparation for Analysis › Lesson 5
TEC-DATA85-05 · Lesson 5 · 11 clock hours · lab

Deduplication and Referential Integrity

Objective. Students will identify and remove exact and near-duplicate records using pandas and fuzzy-matching (rapidfuzz), and resolve foreign-key violations in a relational dataset using SQL, producing a change log of every removed or corrected record.

⚠ 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.

Why Deduplication and Referential Integrity Matter

Dirty data costs organizations real money and produces misleading analysis. Two of the most common structural problems in relational datasets are duplicate records and referential-integrity violations. If a business-license table contains the same license twice, every count, rate, and trend you compute is wrong. If an orders table references a customer ID that does not exist in the customers table, joins silently drop rows or return NULL-filled results. Fixing these problems before analysis—and logging every change—is a professional obligation, not an optional step.

Exact Duplicates vs. Near-Duplicates

An exact duplicate is a row where every field matches another row byte-for-byte. pandas makes these easy to handle. `df.drop_duplicates()` with no arguments removes rows that are identical across all columns. The `subset` argument lets you define what "duplicate" means for your business context. For example, a business-license table might legitimately have two rows with the same business name if the business holds licenses for different locations. Dropping on `subset=['license_number']` would be appropriate; dropping on `subset=['business_name']` alone would incorrectly remove valid records. Always justify your subset choice in comments so a future analyst understands the decision.

A near-duplicate is harder: the same real-world entity appears with slight spelling differences, abbreviations, or data-entry errors (`"Smith & Sons LLC"` vs. `"Smith and Sons, LLC"`). These cannot be caught by exact matching. Fuzzy matching measures string similarity with a score from 0 to 100. The `rapidfuzz` library provides fast, production-ready fuzzy matching in Python. Its `fuzz.ratio` and `fuzz.token_sort_ratio` functions are the most commonly used scorers. `token_sort_ratio` sorts the tokens alphabetically before comparing, which helps with word-order differences.

Setting and Reviewing a Similarity Threshold

Choosing a threshold is a judgment call backed by domain knowledge. A common starting point is 85–90 out of 100. Matches above your threshold are likely the same entity; matches below are likely different. The dangerous zone is the borderline range (roughly 75–90), where you must review manually and record your accept or reject decision. Never auto-accept every match above an arbitrary cutoff without spot-checking a sample—false positives in fuzzy matching can silently merge records that should remain separate.

Document every decision in a change log CSV with at minimum these columns: `record_id`, `action` (removed / corrected / merged), `reason`, `analyst_initials`, `timestamp`. This log is your audit trail. If a stakeholder questions why a record is missing, the log is your defense.

Referential Integrity in Relational Databases

A foreign key in one table must match a primary key that actually exists in the referenced table. When it does not, you have an orphaned record. Orphaned orders (orders whose `customer_id` does not appear in the customers table) will disappear from any INNER JOIN, silently reducing your row counts. A NULL in a primary-key column is a separate violation—primary keys must be unique and non-null by definition.

To find orphaned foreign keys in SQL use a LEFT JOIN and filter for NULL on the right side:

```sql

SELECT o.order_id

FROM orders o

LEFT JOIN customers c ON o.customer_id = c.customer_id

WHERE c.customer_id IS NULL;

```

To find NULL primary keys:

```sql

SELECT COUNT(*) FROM customers WHERE customer_id IS NULL;

```

Once you identify violations, resolution options are:

Always run a COUNT query before and after your fix and record both numbers in your change log.

Safe Data-Modification Practices

Before running any DELETE or UPDATE in a production-like environment, follow these steps:

1. Back up or snapshot the table, or work in a sandbox schema.

2. Run a SELECT first using the exact same WHERE clause to confirm which rows will be affected.

3. Wrap statements in a transaction (`BEGIN; ... ROLLBACK;`) to preview effects before committing.

4. Never modify source data in place without version control or a backup. In pandas, work on a copy (`df.copy()`) so the original DataFrame remains intact for comparison.

These habits protect you and your organization from irreversible data loss. In a professional setting, destructive operations on shared databases typically require a supervisor sign-off recorded in a ticket or change-management system.

Connecting to Credentials

Deduplication and referential integrity appear across all four credentials you are working toward. CompTIA Data+ tests data-quality concepts directly. The Google Data Analytics Certificate covers data cleaning as a core competency. IBM Data Science Professional includes data wrangling with pandas. Microsoft PL-300 tests understanding of data model relationships, which depends on intact foreign keys. Mastering these skills now pays dividends on every exam and in every job.

Key terms9

Exact duplicateA row in a dataset that matches one or more other rows on every compared field, byte-for-byte.
Near-duplicateA record that refers to the same real-world entity as another record but differs due to spelling variation, abbreviation, or data-entry error.
Fuzzy matchingA technique that scores the similarity between two strings on a scale (commonly 0–100) rather than requiring an exact character match, allowing near-duplicates to be detected.
Similarity thresholdA minimum fuzzy-match score chosen by the analyst above which two records are treated as likely duplicates; records near the threshold require manual review.
Referential integrityThe database rule that every foreign-key value in a child table must match an existing primary-key value in the parent table, with no orphaned or NULL foreign keys.
Orphaned recordA row whose foreign-key value has no corresponding primary key in the referenced table, causing it to be lost from INNER JOINs.
Change logA structured record—typically a CSV or database table—documenting every row that was removed, corrected, or merged during data cleaning, including the reason and analyst identity.
drop_duplicates (pandas)A pandas DataFrame method that removes duplicate rows; the subset argument controls which columns define uniqueness for the purpose of deduplication.
token_sort_ratio (rapidfuzz)A fuzzy-matching scorer that sorts the words in each string alphabetically before comparing, making it robust to word-order differences between otherwise identical strings.

Worked examples3

1. A business-license DataFrame has 1,200 rows before deduplication. After drop_duplicates(subset=['license_number']) it has 1,175 rows. After a second pass with drop_duplicates(subset=['license_number','location_id']) it has 1,160 rows. How many duplicates did each pass remove, and what is the total removed?
  1. Pass 1 removed: 1,200 − 1,175 = 25 rows (exact duplicate license numbers).
  2. Pass 2 starts from 1,175 rows and removes: 1,175 − 1,160 = 15 rows (same license number AND location—second-pass duplicates not caught by license number alone).
  3. Total removed: 25 + 15 = 40 rows.
Answer: Pass 1 removed 25 rows; Pass 2 removed 15 rows; total duplicates removed = 40 rows.
2. rapidfuzz returns a token_sort_ratio of 88 for 'Acme Building Services LLC' vs. 'Acme Building Svc LLC'. Your threshold is 90. What action do you take and how do you log it?
  1. The score (88) is below the auto-accept threshold of 90, so this pair falls in the manual-review zone.
  2. Inspect both records: the difference is 'Services' vs. 'Svc', a common abbreviation pointing to the same company.
  3. Decision: accept as a match (merge / flag as duplicate).
  4. Log in the change log CSV: record_id for both rows, action = 'merged', reason = 'Fuzzy score 88, manual review confirmed same entity (abbreviation difference)', analyst_initials, timestamp.
Answer: Manually review and accept the match; document both record IDs, the score, the reason for acceptance, and your initials in the change log.
3. Before fixing referential-integrity violations the orders table has 500 rows, of which 18 are orphaned (no matching customer_id). After running a DELETE to remove orphans, what should the COUNT query return, and what two values belong in the change log?
  1. Before count: 500 rows total in orders; 18 orphaned rows confirmed by the LEFT JOIN / IS NULL query.
  2. After DELETE WHERE customer_id NOT IN (SELECT customer_id FROM customers): expected count = 500 − 18 = 482 rows.
  3. Change log entry 1: before_count = 500.
  4. Change log entry 2: after_count = 482; action = 'deleted'; reason = 'orphaned foreign key — no matching customer_id in customers table'.
Answer: The post-DELETE COUNT query should return 482. The change log records before_count = 500 and after_count = 482.
In class: Exact-duplicate lab: students use pandas drop_duplicates with different subset arguments on a business-license table; they record row counts before and after each pass and explain in comments why each subset choice is or is not appropriate for the business context. · Fuzzy-matching exercise: using rapidfuzz, students match business names across two tables that represent the same entities but were entered by different staff; they set a similarity threshold, review borderline matches manually, and document accept/reject decisions in a CSV change log. · SQL referential-integrity check: students run provided SQL queries against a PostgreSQL sandbox (orders and customers tables) to find orphaned foreign keys and NULL primary keys; they write UPDATE and DELETE statements to resolve the violations and verify with COUNT queries before and after.
Materials: Business-license CSV, PostgreSQL sandbox with orders/customers tables, Jupyter Lab, pandas, rapidfuzz library, DBeaver or psql client, change-log CSV template
Check: Change log must be complete (every removed or corrected record listed with reason); SQL before/after counts must match expected values provided on an answer sheet; rubric pass at 75 % across completeness, correctness, and documentation criteria.

Practice check8

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

Data Quality and Data Cleaning
1. A pandas DataFrame representing employee records has 800 rows. You call drop_duplicates(subset=['employee_id']) and get 780 rows. What does this tell you?
Data Wrangling and Preparation
2. Which rapidfuzz scorer is BEST for matching 'Services Building Acme' to 'Acme Building Services' when word order may vary?
Data Quality and Data Cleaning
3. An analyst sets a fuzzy-match threshold of 92 and auto-accepts all pairs scoring 92 or above without manual review. What is the PRIMARY risk of this approach?
Database Querying and SQL
4. Which SQL pattern correctly identifies orders whose customer_id does not exist in the customers table?
Data Governance and Safe Practice
5. Before deleting orphaned records from a shared database table, what should you do FIRST?
Data Documentation and Governance
6. A change log entry should include which combination of fields to satisfy a professional audit requirement?
Data Quality and Data Cleaning
7. A student runs drop_duplicates(subset=['business_name']) on a business-license table and removes 40 rows. The instructor marks this partially incorrect. Which explanation is MOST likely correct?
Power BI Data Modeling (PL-300)
8. In a Power BI data model, an Orders table has a Many-to-One relationship to a Customers table on customer_id. If orphaned customer_id values exist in Orders, what is the MOST likely symptom during reporting?
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.