Role: QA — data validation (portfolio project)

Dataset: a small e-commerce schema I built myself (customers, products, orders, order_items) — same domain as the rest of this portfolio, seeded with realistic data that includes deliberate, labeled data-quality issues.

UI testing and API testing both stop at the response the app gives you. This project goes one layer deeper: I wrote queries that validate the data itself — duplicate records, orphaned foreign keys, totals that don't add up — the kind of check that catches a bug the UI never shows because it never renders the broken row.

SQL Data Validation Referential Integrity JOINs & Aggregation

Schema

customers (id, name, email, country) · products (id, name, category, price) · orders (id, customer_id, order_date, total_amount) · order_items (id, order_id, product_id, quantity, unit_price) — a standard e-commerce shape, small enough to seed by hand with known, labeled anomalies.

Queries (9)

#What it validatesTechniqueResult
Q1 Duplicate customers by email GROUP BY … HAVING COUNT(*) > 1 1 found
Q2 Customers missing a required field (email) NULL / empty-string check 1 found
Q3 Order items referencing a non-existent product LEFT JOIN … WHERE … IS NULL (anti-join) 1 found
Q4 Stored order total vs. sum of its line items JOIN + GROUP BY + HAVING (business rule) 1 found
Q5 Orders with no linked customer NULL foreign key check 1 found
Q6 Products with an invalid price (≤ 0) WHERE filter 1 found
Q7 Full order detail across customer + product 3-table JOIN 17 rows
Q8 Top customers by total spend Aggregation (SUM, GROUP BY, ORDER BY) Pass
Q9 Products that were never ordered Anti-join 1 found

↳ Full SQL, the pre-built database file and the raw captured output: sql/ on GitHub.

Data issues found (5)

Every result below is from actually running the queries against the seeded database — not hand-typed.

[order_items] Line item references a product that doesn't exist
Q3 · referential integrity
Expected resultEvery order_items.product_id should exist in products
Actual resultOrder 7 has a line item pointing at product_id = 99, which doesn't exist — the kind of row that crashes an order-history screen the moment it tries to join in the product name
Severity: High
[orders] Stored total doesn't match the sum of its line items
Q4 · business-rule validation
Expected resulttotal_amount should equal SUM(quantity × unit_price) for that order
Actual resultOrder 4 stores 50.00 but its line items add up to 57.74 — a $7.74 discrepancy. Same category of bug as a UI cart total not updating, just caught at the data layer
Severity: High
[customers] Duplicate signup with the same email
Q1 · dedup check
Expected resultOne customer record per unique email
Actual resultCustomer id 13 is a duplicate of id 1 (same name, same email) — the kind of bug that splits order history and loyalty status across two accounts
Severity: Medium
[customers] Missing required email field
Q2 · required-field check
Expected resultEvery customer record has a non-null email
Actual resultCustomer id 14 has no email at all — would break order confirmations or password resets for that account
Severity: Medium
[orders] Order with no linked customer
Q5 · foreign-key check
Expected resultEvery order should resolve to a customer
Actual resultOrder 9 has a NULL customer_id — a guest checkout that never got associated with an account, or a broken write
Severity: Medium

↳ Full detail and reasoning for each severity rating in sql/RESULTS.md.

View repository on GitHub → ← Back to QA & Testing