Add complete financial fraud detection database with Docker, schema, data generation, and SQL exercises

- Docker setup with PostgreSQL 16 and DB-UI web interface
- Comprehensive 20+ table schema with fraud detection patterns
- Idempotent shell scripts for data generation (no Python dependency)
- Realistic geographic data (100 US cities, 210 world cities)
- 5M+ transactions with embedded fraud patterns (velocity, geographic, structuring, etc.)
- Progressive SQL exercises from beginner to advanced fraud detection
- Complete documentation and quick start guide
- Setup and verification scripts
This commit is contained in:
Alphaeus Mote
2025-10-23 13:53:30 -04:00
parent 9d9104a4fe
commit b30733ccad
15 changed files with 3864 additions and 2 deletions
+206
View File
@@ -0,0 +1,206 @@
# Level 1: Basic SQL Queries
## Introduction
Welcome to the Financial Fraud Detection SQL learning path! In this first level, you'll learn the fundamentals of SQL by querying a realistic fraud detection database.
## Learning Objectives
- Understand SELECT statements
- Use WHERE clauses for filtering
- Sort results with ORDER BY
- Limit result sets
- Work with basic comparison operators
## Exercises
### Exercise 1.1: View All Customers
**Objective:** Retrieve all customer records
```sql
-- Your query here
SELECT * FROM customers;
```
**Expected Result:** All customer records with all columns
---
### Exercise 1.2: Find a Specific Customer
**Objective:** Find customer with customer_id = 1
```sql
-- Your query here
SELECT * FROM customers WHERE customer_id = 1;
```
---
### Exercise 1.3: High-Risk Customers
**Objective:** Find all customers with a risk_score greater than 80
```sql
-- Your query here
```
**Hint:** Use the WHERE clause with the > operator
**Solution:**
```sql
SELECT customer_id, first_name, last_name, email, risk_score
FROM customers
WHERE risk_score > 80
ORDER BY risk_score DESC;
```
---
### Exercise 1.4: Recent Registrations
**Objective:** Find customers who registered in 2024
```sql
-- Your query here
```
**Hint:** Use WHERE with date comparison
**Solution:**
```sql
SELECT customer_id, first_name, last_name, email, registration_date
FROM customers
WHERE registration_date >= '2024-01-01'
ORDER BY registration_date DESC;
```
---
### Exercise 1.5: Inactive Accounts
**Objective:** Find all inactive customer accounts
```sql
-- Your query here
```
**Solution:**
```sql
SELECT customer_id, first_name, last_name, email, is_active
FROM customers
WHERE is_active = FALSE;
```
---
### Exercise 1.6: Top 10 Largest Transactions
**Objective:** Find the 10 largest transactions by amount
```sql
-- Your query here
```
**Hint:** Use ORDER BY with LIMIT
**Solution:**
```sql
SELECT transaction_id, account_id, amount, transaction_date, description
FROM transactions
ORDER BY amount DESC
LIMIT 10;
```
---
### Exercise 1.7: Flagged Transactions
**Objective:** Find all transactions that have been flagged for review
```sql
-- Your query here
```
**Solution:**
```sql
SELECT transaction_id, account_id, amount, fraud_score, flagged_reason
FROM transactions
WHERE is_flagged = TRUE
ORDER BY fraud_score DESC;
```
---
### Exercise 1.8: International Transactions
**Objective:** Find all international transactions over $1,000
```sql
-- Your query here
```
**Solution:**
```sql
SELECT transaction_id, account_id, amount, country_id, city
FROM transactions
WHERE is_international = TRUE AND amount > 1000
ORDER BY amount DESC;
```
---
### Exercise 1.9: Specific Merchant Categories
**Objective:** Find all merchants in the 'Gambling' or 'Cryptocurrency' categories
```sql
-- Your query here
```
**Hint:** Join merchants with merchant_categories, use IN or OR
**Solution:**
```sql
SELECT m.merchant_id, m.merchant_name, mc.category_name, m.risk_rating
FROM merchants m
JOIN merchant_categories mc ON m.category_id = mc.category_id
WHERE mc.category_name IN ('Gambling', 'Cryptocurrency')
ORDER BY m.risk_rating DESC;
```
---
### Exercise 1.10: Critical Alerts
**Objective:** Find all open alerts with CRITICAL severity
```sql
-- Your query here
```
**Solution:**
```sql
SELECT alert_id, customer_id, alert_type, description, alert_date
FROM alerts
WHERE severity = 'CRITICAL' AND status = 'OPEN'
ORDER BY alert_date DESC;
```
---
## Challenge Exercises
### Challenge 1.1: PEP Customers
Find all Politically Exposed Persons (PEPs) with high risk scores (> 70)
### Challenge 1.2: Expired Cards
Find all cards that have expired (expiry_date < current_date)
### Challenge 1.3: Large Cash Advances
Find all cash advance transactions over $5,000
---
## Next Steps
Once you're comfortable with these basic queries, move on to:
- **Level 2:** JOIN operations
- **Level 3:** Aggregate functions and GROUP BY
+360
View File
@@ -0,0 +1,360 @@
# Level 6: Fraud Detection Scenarios
## Introduction
Now you'll apply your SQL skills to real-world fraud detection scenarios. These exercises simulate actual fraud investigation tasks.
## Learning Objectives
- Detect velocity fraud patterns
- Identify geographic anomalies
- Find money mule networks
- Detect account takeover attempts
- Identify structuring patterns
---
## Fraud Pattern Detection
### Scenario 1: Velocity Fraud Detection
**Objective:** Find accounts with more than 5 transactions in a 1-hour window
```sql
-- Detect rapid-fire transactions (velocity check)
WITH transaction_windows AS (
SELECT
t1.account_id,
t1.transaction_id,
t1.transaction_date,
t1.amount,
COUNT(t2.transaction_id) as transactions_in_hour
FROM transactions t1
JOIN transactions t2 ON t1.account_id = t2.account_id
AND t2.transaction_date BETWEEN t1.transaction_date - INTERVAL '1 hour'
AND t1.transaction_date
GROUP BY t1.account_id, t1.transaction_id, t1.transaction_date, t1.amount
)
SELECT
account_id,
transaction_date,
transactions_in_hour,
SUM(amount) as total_amount
FROM transaction_windows
WHERE transactions_in_hour > 5
GROUP BY account_id, transaction_date, transactions_in_hour
ORDER BY transactions_in_hour DESC;
```
---
### Scenario 2: Geographic Impossibility
**Objective:** Find transactions from the same card in different countries within 2 hours
```sql
-- Detect impossible travel (card used in different countries too quickly)
SELECT
t1.card_id,
t1.transaction_id as trans1_id,
t1.transaction_date as trans1_date,
c1.country_name as country1,
t1.city as city1,
t2.transaction_id as trans2_id,
t2.transaction_date as trans2_date,
c2.country_name as country2,
t2.city as city2,
EXTRACT(EPOCH FROM (t2.transaction_date - t1.transaction_date))/3600 as hours_between
FROM transactions t1
JOIN transactions t2 ON t1.card_id = t2.card_id
AND t2.transaction_date > t1.transaction_date
AND t2.transaction_date <= t1.transaction_date + INTERVAL '2 hours'
JOIN countries c1 ON t1.country_id = c1.country_id
JOIN countries c2 ON t2.country_id = c2.country_id
WHERE t1.country_id != t2.country_id
ORDER BY hours_between ASC;
```
---
### Scenario 3: Money Mule Network Detection
**Objective:** Find clusters of accounts that transfer money in a chain pattern
```sql
-- Detect potential money mule networks (rapid transfer chains)
WITH transfer_chains AS (
SELECT
tr1.from_account_id as account1,
tr1.to_account_id as account2,
tr2.to_account_id as account3,
tr1.transfer_id as transfer1,
tr2.transfer_id as transfer2,
t1.amount as amount1,
t2.amount as amount2,
t1.transaction_date as date1,
t2.transaction_date as date2,
EXTRACT(EPOCH FROM (t2.transaction_date - t1.transaction_date))/3600 as hours_between
FROM transfers tr1
JOIN transfers tr2 ON tr1.to_account_id = tr2.from_account_id
JOIN transactions t1 ON tr1.transaction_id = t1.transaction_id
JOIN transactions t2 ON tr2.transaction_id = t2.transaction_id
WHERE t2.transaction_date BETWEEN t1.transaction_date AND t1.transaction_date + INTERVAL '24 hours'
)
SELECT
account1,
account2,
account3,
amount1,
amount2,
hours_between,
CASE
WHEN ABS(amount1 - amount2) / amount1 < 0.1 THEN 'SUSPICIOUS - Similar amounts'
ELSE 'Review'
END as risk_flag
FROM transfer_chains
WHERE hours_between < 24
ORDER BY hours_between ASC;
```
---
### Scenario 4: Account Takeover Detection
**Objective:** Find accounts with sudden changes in transaction patterns
```sql
-- Detect account takeover by analyzing behavior changes
WITH customer_baseline AS (
SELECT
a.customer_id,
a.account_id,
AVG(t.amount) as avg_transaction,
STDDEV(t.amount) as stddev_transaction,
COUNT(*) as transaction_count
FROM accounts a
JOIN transactions t ON a.account_id = t.account_id
WHERE t.transaction_date < CURRENT_DATE - INTERVAL '30 days'
GROUP BY a.customer_id, a.account_id
),
recent_transactions AS (
SELECT
a.customer_id,
a.account_id,
t.transaction_id,
t.amount,
t.transaction_date,
t.country_id,
t.device_id
FROM accounts a
JOIN transactions t ON a.account_id = t.account_id
WHERE t.transaction_date >= CURRENT_DATE - INTERVAL '7 days'
)
SELECT
rt.customer_id,
rt.account_id,
rt.transaction_id,
rt.amount,
cb.avg_transaction,
(rt.amount - cb.avg_transaction) / NULLIF(cb.stddev_transaction, 0) as z_score,
CASE
WHEN ABS((rt.amount - cb.avg_transaction) / NULLIF(cb.stddev_transaction, 0)) > 3
THEN 'HIGH RISK - Amount anomaly'
WHEN ABS((rt.amount - cb.avg_transaction) / NULLIF(cb.stddev_transaction, 0)) > 2
THEN 'MEDIUM RISK'
ELSE 'Normal'
END as risk_level
FROM recent_transactions rt
JOIN customer_baseline cb ON rt.account_id = cb.account_id
WHERE cb.transaction_count > 10
ORDER BY ABS((rt.amount - cb.avg_transaction) / NULLIF(cb.stddev_transaction, 0)) DESC;
```
---
### Scenario 5: Structuring Detection (Smurfing)
**Objective:** Find patterns of transactions just under $10,000 (reporting threshold)
```sql
-- Detect structuring - multiple transactions just under reporting threshold
WITH daily_transactions AS (
SELECT
account_id,
DATE(transaction_date) as transaction_day,
COUNT(*) as num_transactions,
SUM(amount) as total_amount,
AVG(amount) as avg_amount,
MAX(amount) as max_amount
FROM transactions
WHERE amount BETWEEN 9000 AND 9999
AND transaction_date >= CURRENT_DATE - INTERVAL '30 days'
GROUP BY account_id, DATE(transaction_date)
)
SELECT
dt.account_id,
c.first_name,
c.last_name,
dt.transaction_day,
dt.num_transactions,
dt.total_amount,
dt.avg_amount,
CASE
WHEN dt.num_transactions >= 3 AND dt.total_amount > 25000
THEN 'CRITICAL - Likely structuring'
WHEN dt.num_transactions >= 2 AND dt.total_amount > 18000
THEN 'HIGH - Possible structuring'
ELSE 'Review'
END as risk_assessment
FROM daily_transactions dt
JOIN accounts a ON dt.account_id = a.account_id
JOIN customers c ON a.customer_id = c.customer_id
WHERE dt.num_transactions >= 2
ORDER BY dt.total_amount DESC, dt.num_transactions DESC;
```
---
### Scenario 6: High-Risk Merchant Analysis
**Objective:** Find customers with unusual activity at high-risk merchants
```sql
-- Analyze transactions at high-risk merchants
SELECT
c.customer_id,
c.first_name,
c.last_name,
c.risk_score as customer_risk,
mc.category_name,
m.merchant_name,
m.risk_rating as merchant_risk,
COUNT(t.transaction_id) as transaction_count,
SUM(t.amount) as total_spent,
AVG(t.amount) as avg_transaction,
MAX(t.amount) as max_transaction
FROM customers c
JOIN accounts a ON c.customer_id = a.customer_id
JOIN transactions t ON a.account_id = t.account_id
JOIN merchants m ON t.merchant_id = m.merchant_id
JOIN merchant_categories mc ON m.category_id = mc.category_id
WHERE m.risk_rating IN ('HIGH', 'CRITICAL')
AND t.transaction_date >= CURRENT_DATE - INTERVAL '90 days'
GROUP BY c.customer_id, c.first_name, c.last_name, c.risk_score,
mc.category_name, m.merchant_name, m.risk_rating
HAVING COUNT(t.transaction_id) > 5 OR SUM(t.amount) > 10000
ORDER BY total_spent DESC;
```
---
### Scenario 7: Card Testing Detection
**Objective:** Find cards with multiple small failed transactions (testing stolen cards)
```sql
-- Detect card testing patterns
SELECT
t.card_id,
c.card_last_four,
COUNT(*) as failed_attempts,
COUNT(DISTINCT t.merchant_id) as different_merchants,
MIN(t.amount) as min_amount,
MAX(t.amount) as max_amount,
MIN(t.transaction_date) as first_attempt,
MAX(t.transaction_date) as last_attempt,
EXTRACT(EPOCH FROM (MAX(t.transaction_date) - MIN(t.transaction_date)))/60 as minutes_span
FROM transactions t
JOIN cards c ON t.card_id = c.card_id
WHERE t.status = 'FAILED'
AND t.amount < 10
AND t.transaction_date >= CURRENT_DATE - INTERVAL '24 hours'
GROUP BY t.card_id, c.card_last_four
HAVING COUNT(*) >= 3
ORDER BY failed_attempts DESC, minutes_span ASC;
```
---
### Scenario 8: Dormant Account Reactivation
**Objective:** Find dormant accounts that suddenly become active (potential takeover)
```sql
-- Detect dormant account reactivation
WITH account_activity AS (
SELECT
account_id,
MIN(transaction_date) as first_transaction,
MAX(transaction_date) as last_transaction,
COUNT(*) as total_transactions
FROM transactions
GROUP BY account_id
),
dormant_accounts AS (
SELECT
account_id,
last_transaction,
total_transactions
FROM account_activity
WHERE last_transaction < CURRENT_DATE - INTERVAL '180 days'
),
recent_activity AS (
SELECT
t.account_id,
COUNT(*) as recent_transactions,
SUM(t.amount) as recent_amount,
MIN(t.transaction_date) as reactivation_date
FROM transactions t
WHERE t.transaction_date >= CURRENT_DATE - INTERVAL '7 days'
GROUP BY t.account_id
)
SELECT
da.account_id,
c.first_name,
c.last_name,
c.email,
da.last_transaction as last_active,
EXTRACT(DAY FROM (CURRENT_DATE - da.last_transaction)) as days_dormant,
ra.reactivation_date,
ra.recent_transactions,
ra.recent_amount,
'CRITICAL - Dormant account reactivated' as alert_type
FROM dormant_accounts da
JOIN recent_activity ra ON da.account_id = ra.account_id
JOIN accounts a ON da.account_id = a.account_id
JOIN customers c ON a.customer_id = c.customer_id
ORDER BY days_dormant DESC;
```
---
## Investigation Exercises
### Exercise 6.1: Full Customer Investigation
Create a comprehensive report for a suspicious customer including:
- All accounts
- All transactions
- All alerts
- All fraud cases
- Related customers (via relationships)
### Exercise 6.2: Fraud Case Summary
Generate a summary report of all open fraud cases with:
- Case details
- Associated transactions
- Total amount at risk
- Investigation status
### Exercise 6.3: Daily Fraud Dashboard
Create a daily dashboard showing:
- New alerts by severity
- High-risk transactions
- Geographic anomalies
- Velocity violations
---
## Next Steps
Congratulations! You've completed the fraud detection scenarios. You now have the skills to:
- Detect complex fraud patterns
- Investigate suspicious activity
- Generate fraud reports
- Analyze customer behavior
Continue practicing with real data and explore advanced topics like:
- Machine learning integration
- Real-time fraud scoring
- Network analysis
- Predictive modeling