← Bank of America Interview Insights

Bank of America·Data Scientist·Take-home Assignment·Senior

Senior
Jun 2026Remote

Summary

Got sent a SQL-heavy take-home for a Data Scientist role. Four tasks, all tied together around FX conversion and revenue reporting. Felt more like a data engineering screen than anything else, but I guess that's just how these go now.

Questions Asked (4)

Q1

Write a SQL query to convert all transactions to USD using the most recent available FX rate on or before the transaction date (a point-in-time join). Output should include transaction ID, date, customer, product, region, category, segment, USD amount, and a flag for missing FX rates.

Data ModelingProduct Analytics & Metrics
Author's notes

This is the one I spent the most time on.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Use a correlated subquery or a lateral join to find the most recent FX rate on or before each transaction date, then join back to the transactions table. Ensure the output includes all required columns and a flag indicating missing rates, handling NULLs appropriately.

Pro tip: Mention that you would validate the join by checking for duplicate transactions and ensuring the FX rate date is the maximum date <= transaction date, and consider performance implications of indexing the FX rate table on (currency, date).

1. Understand the data and requirements

Identify the transaction table with columns: transaction_id, date, customer, product, region, category, segment, amount, currency. Identify the FX rate table with columns: currency, date, rate_to_usd. Clarify that the most recent rate on or before the transaction date should be used.

2. Design the point-in-time join

Use a LEFT JOIN with a subquery that selects the maximum FX date <= transaction date for each transaction's currency, or use a lateral join to fetch the latest rate. Ensure the join condition includes currency and date <= transaction date.

3. Compute USD amount and missing rate flag

Multiply the transaction amount by the FX rate to get USD amount. Use a CASE statement to flag missing rates (e.g., when FX rate is NULL, set flag to 1 or 'Missing', else 0 or 'Present').

4. Select and format output columns

Include transaction_id, date, customer, product, region, category, segment, USD amount (rounded appropriately), and the missing rate flag. Ensure column names are clear.

5. Validate and optimize

Check for duplicates, ensure correct handling of edge cases (e.g., transactions before earliest FX rate), and suggest indexing on FX table (currency, date) for performance.

Key Points to Mention

  • Point-in-time join concept: using the most recent FX rate on or before the transaction date.
  • Handling missing FX rates with a flag (e.g., LEFT JOIN and CASE).
  • Use of window functions or correlated subqueries for efficiency.
  • Data types and rounding for USD amount.
  • Performance considerations: indexing FX table on (currency, date).
  • Edge cases: transactions before earliest available rate, multiple rates on same date.

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.

Q2

Build a pivot-style monthly revenue report for a three-month window, with product categories as rows and regions as columns, plus a total column. The months must be derived dynamically from the data, not hardcoded.

Product Analytics & MetricsData Modeling
Author's notes

The 'don't hardcode months' part is what makes this annoying.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying the data schema and business context, then outline a SQL-based pivot using conditional aggregation with dynamically derived months. Emphasize data quality checks and performance considerations, and conclude with how you'd validate the report against source data.

Pro tip: Mention that you'd use a CTE to first extract distinct months and then join or filter, ensuring the report automatically adapts to the latest three months without code changes. Also, highlight the importance of handling NULLs and ensuring totals reconcile.

1. Clarify Requirements and Data Schema

Ask about the source tables, column names, date formats, and whether the three-month window is based on the latest data or a specific period. Confirm the definition of 'total column' (e.g., sum across regions).

2. Design the Dynamic Month Extraction

Use a subquery or CTE to select the three most recent distinct months from the data, ensuring they are ordered and limited. This avoids hardcoding and adapts to new data.

3. Construct the Pivot with Conditional Aggregation

Write a query that groups by product category and uses CASE statements or FILTER clauses to sum revenue for each dynamically derived month, aliasing columns appropriately. Include a total column summing across regions.

4. Validate and Optimize

Check for NULLs, ensure totals match, and consider indexing or partitioning for performance. Discuss how you'd test the query with sample data and handle edge cases like missing months.

Key Points to Mention

  • Use of conditional aggregation (CASE WHEN or PIVOT function) to create the pivot structure.
  • Dynamic month derivation via subquery/CTE with ORDER BY and LIMIT to get the latest three months.
  • Handling of NULL values and ensuring they are treated as zero in sums.
  • Inclusion of a total column that sums across all regions for each product category.
  • Data validation steps: comparing totals to source, checking for missing data, and ensuring correct month ordering.
  • Performance considerations: indexing on date and category columns, and avoiding unnecessary sorting.

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.

Q3

For a single target month, return the top customer by USD revenue within each region. Ties should be broken first by the highest individual transaction amount in that month, then by customer ID alphabetically.

Product Analytics & MetricsAlgorithms & Data Structures
Author's notes

Tie-breaking with two criteria in a window function is one of those things that sounds easy until you write it out.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying the schema and assumptions (e.g., single transactions table with customer_id, region, transaction_date, amount_usd). Then outline a SQL solution using a window function to rank customers per region by total revenue, with tie-breakers on max transaction amount and customer_id. Finally, discuss edge cases like ties, missing data, and performance considerations.

Pro tip: Mention that you would validate the result by checking for ties and ensuring the tie-breaking logic is correctly applied, and consider using a CTE for readability and maintainability.

1. Clarify requirements and data model

Ask about the table structure, column names, and whether revenue is already in USD. Confirm the definition of 'top customer' (e.g., by total revenue) and tie-breaking rules.

2. Aggregate revenue per customer per region

Write a subquery or CTE to sum transaction amounts for each customer within the target month and region, also capturing the maximum individual transaction amount.

3. Rank customers within each region

Use a window function like ROW_NUMBER() with PARTITION BY region ORDER BY total_revenue DESC, max_transaction DESC, customer_id ASC to assign ranks.

4. Select top customer per region

Filter the ranked results to only include rows where rank = 1, returning region and customer_id (and possibly revenue for context).

5. Discuss edge cases and performance

Address handling of ties, nulls, and large datasets; suggest indexing on region, transaction_date, and customer_id for efficiency.

Key Points to Mention

  • Use of window functions (ROW_NUMBER, RANK, DENSE_RANK) and the difference between them for tie handling.
  • Importance of partitioning by region and ordering by multiple criteria.
  • Aggregation with SUM and MAX to compute total revenue and max transaction amount.
  • Filtering for the target month using date functions (e.g., DATE_TRUNC, EXTRACT).
  • Consideration of data types and currency conversion if revenue is not already in USD.
  • Performance optimization: indexing, avoiding unnecessary subqueries, and using CTEs for readability.

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.

Q4

Identify transactions where no FX rate exists within the 30 days prior to the transaction date for non-USD currencies. Explain briefly how you would monitor this gap in a production environment.

Root Cause AnalysisSystem Design
Author's notes

The 30-day window is a tighter constraint than the earlier task, which just said 'on or before.' So a transaction could have a valid rate for the point-in-time join but still fail this check if the rate is older than 30 days.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying the data model: transactions table with currency and date, and an FX rates table with currency pairs and dates. Then describe a SQL-based approach using a LEFT JOIN or NOT EXISTS to find transactions where no rate exists in the 30-day window. Finally, outline a production monitoring strategy with automated checks, alerting, and dashboards.

Pro tip: Mention that you would exclude USD transactions early to avoid unnecessary computation, and that you would consider using a calendar table to handle weekends/holidays when FX rates might not be published.

1. Clarify data sources and requirements

Identify the transactions table (with transaction_id, currency, transaction_date) and the FX rates table (with currency_pair, rate_date, rate). Confirm that 'non-USD currencies' means the transaction currency is not USD, and that the FX rate needed is for converting that currency to USD (or another base).

2. Design the query logic

Use a LEFT JOIN or NOT EXISTS to find transactions where no FX rate exists for the same currency within the 30 days prior to the transaction date. Ensure the date range is inclusive of the transaction date minus 30 days up to the day before the transaction date (or including it, depending on business rules).

3. Write and optimize the SQL

Write a query that filters out USD transactions, then checks for missing rates. Use a subquery or CTE to pre-filter FX rates to the relevant date range for efficiency. Consider indexing on currency and date columns.

4. Monitor in production

Set up a daily or hourly job that runs the query and alerts if any transactions are found. Use a dashboard to visualize gaps over time, and track metrics like count of missing rates per currency. Implement data quality checks and SLA for resolution.

5. Handle edge cases and remediation

Address weekends/holidays by using a calendar table or business day logic. Define a process for backfilling missing rates or flagging transactions for manual review. Consider fallback rates or interpolation if allowed.

Key Points to Mention

  • Use of LEFT JOIN or NOT EXISTS to identify missing FX rates.
  • Date range logic: 30 days prior to transaction date, excluding USD.
  • Performance considerations: indexing, filtering early, avoiding full table scans.
  • Production monitoring: automated alerts, dashboards, and data quality checks.
  • Handling non-business days and rate publication schedules.
  • Remediation steps: backfilling, fallback rates, or manual review.

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.