Interview guides · Massachusetts General Hospital
Massachusetts General Hospital Data Scientist Interview Questions & Guide 2026
Metric-diagnosis practice for Massachusetts General Hospital data scientist candidates: a number moves week over week and you work out why, splitting by segment, ruling out a logging or release change, and separating a mix shift from a real change in user behaviour before naming a cause.
The 60-second brief
The role of a Data Scientist at Massachusetts General Hospital (MGH) is pivotal in leveraging data to enhance healthcare outcomes and operational efficiency. As a leading healthcare institution, MGH relies on data-driven insights to inform clinical decisions, research initiatives, and patient care strategies. Data Scientists at MGH contribute to critical projects that span various domains, including patient analytics, predictive modeling, and clinical research, ultimately aiming to improve patient outcomes and enhance the quality of care provided.
Coding rounds for this role are usually data-manipulation shaped rather than data-structure shaped: group-bys, joins, time windows, ranking within a partition. Confirm the format before spending a week on graph traversal.
Focus areas
- Minimise protected health information in every extract
- Risk-adjust outcomes before comparing providers or panels
- Build member-month denominators from overlapping coverage spans
Overview
In this role, you will engage with complex datasets, employing advanced statistical methods and machine learning techniques to generate actionable insights. You will collaborate with interdisciplinary teams, including clinicians, researchers, and IT professionals, to develop solutions that directly impact patient care and operational processes. The work is both challenging and rewarding, as you will be at the forefront of innovations that shape the future of healthcare delivery.
The Massachusetts General Hospital interview process
Massachusetts General Hospital candidates report 5 rounds · ≈ 4-6 weeks. The stages below are what candidates describe, not a published process.
Initial Screen
A screening call is a matching exercise run by someone who will not evaluate your statistics. They are checking that the work described on your resume is work you personally did, and that its scope matches the level the role is written for. Logistics get settled in the same half hour so nobody spends an interviewer's afternoon on a mismatch. The answer that fails is the one narrated in the plural. If every sentence is 'we built' and 'the team decided', there is nothing specific to write down about you. Name the piece that was yours, the decision you made inside it, and what changed after.
What to demonstrate
- Whether the ownership implied by your resume survives one round of follow-up about who actually did which part
- Whether your described scope (data size, stakeholders, what shipped) matches the seniority the role is written at
- Whether timeline, location and compensation expectations make the rest of the loop worth scheduling
How to prepare
- Rewrite your top three resume bullets in the first person singular, each with the decision you made and what moved afterwards, then say them out loud once so the 'we' does not return under pressure
- Attach one number to each project: the baseline, the change, and the window it was measured over. Where impact was never measured, say that plainly rather than inventing a figure
- Settle your compensation range before the call and give it as a range with a reason behind it, such as current total comp or a competing timeline, instead of deflecting the question twice
Technical Assessment
Before anything else, this round is a reading test. You are given a small schema and a question phrased in business language, and most of the difficulty sits in the gap between them. Who counts as an active user, does a refunded order still count as an order, is that date column an event time or a load time. Weak answers start typing immediately and compute something precise about the wrong population. Strong ones pin the definition in one sentence, name the column that encodes it, then write the query. On a timed assessment with nobody to tell, write the definition in a comment anyway.
What to demonstrate
- Whether an ambiguous term becomes a specific column and filter before any computation happens
- Whether you read the schema for keys and cardinality rather than only for column names
- Whether the result answers the question at the grain it was asked at, per user or per session or per day
How to prepare
- Take three metrics you already use and write down the exact filter and exact grain behind each, then practise stating one of them in a single sentence out loud
- On a schema you have never seen, spend the first minute writing what one row of each table means and which key it is unique on, then predict which joins can duplicate rows
- Rehearse a version where the definition changes halfway through, and edit the query you have instead of starting over
Behavioral Interview
This round decides whether you owned a decision or watched one happen nearby. Interviewers for data roles listen for the point where the analysis stopped being a report and started changing what someone did, so build each story around that hinge: what was going to happen by default, what you found, and what happened instead. The most common weakness is a story that ends at delivery. If you can name the decision your work changed and the number that moved because of it, most follow-ups become easy.
What to demonstrate
- Whether the decision was yours to influence, or whether you are narrating a team outcome in the first person
- The counterfactual: what would have been done without your analysis, and why that default was worse
- How far your involvement ran past the handoff, and whether you checked that the change did what you predicted
How to prepare
- Pick three projects and write one sentence for each naming the decision-maker, the choice in front of them, and what they chose after seeing your work. If you cannot name a person and a choice, the story is not ready for this round.
- Reconstruct the baseline for your strongest project from the original query or dashboard rather than memory, so the before-number survives a follow-up asking where it came from.
- Prepare an honest version of a project where your recommendation was overruled, including what you did with the analysis afterwards.
Final Discussions
Where a loop ends with a senior leader, that conversation is rarely another skills test. The technical signal already exists by then, so the questions tend to open up: what you would look at first, where a metric you have heard about could mislead, what you would push back on. The decision being made is scope, which in practice means level and how much you would be trusted to own unsupervised. Treating it as a formality is the usual mistake. An open question late in the day is still being scored, and a vague answer reads as someone who has not run anything themselves.
What to demonstrate
- Whether your view of the business has anything specific behind it, given that you are working only from what is public and are expected to say so
- Whether the scope of work you describe owning matches the scope of the role, instead of sitting a level below it
- Whether you can disagree with something concrete and stay useful about it, rather than agreeing with everything said in the room
- Whether your questions are ones only this person could answer, as opposed to ones the recruiter already covered
How to prepare
- Build one view you could defend for two minutes using only public information: what the funnel probably looks like, which metric likely drives decisions, and where that metric could mislead. Being wrong for a stated reason survives this round; having no view does not
- Write down the largest piece of work you have owned from question to decision, who else touched it, and what you decided alone, then check that it reads at the level you are interviewing for
- Prepare one thing you would want changed if you joined and phrase it as a question rather than a verdict, so it opens a conversation instead of closing one
Offer Discussion
An extra round usually exists because something is still open after the standard loop: a skill the earlier interviews did not sample, a level decision, or two interviewers who disagreed. It is rarely a rerun of what you already did well. Ask the recruiter who you are meeting, what function they sit in, and how long the session runs. That is an ordinary scheduling question, and the answer changes what you should prepare. What separates a strong candidate here is treating the round as a fresh evaluation with its own bar, rather than assuming earlier performance carries you through or sinks you.
What to demonstrate
- Whether you can answer well on ground the earlier rounds did not cover, without leaning on what you already said to someone else
- Consistency of the facts in your stories: the same sample size, timeframe, team size and scope of your own role as in earlier conversations
- How you handle an unfamiliar format live, including whether you ask what kind of answer is wanted before producing one
How to prepare
- Ask the recruiter for the interviewer's function, the length, and whether to expect a coding surface, a discussion, or a presentation. Preparing for a 30 minute conversation with a partner team is not the same work as preparing for a 60 minute technical block.
- Write out what each earlier round actually covered, then list the two or three areas nobody probed. That gap is the most likely subject of the extra round.
- Re-read the numbers in the project stories you have already told, so a second telling does not quietly contradict the first.
Where candidates lose points
Treating clinical measurements as missing at random
A lab result, a vital sign, or a screening exists because someone ordered it, and ordering tracks suspicion of disease, visit frequency, and site workflow. Imputing the mean or dropping incomplete rows biases the population estimate and can flip the sign of an association, because the untested are systematically healthier or systematically disengaged. The presence indicator is often more predictive than the value, which is a warning sign rather than a feature win: a model that learns test ordering will not transfer to a site with different protocols.
Pre-post evaluation on a high-cost or high-risk cohort
Cohorts selected on an extreme value of the outcome regress toward the mean on their own. Members identified as the top 1 percent of spend in one year spend far less the next, whether or not anyone intervenes, because the selecting year captured both chronic severity and one-off events. A pre-post design on such a cohort will report savings every time. A concurrent comparison group selected by the same rule in the same period, or a regression discontinuity at the selection threshold, is the minimum credible design.
Explaining an aggregate move without decomposing the mix shift
Split the change in the aggregate into within-segment movement and movement in segment weights before you explain it. Every segment's rate can fall while the overall rate rises, purely because volume shifted toward segments that already had higher rates.
Building features from data that postdates the prediction time
Check every feature against the timestamp at which the model would actually score, and drop anything computed from a window that includes or follows the label event. For a forecasting use case, split train and test by time rather than at random, and split by entity when the same entity recurs.
Questions & practice
Given a dataset, write a Python function that calculates the mean and standard deviation of a specified column.
Medium · statistics and probability
Approach
- Sanity-check the answer against a simple bound or a simulated case.
- Quantify uncertainty explicitly rather than reporting a point estimate alone.
- Translate the result into the decision it informs, in one plain sentence.
Follow-up
- How would you explain this result to someone who does not know statistics?
- Which assumption here is most likely to be violated in practice?
Describe the bias-variance tradeoff in machine learning.
Medium · machine learning and modelling
Approach
- Set a baseline first, so any model has something honest to beat.
- Frame the prediction: the label, the moment of prediction, and the action it triggers.
- Say how the offline result would be validated online before it is trusted.
Follow-up
- Where could label leakage enter this setup?
- What would you monitor after launch to know the model is still valid?
How do you control for overfitting in a regression model?
Medium · machine learning and modelling
Approach
- Set a baseline first, so any model has something honest to beat.
- Frame the prediction: the label, the moment of prediction, and the action it triggers.
- Say how the offline result would be validated online before it is trusted.
Follow-up
- How would you choose the decision threshold, and who owns that choice?
- What would you monitor after launch to know the model is still valid?
Sessionise transfer chains into episodes, then count readmissions
Hard · sessionisation · cumsum grouping · readmission
encounter has encounter_id, patient_id, facility_id, encounter_type, admit_ts, discharge_ts, admission_type, discharge_disposition, is_planned_admission, principal_diagnosis_code. Chain acute-to-acute transfers into episodes of care: an inpatient encounter discharged as transfer_acute, followed by another inpatient encounter for the same patient at a different facility admitting within 24 hours of that discharge, belongs to the same episode. Then compute the 30-day unplanned readmission rate over episodes, excluding index episodes that are planned, that end in expired, hospice or against medical advice, or that are still open. Return encounter_id to episode_id, plus the rate.
Approach
- Restrict to inpatient encounters for the chaining step and sort by patient_id, admit_ts. Observation and emergency encounters are not acute inpatient stays and pooling them changes both the chain and the denominator.
- Build a boolean continues flag: the previous row is the same patient, its discharge_disposition is transfer_acute, its facility_id differs from this row's, and admit_ts minus previous discharge_ts is between 0 and 24 hours. Episode id = cumsum of the negation of that flag. This is the vectorised form of a sessionisation loop and is why the pattern generalises to any event stream.
- Collapse to episode grain taking first admit_ts, last discharge_ts, last discharge_disposition, and any() of is_planned_admission. The episode inherits its exit state, not its entry state, which is why a transfer chain ending at home is one home discharge rather than two transfers.
- Apply index exclusions at episode grain. Dropping episodes that end in death is not optional: a dead patient cannot be readmitted, so leaving them in inflates the denominator and depresses the rate for exactly the panels caring for the sickest members.
- For each surviving index episode, find the next unplanned acute inpatient episode for that patient admitting within 30 days of the index discharge_ts. Count events at episode grain, since one patient can contribute several index episodes. Report the raw rate and say plainly that it is not comparable across panels without risk adjustment, which is what the observed-over-expected form exists for.
Worked solution (45 min)
- Filter to encounter_type 'inpatient', sort by patient_id and admit_ts, and shift discharge_ts, discharge_disposition, facility_id and patient_id by one row.
- Compute continues as same patient AND prior disposition is transfer_acute AND facility differs AND 0 <= (admit_ts - prior discharge_ts) <= 24 hours; episode_id = (~continues).cumsum().
- Aggregate to episodes: first admit_ts, last discharge_ts, last discharge_disposition, any planned flag, patient_id.
- Drop index-ineligible episodes: planned, disposition in expired, hospice or ama, and null discharge_ts.
- For each eligible index episode, search the same patient's later episodes for an unplanned admit_ts within 30 days of index discharge_ts; a merge_asof on patient with a forward direction and a 30-day tolerance does this without a nested loop.
- Rate = index episodes with an event divided by eligible index episodes; return the encounter-to-episode map alongside it.
Expected result: Two outputs: an encounter_id to episode_id map, and one rate. Worked case: encounter A discharged transfer_acute at 10:00, encounter B admitted 14:00 the same day at a different facility and discharged home on day 5, encounter C an unplanned admission on day 20. A and B form one episode, C is a readmission of it, and the patient contributes one eligible index episode and one event, not two indexes and possibly two events.
Verify it yourself
- Every closed episode ends in a disposition other than transfer_acute; an episode ending in transfer_acute means a chain was cut early.
- Episode count is less than or equal to inpatient encounter count, with equality only when the sample contains no transfers.
- Turning the chaining rule off raises the readmission rate. The direction of that change is the proof your chaining fired at all.
- No index episode's matched readmission is an encounter already inside that same episode.
Follow-up
- discharge_ts is null on an open stay in the middle of a chain. What does your flag do, and what should it do?
- A patient is transferred out and then back to the originating facility within 24 hours. Should that chain, and does your facility_id condition handle it?
- Is a readmission itself eligible to serve as a later index episode? Say what you chose and what the choice does to the rate.
Write a SQL query to find the top 10 patients with the highest number of visits.
Medium · sql and data manipulation
Approach
- State the window function and its partition and ordering out loud before writing it.
- Say which table is the grain you start from, and join outward from it.
- Handle the rows that do not match: a LEFT JOIN with a NULL check is usually the question.
Follow-up
- How would you verify this result without re-running the same query?
- What breaks if events arrive late or out of order?
Create a Python script to visualize a dataset using a library of your choice.
Medium · sql and data manipulation
Approach
- State the window function and its partition and ordering out loud before writing it.
- Handle the rows that do not match: a LEFT JOIN with a NULL check is usually the question.
- Say which table is the grain you start from, and join outward from it.
Follow-up
- How would you verify this result without re-running the same query?
- How does the query change if the join becomes one-to-many?
How would you optimize a slow-running SQL query?
Medium · sql and data manipulation
Approach
- Compute rates by summing numerator and denominator separately, never by averaging rates.
- Handle the rows that do not match: a LEFT JOIN with a NULL check is usually the question.
- Check whether any join is one-to-many before aggregating, or the sums inflate.
Follow-up
- What breaks if events arrive late or out of order?
- How does the query change if the join becomes one-to-many?
Count thirty-day unplanned readmissions without counting transfers
Medium · self-join · event streams · exclusions
encounter holds encounter_id, patient_id, facility_id, encounter_type, admit_ts, discharge_ts, admission_type, discharge_disposition, is_planned_admission and index_encounter_id. For inpatient stays discharged between 2025-01-01 and 2025-11-30, return the 30-day unplanned readmission rate overall and by facility_id. Exclude an index stay when is_planned_admission is TRUE or discharge_disposition is transfer_acute, expired, hospice or ama. A qualifying readmission is any unplanned inpatient admission for the same patient with admit_ts after the index discharge_ts and within 30 days of it. One stay can be both a readmission and the next index stay.
Approach
- Decide between LEAD and EXISTS explicitly and say why. LEAD over the patient's admission stream gives the literal next stay, so an intervening planned admission hides a later unplanned one. The measure asks whether any unplanned admission fell in the window, which is an EXISTS or a self-join with a range predicate.
- Exclude transfers at the index end before anything else. An acute-to-acute transfer closes one encounter and opens another at a different facility_id within hours, so without the transfer_acute exclusion the facilities that move the sickest patients out look the worst.
- Apply the index exclusions as a set, including stays with NULL discharge_ts, which are still open and have no measurable window.
- Stop the denominator early enough that every index stay had a full 30 days of observation plus encounter lag. That is why the window ends 2025-11-30 rather than at year end.
- Compute the rate at stay level, not patient level, then compare the raw facility rates against an observed-over-expected framing before anyone publishes a ranking.
Worked solution (30 min)
- CTE ip: inpatient encounters with a non-null discharge_ts.
- CTE index_stays: ip rows with discharge_ts in the window, is_planned_admission FALSE, and discharge_disposition not in the four excluded values.
- Flag each index stay with EXISTS against ip for the same patient_id where is_planned_admission is FALSE, encounter_id differs, admit_ts > index.discharge_ts and admit_ts <= index.discharge_ts + 30 days.
- Aggregate numerator and denominator overall and grouped by facility_id.
- Re-run with the transfer exclusion removed and record how much the rate moves.
Expected result: Eligible index stays, stays with a qualifying readmission, and the quotient, overall and per facility_id. Removing the transfer exclusion returns a higher rate, and the gap between the two is a number you should be able to quote.
Verify it yourself
- Numerator never exceeds denominator, and an index stay with two qualifying readmissions still contributes exactly one.
- No index stay in the output has discharge_disposition transfer_acute, expired, hospice or ama.
- A 0-day window gives a rate of exactly 0, and a 365-day window gives a rate no lower than the 30-day one.
- Facility rates weighted by facility denominators reconcile to the overall rate.
Follow-up
- A patient has three stays ten days apart. How many index stays and how many readmissions, and why does the answer depend on the stated rule?
- Which comparison would you publish across facilities, raw rate or observed over expected, and what does risk adjustment still fail to fix?
- index_encounter_id already exists on the table. Would you trust it, and how would you audit it against your own logic?
How do you prioritize tasks when facing multiple deadlines?
Medium · product sense and metrics
Approach
- State what result would change your recommendation, so the answer is falsifiable.
- Name one primary metric, then the guardrail that stops it being gamed.
- Decompose the metric into the rates that drive it, and say which one you would check first.
Follow-up
- What would you do if the primary metric and the guardrail moved in opposite directions?
- How would you detect that the metric is being gamed rather than genuinely improving?
Explain the concept of cross-validation and why it is important.
Medium
Approach
- Say what you would check first and why it is the highest-information step.
- State your assumptions explicitly before working the problem.
- Work from the decision backwards to the evidence you would need.
Follow-up
- How would you know your answer was wrong?
- What assumption would you test first?
Critique a denial rate slide before it is shown
Easy · metric critique · claim versions · runout · mix shift
A weekly slide says first-pass denial rate improved from 9.1 percent to 7.4 percent month over month. It was computed from medical_claim_line as rows with claim_status 'denied' divided by all rows with a received_date in the month. You cannot query anything. List every assumption the number rests on, restate the metric so two analysts computing it independently would get the same value, and give the three questions you would ask before the slide is presented.
Approach
- Work the grain first. The denominator counts all rows, so a claim resubmitted after a denial contributes its original line, its replacement (frequency_code 7) and possibly a void (8). Both numerator and denominator are inflated by exactly the claims most likely to have been denied, which makes the rate a function of resubmission behaviour rather than adjudication.
- Work maturity second. A line received late in the month may still be pended at extract time, and pended lines are neither paid nor denied. If pends resolve to denials later, the most recent month is understated by construction, which looks exactly like improvement. Ask for the paid-through date and the adjudication runout hold.
- Work the unit third. A denial rate on claim lines and a denial rate on claims are different numbers, and a single denied line on a twenty-line facility claim is a different operational event from a wholly denied professional claim. The spec has to pick one and say so.
- Work mix fourth. Denial reasons have different owners and different volumes: eligibility denials belong to enrollment operations, coding denials to provider relations. A shift in submission mix across providers, place of service or reason code moves the blended rate with no change in any component, so the restated metric reports by denial_reason_code group.
- Work precision last. A 1.7 point move is decisive on two million lines and meaningless on three thousand. The restated metric carries the denominator count, and a slide without it cannot be read.
Worked solution (15 min)
- Write the assumption list as a numbered set: single version per claim, adjudication complete at extract, line grain intended, stable reason-code and provider mix, denominator large enough for the move to be real.
- Restate the metric with numerator as lines denied at first adjudication, denominator as lines received in the month counted at claim_version 1, reported by received_date month, held 60 days, broken out by denial_reason_code group, and published with the denominator count.
- Write the three questions in the order that would kill the slide fastest: what is the paid-through date, how many lines are in each month's denominator, and did the reason-code mix move.
- State how the restated number is presented, with the most recent month marked provisional and restated at each refresh.
Expected result: A restated specification reading: numerator is claim lines whose first adjudication returns claim_status denied; denominator is lines with received_date in month M counted at claim_version 1; the month is held until 60 days of adjudication runout have passed; the rate is broken out by denial_reason_code group; and both the denominator count and the paid-through date appear on the slide, with the most recent month marked provisional. The three questions are the paid-through date, the denominator size, and whether reason-code mix shifted.
Verify it yourself
- The restated denominator must be smaller than the original, since version-1 filtering can only remove rows. If it is not, the version filter is not doing anything.
- Both months should be recomputable at the same paid-through age; comparing a mature month to a two-week-old month is the defect the hold is meant to prevent.
- The reason-code breakout should sum back to the blended rate, which is the check that the mix decomposition is complete.
Follow-up
- The rate is still down after version dedup and a 60-day hold. What is the next thing you check before anyone celebrates?
- Which of these problems would also affect a paid-amount series computed the same way?
- How would you present the restated number so the audience understands the prior month is provisional?
Glycemic control share jumped when a feed connected
Medium · informative missingness · unit mismatch · metric specification
The share of members with a controlled glycemic result moved from 0.62 to 0.81 the month a second result feed was connected. lab_result carries result_id, order_id, patient_id, encounter_id, loinc_code, analyte_name, value_numeric, units, reference_low, reference_high, abnormal_flag, result_status and supersedes_result_id. The metric is members whose latest result in the year is below the control threshold, divided by members with any result in the year. Decide whether control actually improved, and specify the metric so results from both feeds can be pooled.
Approach
- Split numerator and denominator. The denominator is members with any result, so a feed that tests more people changes the metric without changing anyone's health. Count denominator members before and after and see how much of the 19 point move is denominator growth.
- Recompute on a fixed cohort: members who had a qualifying result in both the before and after periods. If the share is flat on the fixed cohort, the movement is who got tested, not what their results were.
- Deduplicate to the latest non-cancelled row per (order_id, loinc_code), respecting supersedes_result_id, because a corrected result arrives as a new row and counting both gives one person two values.
- Audit units and loinc_code mix by feed. Two unit conventions coexist for this analyte, percent and mmol/mol, related by mmol/mol equal to 10.929 times (percent minus 2.15), so 7.0 percent is 53 mmol/mol. Comparing mmol/mol values to a percent threshold would classify them all as uncontrolled and depress the share, so a rise cannot be explained by that mismatch, which rules it out rather than in.
- State plainly that the tested population is not the covered population. Testing is ordered when someone suspects a problem or when a site runs standing orders, so the mean among tested members is not the population mean and cannot be made into one by imputation.
- Respecify: numerator and denominator both restricted to members with a stated continuous-enrolment requirement, one deduplication rule, one unit after conversion, one threshold, and a separately reported testing rate so the denominator's movement is visible.
Follow-up
- Someone proposes imputing the mean result for untested members. What happens to the estimate and why?
- A model you are building gains AUC from a feature that marks whether the test exists. Why is that a warning rather than a win?
- How would you report this metric so a clinical committee can see improvement separately from coverage of testing?
Suggested practice checklist
For someone who has spent the last year in notebooks, dashboards or modelling work and has not written raw SQL under time pressure. The first four days rebuild query fluency against a fixture you control and can verify by hand; the last three attach that fluency to the rest of the loop.
Day 1 — Build a fixture you can check answers against
- Create a local Postgres or SQLite database with four tables (users, sessions, events, orders) holding roughly 200 rows you generated yourself, so you know the contents well enough to predict every result.
- Deliberately seed the cases that break queries: a user with no sessions, a session with no events, two orders sharing a timestamp, a NULL in one join key, and one duplicated user row.
- Before writing any SQL, hand-compute five answers on paper (how many users placed at least one order, median orders per ordering user, and three others) and save them as the ground truth for the week.
Deliverable: A one-command seed script plus a text file of five hand-computed answers to grade every later query against.
Day 2 — Joins, filters and NULL semantics
- Answer "which users have no orders" three ways (LEFT JOIN with IS NULL, NOT EXISTS, NOT IN) and confirm that the NOT IN version returns zero rows once the subquery contains a NULL, because the comparison is never TRUE.
- Reproduce the LEFT JOIN that silently collapses to an inner join by putting a right-table predicate in WHERE, then fix it by moving the predicate into the ON clause, and record both row counts.
- Create a fan-out bug on purpose by joining orders to order_items and summing the order total, then correct it with a pre-aggregated subquery and explain in one line which table changed the grain.
Deliverable: One annotated .sql file holding the three join traps, each with the wrong result and the corrected result side by side.
Day 3 — Window functions and frames
- Write three window queries against the fixture: a running order total per user, the rank of each order within its user by value, and the day gap to that user's previous order, then check each against the day-one ground truth.
- Run ROW_NUMBER, RANK and DENSE_RANK over a column containing ties, print all three side by side, and write one sentence on when each is the correct choice.
- Switch one query from the default frame (RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW, which is what you get when ORDER BY is present and no frame is written) to ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW, and explain why the output differs only when the ORDER BY column has duplicates.
Deliverable: Three verified window queries plus a short note explaining the RANGE versus ROWS difference in your own words.
Day 4 — The four analytical query patterns
- Write a monthly retention grid: first order month per user, then months-since-first as the column, and verify that month zero equals the cohort size exactly.
- Sessionize the events table under a 30-minute inactivity rule using LAG plus a cumulative sum over a new-session flag.
- Build a four-step funnel that counts distinct users rather than events at each step, and state the rule you applied to a user who reaches step three without ever logging step two.
Deliverable: One file with the retention, sessionization and funnel patterns, each carrying a one-line note on the assumption it bakes in.
Day 5 — Write SQL the way you will have to write it live
- Set a 12-minute timer and solve three medium prompts in a plain editor with no execution and no autocomplete, then run them and tally syntax errors separately from logic errors.
- Narrate one solution aloud while writing it, stating the grain of each intermediate result (one row per user, one row per user-day) before you type its body.
- Rewrite your slowest solution as a CTE chain where every CTE name states its grain, and time yourself re-solving it from blank.
Deliverable: A recording of one narrated solution plus an error tally that separates syntax from logic.
Day 6 — One day for everything that is not SQL
- Write the preconditions of the two-sample t-test from memory, then check them: independent observations, and a difference in means whose sampling distribution is approximately normal, which at large sample sizes follows from the central limit theorem rather than from normality of the raw values.
- Write the difference between an odds ratio from logistic regression and a relative risk, and state the condition under which the two are close (low outcome prevalence).
- Prepare a 90-second answer to "how would you know this model is any good" that names the metric, the baseline you would beat, and the cost of the errors you care about.
Deliverable: One page of notes covering test preconditions, the odds-ratio caveat and the model-quality answer.
Day 7 — Full loop rehearsal
- Run a 45-minute mock with someone willing to interrupt: 20 minutes of SQL, 15 minutes defining a metric, 10 minutes on a past project.
- Re-solve from blank the two queries you were slowest on this week and compare the times against day five.
- Write a five-line answer to "walk me through a project" that puts a number in the first sentence and names the decision the work changed.
Deliverable: Mock feedback notes plus a timed project narrative you can deliver without reading it.
The project you argued against
Saying no well is a senior skill and it is rarely rehearsed. Think of a time you told someone their analysis was not worth doing, or that the experiment could not answer their question at the sample size available. Explain what you offered instead. Refusal without an alternative reads as obstruction rather than judgement.
Tell me about a time you worked on a challenging team project. What was your role?
Medium · behavioural and stakeholder questions
Approach
- Quantify the outcome, including what you would not claim credit for.
- Close with what you would do differently, concretely.
- State the situation in two sentences and spend the rest on your reasoning.
Follow-up
- What did you decide not to do, and why?
- How did you know the outcome was caused by your change?
Scope a one-line request for a readmission rate
Easy · scoping · measure specification · stakeholder communication
A clinical operations lead messages you: 'What is our readmission rate? The committee meets Friday.' You have encounter (encounter_id, admit_ts, discharge_ts, encounter_type, admission_type, discharge_disposition, drg_code, index_encounter_id) and member_enrollment coverage spans. Do not open a query editor yet. Deliverable: the three to five questions you send back, ranked by how much the answer moves the number; the default specification you will build if nobody replies by Wednesday; and the one line you will place under the figure so the committee does not read it against a published benchmark.
Approach
- Read the probe: this tests whether you convert ambiguity into a specification without either stalling or guessing silently. Both failure modes are common, and the silent guess is worse because nobody can see it.
- Rank your questions by leverage on the number rather than by curiosity. Whether the numerator is all-cause or unplanned, and whether the clock starts at discharge_ts, move the result far more than a tie-break rule on same-day returns.
- Ask about the comparison first. A number going to a committee will be compared to something, and whether that something is last quarter, another panel, or a national figure decides whether you owe them a raw rate, a risk-adjusted rate, or an observed-over-expected ratio.
- Commit to a default in writing so silence does not block you: unplanned acute inpatient readmission within 30 days of discharge_ts, index stays excluding planned admissions, acute-to-acute transfers, discharges against medical advice, and dispositions of expired or hospice, denominator of eligible index discharges, paid-through date stated.
- Write the caveat as a restriction on use rather than a hedge: name the one comparison the figure supports and the one it does not.
Follow-up
- They reply that they want it 'the way the benchmark does it'. What do you ask next?
- The committee wants it split by attending provider. What changes in the specification, and what do you refuse to show?
- How does your answer change if the meeting is tomorrow rather than Friday?
Disagree with a product manager about an adherence nudge
Medium · immortal time · confounding · disagreement
A product manager proposes shipping a refill-reminder feature to the whole member base, citing an internal analysis: members with 12-month proportion of days covered at or above 0.80 had 31 percent fewer admissions than members below it. The roadmap date is three weeks out and engineering is scoped. You believe the comparison builds survival and continuous coverage into the exposure definition, and is separately confounded by the kind of member who refills on time. Deliverable: what you say in the room, what you send afterwards, and the smallest study you would accept as sufficient to ship.
Approach
- The probe is whether you can be specific and non-territorial at once. A disagreement that arrives as 'the analysis is flawed' costs you the room; one that names a mechanism and offers a cheaper path keeps it.
- Name the two defects separately, because they have different fixes. Classifying a member as adherent over 12 months requires them to stay alive and stay covered for those 12 months, and that guaranteed event-free interval is assigned to the adherent group. Separately, members who refill on schedule differ from those who do not in ways claims never record.
- Show rather than assert. Rerun the same comparison as a landmark analysis: classify adherence over days 1 to 90, start follow-up at day 91 for everyone still enrolled and event-free, and report how much of the 31 percent survives.
- Separate the association claim from the intervention claim out loud. Nothing in the analysis speaks to whether a reminder changes refill behaviour, which is the actual product question and is separately testable.
- Offer the shippable path: a randomised holdout on a subset with proportion of days covered as the primary endpoint, powered on the plausible effect of a reminder rather than on the 31 percent, with a stated read date.
Follow-up
- The landmark rerun still shows a 20 percent difference. Do you ship?
- The product manager says a holdout delays launch. How do you cost that argument?
- What primary endpoint do you choose, and why not admissions?