cswork / libraryOpen practice workspace

Interview guides · Covera Health

Covera Health Data Scientist Interview Questions & Guide 2026

Diagnose a metric move for Covera Health data scientist prep: split by segment, rule out a logging change, separate mix shift from behaviour.

The 60-second brief

The Data Scientist role at Covera Health is pivotal in leveraging data to enhance healthcare outcomes and drive business decisions. As a Data Scientist, you will be tasked with analyzing complex datasets, deriving actionable insights, and developing models that inform strategic initiatives across various teams. Your work will directly impact the development of innovative healthcare products that facilitate better patient outcomes, making your contributions vital to the company’s mission of improving healthcare delivery.

Ask early whether the loop includes an asynchronous take-home or a timed live case, because the two are graded on different things. A take-home is read as an artifact: the question you decided to answer, what you did about missing or malformed records, and a conclusion stated plainly enough for someone to act on. A reviewer who cannot rerun your notebook discounts the result whatever score is printed in it. Hold to the stated time box and write down what you would have done with more of it, since the follow-up round is usually a live defence of the same work.

Focus areas

  • Separate censoring from events in time-to-event models
  • Correct for claims runout before reporting recent months
  • Reconstruct drug exposure intervals from dispensing records

Overview

This role is particularly engaging due to its emphasis on solving real-world healthcare challenges through data-driven solutions. You will collaborate closely with cross-functional teams, including product management and engineering, to ensure that your analytical insights translate into tangible improvements in patient care. The complexity and scale of the data you will work with provide a stimulating environment that encourages continuous learning and professional growth.

The Covera Health interview process

Covera Health candidates report 4 rounds · ≈ 3-5 weeks. The stages below are what candidates describe, not a published process.

Phone 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 Assessments

A handful of shapes account for most of what gets asked in this format: a ranking or deduplication inside groups, a running or rolling total, a period-over-period comparison, and a cohort tracked forward over time. Recognising the shape quickly is most of the speed here; deriving it from scratch while a clock runs is where the time goes. Know that a window function keeps every row while a GROUP BY collapses them, and know which one the question needs. If the exercise is in Python instead of SQL, the same shapes arrive as groupby with transform, shift and merge, and the same grain mistakes are available.

What to demonstrate

  • Whether you reach the right construct without a detour, such as ROW_NUMBER over a partition to deduplicate instead of a self-join against a MAX subquery
  • Whether you know what your window frame actually is, since adding ORDER BY inside OVER changes the default frame and silently changes a running total
  • Whether the thing runs. A near-miss that throws an error scores below a plainer query that returns the right rows.

How to prepare

  • Write each of the four shapes once from memory against a small schema and keep the working version somewhere you will reread it: dedupe with ROW_NUMBER, a running total, a month-over-month change with LAG, and a retention table
  • Compute one running total twice on data with tied timestamps, once on the default frame and once with ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW, and look at where the two disagree
  • If Python is on the table, rebuild the dedupe and the running total with groupby and cumsum, then assert the two implementations return identical rows

Interviews with Team Leads

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.

Interviews with Senior Data Scientists

An added round often puts you in front of someone outside the core hiring team: a partner engineer, a product owner, a domain expert, sometimes a more senior manager. The question they are really asking is not whether you can do the work but whether they would trust a number that came from you. That changes what a good answer looks like. Lead with what the decision cost and what it changed, keep the method available but not central, and be plain about the limits of your evidence. Overstating a result is the fastest way to lose this round.

What to demonstrate

  • Whether you can explain a technical choice to someone who will never read your code, without either flattening it into nothing or hiding inside jargon
  • Honesty about evidence strength: what the analysis establishes, what it only suggests, and what it cannot say at all
  • How you take disagreement, specifically whether you update on a good objection, hold your position with reasons, or fold on contact

How to prepare

  • Write the two-sentence version of your most technical project for a non-specialist, then check that neither sentence needs a method name to make sense.
  • For one result you are proud of, write the strongest objection someone could raise and a response that concedes the part of it that is correct.
  • Prepare one decision that turned out to be wrong: how you found out, what it cost, and what you changed afterwards. A senior cross-functional interviewer asks for this more often than a technical one does.

Where candidates lose points

Immortal time in adherence, treatment, and enrolment definitions

Classifying members as adherent, treated, or programme-enrolled requires them to survive and stay covered long enough to accumulate the defining events. That guaranteed event-free interval is assigned to the exposed group, so the exposure looks protective for reasons that have nothing to do with the treatment. Adherence studies are the classic case: measuring 12-month proportion of days covered and then comparing mortality builds survival into the exposure definition. Use time-varying exposure or a landmark analysis with the classification window excluded from follow-up.

Ignoring clustering by provider, facility, or site

Patients within a provider panel, and subjects within a trial site, are correlated on both case mix and practice pattern. Standard errors computed as if observations were independent are too narrow by roughly the design effect, 1 + (m - 1) * ICC, where m is the average cluster size. With 50 patients per provider and an intracluster correlation of only 0.02, variance is understated by about a factor of two, which manufactures significant provider differences out of noise. Cluster-robust errors or a random intercept per provider, and cluster-level randomisation when you design the test, are the corrections.

Writing SQL without stating NULL and tie-breaking behaviour

Before calling a query finished, say what it does with NULLs, ties and empty groups. NOT IN against a subquery containing a single NULL returns no rows at all, and RANK, DENSE_RANK and ROW_NUMBER differ precisely on ties, so name which one the question requires.

Extrapolating a first-week lift inflated by novelty effects

Plot the treatment effect by days since first exposure instead of quoting one pooled average. A lift that decays toward zero across the test window is behaviour that will not persist, and annualising it produces a forecast that misses by an order of magnitude.

Questions & practice

Write a function to calculate the Pearson correlation coefficient.

Medium · statistics and probability

Approach

  1. Quantify uncertainty explicitly rather than reporting a point estimate alone.
  2. Translate the result into the decision it informs, in one plain sentence.
  3. Sanity-check the answer against a simple bound or a simulated case.

Follow-up

  • What sample size would you need to detect an effect half this size?
  • Which assumption here is most likely to be violated in practice?

How would you optimize a machine learning model for better performance?

Medium · machine learning and modelling

Approach

  1. Say how the offline result would be validated online before it is trusted.
  2. Frame the prediction: the label, the moment of prediction, and the action it triggers.
  3. Check what information would not exist at prediction time, and exclude it.

Follow-up

  • What would you monitor after launch to know the model is still valid?
  • Where could label leakage enter this setup?

What metrics would you use to evaluate the performance of a classification model?

Medium · machine learning and modelling

Approach

  1. Check what information would not exist at prediction time, and exclude it.
  2. Set a baseline first, so any model has something honest to beat.
  3. Pick an evaluation metric that matches the cost of each error type, not a default.

Follow-up

  • What would you monitor after launch to know the model is still valid?
  • Where could label leakage enter this setup?

Collapse claim versions before summing allowed amounts by member

Easy · claim versioning · groupby · deduplication

You are given medical_claim_line as a pandas DataFrame: claim_line_id, claim_id, claim_version, frequency_code (1 original, 7 replacement, 8 void), member_id, service_start_date, procedure_code, allowed_amount, claim_status. Return total allowed_amount per member for service dates in one stated calendar month, counting each claim once at its surviving version and excluding any claim whose surviving version is a void. Multi-line claims must keep every line of that surviving version. Output columns: member_id, allowed_amount, sorted descending. Do not deduplicate on claim_id alone.

Approach

  1. Separate the two grains out loud before writing code: versions live at the claim level, dollars live at the line level. Every bug in this exercise comes from mixing them.
  2. Compute the surviving version per claim with a groupby transform of max over claim_version, then keep the lines whose claim_version equals that value. A transform keeps the frame at line grain, which a sort plus head(1) does not.
  3. Drop whole claims whose surviving version carries frequency_code 8. A void is not a zero-dollar line, it retracts the claim, so filtering rows rather than claims leaves the prior version's lines behind.
  4. Filter to claim_status 'paid' and state the assumption: denied, pended and reversed lines carry an allowed_amount that never became a liability, so including them overstates cost.
  5. Restrict service_start_date to the month boundaries, then groupby member_id and sum. Sort descending and return.

Worked solution (20 min)

  1. Build a max-version lookup per claim_id with groupby('claim_id')['claim_version'].transform('max') and keep rows where claim_version equals it.
  2. From the surviving rows, collect the claim_ids whose frequency_code is 8 and drop those claim_ids entirely.
  3. Filter claim_status to 'paid' and service_start_date into the month window.
  4. Group by member_id, sum allowed_amount, sort descending, reset the index.

Expected result: A two-column frame member_id, allowed_amount. On a claim with versions 1, 7, 7 only the third version's lines contribute; a claim whose latest version is frequency_code 8 appears nowhere. Total allowed is strictly below a naive sum over all rows whenever any claim in the sample was adjusted, and equal to it when none was.

Verify it yourself

  • The distinct claim_id count in your filtered frame equals the count of distinct claim_ids whose surviving version is not a void.
  • The line count you kept for each surviving claim equals that claim's line count at its max version, not 1.
  • A naive sum over every row is greater than or equal to your total, with equality only when no claim has claim_version above 1.

Follow-up

  • A claim has versions 1, 7, 7 where the second replacement has fewer lines than the first. What does your code return and is that correct?
  • How would you handle a claim whose lines span two calendar months at the boundary of the reporting window?
  • The same logic has to run over 400 million lines in a warehouse. What changes, and what stays the same?

Can you explain the time complexity of your solution to a specific problem?

Medium · sql and data manipulation

Approach

  1. State the window function and its partition and ordering out loud before writing it.
  2. Handle the rows that do not match: a LEFT JOIN with a NULL check is usually the question.
  3. Say which table is the grain you start from, and join outward from it.

Follow-up

  • What breaks if events arrive late or out of order?
  • How would you verify this result without re-running the same query?

Reconstruct drug coverage intervals and compute proportion of days covered

Hard · gaps and islands · window functions · adherence

pharmacy_claim holds fill_id, member_id, ndc_code, therapeutic_class_code, fill_date, days_supply, reversal_flag and reversed_fill_id. Early refills overlap, so days_supply must be laid end to end: each fill's coverage starts at the later of its fill_date and the previous interval's end. Both rows of a reversed pair are excluded. For one therapeutic_class_code over 2025-01-01 to 2025-06-30, return per member the proportion of days covered, defined as covered days divided by days from first fill_date to window end, plus the share of members at or above 0.80. Require at least two fills and 91 days of follow-up.

Approach

  1. Clean the fills first. Drop rows with reversal_flag TRUE and also the fills they point at through reversed_fill_id. Dropping only the reversal row leaves an original fill counted as exposure that never reached the member. Use NOT EXISTS for that second step, since reversed_fill_id is nullable and NOT IN would return nothing.
  2. Shift, never stack. The shifted end is covered_end_i = GREATEST(fill_date_i, covered_end_{i-1}) + days_supply_i, which looks recursive but has a closed form: with cum_i the running sum of days_supply through fill i, covered_end_i = cum_i + MAX over j <= i of (fill_date_j - cum_{j-1}). That is SUM(days_supply) OVER (ORDER BY fill_date ROWS UNBOUNDED PRECEDING) plus a running MAX of an anchor column, so it is two window functions and no recursive CTE.
  3. Derive covered_start_i as GREATEST(fill_date_i, LAG(covered_end)). The intervals are disjoint by construction, so covered days is a plain sum of lengths and never needs a distinct day grid.
  4. Clip intervals to the window end before summing, and decide explicitly whether to clip at disenrollment as well. Supply that runs past the window must not inflate the numerator.
  5. Use the denominator the spec names, first fill_date to window end, and hold it constant across classes. A fixed-window denominator yields a different and usually lower number, and mixing the two across classes makes the comparison meaningless.
  6. Apply the inclusion rules at member level after the intervals are built, then compute the share at or above 0.80 with the qualifying member count beside it.

Worked solution (40 min)

  1. Filter to the therapeutic_class_code and window, then remove reversal rows and their originals with NOT EXISTS.
  2. Per member ordered by fill_date, compute cum_supply and anchor = fill_date - (cum_supply - days_supply), then covered_end = cum_supply + MAX(anchor) OVER (ORDER BY fill_date ROWS UNBOUNDED PRECEDING).
  3. Compute covered_start = GREATEST(fill_date, LAG(covered_end) OVER (ORDER BY fill_date)), clip both ends to the window, and drop intervals that collapse.
  4. Sum interval lengths as covered_days, compute follow_up_days from first fill_date to window end, and divide.
  5. Apply the two-fill and 91-day rules, then aggregate the share at or above 0.80.

Expected result: One row per qualifying member with covered_days, follow_up_days and pdc in [0, 1], plus a summary row with qualifying members and the share at or above 0.80. A member with 30-day fills on 2025-01-01, 2025-01-20 and 2025-04-01 is covered 2025-01-01 to 2025-03-01 and 2025-04-01 to 2025-04-30, giving 60 + 30 = 90 covered days over 181 follow-up days and a PDC of 0.497.

Verify it yourself

  • No pdc exceeds 1.0 before any clipping. A value above 1 proves supplies were stacked instead of shifted.
  • On a twenty-member sample, the summed interval lengths equal the distinct covered day count from a slow day-grid version.
  • A member with one fill is excluded by the two-fill rule rather than appearing with a PDC of 1.0.
  • Re-running with reversals left in raises covered days for exactly the members who have a reversed_fill_id, and for no one else.

Follow-up

  • A member is hospitalised for twelve days mid-window, when the facility supplies medication. Should those days count as covered, and what do published adherence measures do about them?
  • Someone wants to classify adherence over twelve months and then compare mortality from month zero. What is wrong with that design and what fixes it?
  • Two different ndc_codes in the same therapeutic class overlap. Is that stacking or switching, and how does your interval logic treat each case?

If tasked with improving a healthcare service based on data insights, what steps would you take?

Medium · product sense and metrics

Approach

  1. State what result would change your recommendation, so the answer is falsifiable.
  2. Restate the decision this analysis has to support, and who acts on the answer.
  3. Name one primary metric, then the guardrail that stops it being gamed.

Follow-up

  • How would you detect that the metric is being gamed rather than genuinely improving?
  • What would you do if the primary metric and the guardrail moved in opposite directions?

How do you prioritize your tasks when managing multiple projects?

Medium · product sense and metrics

Approach

  1. Fix the population and the time window before naming any metric.
  2. Restate the decision this analysis has to support, and who acts on the answer.
  3. Decompose the metric into the rates that drive it, and say which one you would check first.

Follow-up

  • Which segment would you cut first, and what would that rule out?
  • How would you detect that the metric is being gamed rather than genuinely improving?

Given a dataset of patient records, how would you identify factors that contribute to readmission rates?

Medium · product sense and metrics

Approach

  1. State what result would change your recommendation, so the answer is falsifiable.
  2. Name one primary metric, then the guardrail that stops it being gamed.
  3. Decompose the metric into the rates that drive it, and say which one you would check first.

Follow-up

  • How would you detect that the metric is being gamed rather than genuinely improving?
  • Which segment would you cut first, and what would that rule out?

Discuss your experience with A/B testing and how you would design an experiment.

Medium · a/b testing and experimentation

Approach

  1. Name the randomisation unit first; it decides the variance and what the test can detect.
  2. State the primary metric and the minimum effect worth shipping, then size the test.
  3. Decide the analysis before seeing data, including how long it runs and when you look.

Follow-up

  • How would you handle interference between treated and control units?
  • What would you conclude if the result is positive but the test is underpowered?

Can you explain the difference between supervised and unsupervised learning?

Medium

Approach

  1. Work from the decision backwards to the evidence you would need.
  2. Say what you would check first and why it is the highest-information step.
  3. Clarify what is being asked and what a complete answer would contain.

Follow-up

  • What assumption would you test first?
  • How would you know your answer was wrong?

Diagnose a sample ratio mismatch in a randomised outreach test

Easy · sample ratio mismatch · randomisation audit · selection bias

A member-level outreach test hashed member_id into two arms and wrote assignments to a bucket table before any contact was made. The analysis extract, built by joining assignments to member_enrollment and to the vendor send file, contains 20,560 treatment and 19,440 control members out of 40,000 assigned. The intended split was 50/50. State the test you would run on the split, compute it, say what it means for the outcome analysis, and describe how you would locate the cause.

Approach

  1. Test the split against the intended allocation with a chi-square goodness-of-fit on one degree of freedom, or equivalently a two-sided normal test on the treatment count with standard deviation sqrt(N x 0.5 x 0.5). Both give the same p-value.
  2. Stop the outcome analysis before running it. A significant ratio mismatch means the analysis population is not the randomised population, so any treatment effect is confounded by whatever selected members out, and no covariate adjustment can be trusted to fix it.
  3. Instrument the pipeline stage by stage and recompute the ratio at each one: the assignment table, the join to member_enrollment, the vendor send file, the response join, and the final extract. The mismatch appears at exactly one stage, and that stage is the bug.
  4. Given this domain, check the eligibility join first. Coverage terminations are back-dated and land after the fact, so a join that requires active coverage at extract time silently drops members, and the drop is not independent of arm if the outreach itself triggered contact that refreshed eligibility records.
  5. Compare the dropped members with the retained ones on termination_date, termination_reason_code, product_type, and prospective_risk_score to characterise the selection, then rerun the test on a corrected extract rather than rebalancing the arms.

Worked solution (15 min)

  1. Expected count per arm is 20,000.
  2. z = (20,560 - 20,000) / sqrt(40,000 x 0.5 x 0.5) = 560 / 100 = 5.6.
  3. Equivalently chi-square = 560^2 / 20,000 + 560^2 / 20,000 = 15.68 + 15.68 = 31.36 on 1 df.
  4. Convert to a p-value: two-sided p is about 2e-8.
  5. Pull arm counts at each pipeline stage and find the first stage where the ratio departs from 50/50.

Expected result: z = 5.6, chi-square = 31.4 on 1 degree of freedom, p is about 2e-8. This is not chance. The experiment is not analysable until the differential drop is located and either fixed or demonstrated to be independent of assignment.

Verify it yourself

  • A deterministic hash on member_id should produce an exact or near-exact 50/50 split at the assignment table; if it does not, the randomiser itself is the bug.
  • The imbalance should appear at exactly one pipeline stage, not drift gradually across several.
  • The dropped members should differ from the retained on at least one observable, which both confirms the selection and describes it.

Follow-up

  • The assignment table itself is exactly 20,000 / 20,000. What does that tell you and where do you look next?
  • A colleague proposes randomly downsampling the treatment arm to 19,440 to restore balance. Why is that not a fix?
  • At what imbalance would you not investigate, and how did you pick that threshold?

Protocol deviations fell as new sites came online

Hard · reporting lag · denominator mix · clustering

Protocol deviations per 100 completed visits across a multi-site study fell from 4.6 to 2.9 over two months while randomisation accelerated. study_subject_visit carries study_id, site_id, subject_id, visit_number, visit_name, planned_visit_date, actual_visit_date, visit_window_days, visit_status, protocol_deviation_flag, deviation_severity, data_entry_ts and site_activation_date. Operations wants to credit a retraining rollout that began in that window. Establish whether deviation behaviour changed, and deliver a version of the series that is safe to review monthly.

Approach

  1. Treat deviation flags as late-arriving data. Build a lag triangle of data_entry_ts minus actual_visit_date, because deviations are largely identified during monitoring review weeks after the visit, so the two most recent months are structurally undercounted in exactly the way an improvement looks.
  2. Hold back the months that are not developed, or apply development factors fitted on fully developed months, and restate. Do this before any explanation involving training.
  3. Attack the denominator. It counts visits with visit_status 'completed', while out_of_window and missed visits are excluded even though out-of-window attendance is itself a deviation in most protocols, so a site that pushes visits out of window lowers the rate twice over.
  4. Standardise the visit mix. Newly activated sites contribute mostly screening and baseline visits, which carry fewer procedures and fewer opportunities to deviate than later treatment visits, so compute the rate within visit_number strata and reweight to a fixed mix before comparing months.
  5. Split major from minor deviation_severity and report them separately. A single major deviation can remove a subject from the per-protocol analysis set while ten minor ones may not, so a pooled rate can fall while the consequential series rises.
  6. Before attributing anything to training, model at the right level: subjects are nested in sites, so use a random intercept per site or cluster-robust standard errors. With average cluster size m and intracluster correlation rho the variance is understated by the design effect 1 + (m - 1) times rho, which at m = 60 and rho = 0.02 is about 2.2, so naive intervals are roughly 1.5 times too narrow.

Follow-up

  • Design a defensible evaluation of the retraining rollout, given it was deployed site by site and cannot be withheld.
  • Your reweighted series is flat but major deviations rose. What do you escalate and to whom?
  • How would you decide the holdback period, and how would you communicate a provisional number without it being quoted as final?

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.

Your part, not the team's

Most data work is done by groups, so an interviewer has to work out which piece was yours. An answer that runs on 'we' for several minutes gets interrupted with a question about what you personally did, and by then the answer sounds defensive even when it is true. Mark your own contribution as you go, and name the parts that belonged to someone else instead of leaving them ambiguous. Keep a few specifics back as well, like the name of the metric or who actually objected, so a probe can be answered with something you had not already said.

Tell me about a time you faced a significant challenge in a project and how you overcame it.

Medium · behavioural and stakeholder questions

Approach

  1. Quantify the outcome, including what you would not claim credit for.
  2. Close with what you would do differently, concretely.
  3. Name the disagreement or constraint, and how you resolved it with evidence.

Follow-up

  • What would you do differently if you ran that project again?
  • How did you know the outcome was caused by your change?

Explain an incomplete cost series to a non-technical executive

Medium · claims runout · uncertainty · executive communication

An executive opens a dashboard showing risk-adjusted allowed PMPM down 6 percent across the last three incurred months and asks whether the cost initiative is working. You know pharmacy adjudicates within days, professional claims within weeks, and inpatient facility claims over months, so those three months are both undercounted and mix-shifted toward cheap services. There is also a genuine movement of roughly 1.5 percent in the older, complete months. Deliverable: a two-minute spoken answer, the change you make to the chart, and what you commit to telling them and when.

Approach

  1. The probe is whether you can be honest about uncertainty without sounding evasive. Executives read hedging as not knowing, so the answer has to end in a commitment.
  2. Separate the two claims immediately. The 6 percent is an artefact of incomplete data, and there is a smaller real movement in the months that are complete. Delivering only the debunk leaves them holding nothing.
  3. Explain the lag in their terms: the bills for the most expensive care arrive last, so an incomplete month always looks cheap and always looks like it is improving. Keep the phrase completion factor out of the first pass.
  4. Fix the chart instead of explaining around it. Shade or omit the incomplete months, print the paid-through date on the axis, and overlay the same series as it looked at equivalent maturity a year earlier so the shape is comparable rather than merely lower.
  5. Close with a date and a magnitude. Commit to a restated figure once runout matures, say roughly how far you expect the 6 percent to shrink, and name what you would need to see to call the initiative working.

Follow-up

  • They ask for your best guess today, knowing it is provisional. What do you say?
  • The restated number comes back at 1 percent. How do you handle having flagged the 6 percent at all?
  • How do you stop this dashboard producing the same conversation next quarter?

Push back on an over-broad extract without blocking the work

Hard · minimum necessary · de-identification · governance

A researcher asks for a one-off extract covering 12,000 members: member_id, date of birth, five-digit residential postal code, full lab_result rows including value_text, and clinical note text, held on their laptop for a retrospective analysis of one lab analyte over time. They describe it as de-identified because names are excluded. A flat refusal is not an acceptable answer. Deliverable: the column list you will actually provide with a justification per retained field, the sentence explaining why free text defeats an enumerated-identifier approach, your small-cell rule for the published stratification, and what you deliver this week.

Approach

  1. The probe is whether privacy is a design skill for you or a compliance reflex. Flat refusal and unquestioned fulfilment both fail, for opposite reasons.
  2. Reconstruct the analysis from the research question rather than from the request. A longitudinal trend in one analyte needs a stable pseudonymous subject key, the analyte's loinc_code, value_numeric, units, the reference bounds, and a date. It does not need names, notes, or a precise birth date.
  3. Replace each identifier with the least precise version that still answers the question: a salted per-study pseudonym instead of member_id, age in years or an age band instead of date of birth, a consistent per-subject date offset if only intervals matter, and a coarser geography than five-digit postal code.
  4. Explain the free-text problem in one sentence. Removing an enumerated list of identifier fields does not de-identify a note, because notes carry names, relationships, employers, dates and rare clinical detail in prose, so only a reviewed extraction into structured fields or a formal statistical determination addresses it.
  5. Set the publication rule before the analysis runs. Suppress cells below a stated threshold and suppress complements too, because a reader holding a row total and all but one cell recovers the suppressed count by subtraction.
  6. Keep them moving. Deliver the reduced extract into a controlled environment this week rather than onto a laptop, and offer to derive any note-based variable yourself as a structured flag so they never need the prose.

Follow-up

  • They say the age band loses resolution their model needs. What do you do?
  • How do you set the suppression threshold, and who signs off on it?
  • The analysis later needs linking to a second data source. What changes?