cswork / libraryOpen practice workspace

Interview guides · DataZymes

DataZymes Data Scientist Interview Questions & Guide 2026

SQL practice for DataZymes data scientist candidates: window functions, funnel and retention queries, joins that quietly drop rows.

The 60-second brief

As a Data Scientist at DataZymes, you are at the intersection of clinical insight and advanced computational modeling. You will not merely be building models; you will be architecting longitudinal patient journeys by integrating complex, multi-modal healthcare data, including claims, EHR, lab results, and pharmacy records. Your work directly informs strategic decisions for pharmaceutical clients, helping them navigate patient care pathways, treatment patterns, and disease progression.

Nearly every loop contains a round whose deliverable is a recommendation to someone non-technical. Practise stating a conclusion, the confidence attached to it, and the cost of being wrong in each direction, because that triple is the artifact being graded.

Focus areas

  • Separate censoring from events in time-to-event models
  • Correct for claims runout before reporting recent months
  • Build member-month denominators from overlapping coverage spans

Overview

This role is critical to the DataZymes mission of generating actionable, high-impact clinical insights. You will be expected to translate complex analytical methodologies into clear, executive-ready presentations, bridging the gap between raw data and business strategy. Success in this role requires a blend of rigor in predictive modeling—such as risk stratification and survival analysis—and the agility to adapt to evolving, often ambiguous, clinical problem statements.

The role is highly specialized. Expect your interviewers to place significant weight on your domain expertise in the pharma sector and your ability to handle messy, integrated healthcare datasets.

The DataZymes interview process

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

Initial Screening

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 Evaluations

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

Leadership-Level Assessments

This round decides whether someone can hand you a schema and a question and trust the number that comes back. Correctness under a clock is the bar, not clever syntax. The habit that separates strong from weak answers is checking the grain: after every join, know how many rows you expect and whether the count moved. Most wrong answers in this format are not wrong logic, they are a fan-out from a key that turned out not to be unique, or a filter applied before an aggregate when it belonged after. Say what you expect before you run it.

What to demonstrate

  • Whether your row counts survive each join, and whether you notice on your own when they do not
  • Deliberate handling of rows that fail to match, including whether the question needs an inner join or a left join with the non-matches kept and counted
  • Whether NULLs are treated on purpose, given that a NULL compares equal to nothing and that COUNT of a column skips it
  • Reaching a defensible answer inside the window instead of a refined one after it

How to prepare

  • Take a two-table schema, write a join that fans out on purpose, then fix it by collapsing the many-side to one row per key before joining. Repeat until the fix is reflex rather than recall.
  • Write a funnel as one query and print the distinct user count at each stage, then confirm each stage is a subset of the one above it rather than assuming it
  • Do a few timed runs in a plain text box with no autocomplete and no formatter, since assessment editors often have neither

Where candidates lose points

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.

Reading the most recent months of a claims-based series as real

Claims incur before they are reported and paid, so recent incurred months are systematically undercounted until runout completes. The lag is not uniform: pharmacy adjudicates in days, professional claims in weeks, inpatient facility claims in months. That means recent data is both too low and mix-shifted toward cheap services, which reads as a cost improvement and a utilisation drop at once. The fix is to hold the last three incurred months back or apply completion factors, and to state the paid-through date on every chart.

Reading a dozen metrics with no multiplicity control

Nominate one primary metric before launch and treat the rest as guardrails or exploratory, with Bonferroni or Benjamini-Hochberg applied when you intend to make claims from them. Twenty independent tests at 0.05 under the null produce at least one false positive about 64 percent of the time.

Averaging per-user rates to produce a population rate

Decide which quantity you want: the mean of per-user ratios and the ratio of summed numerator to summed denominator are different estimands, and heavy users dominate one but not the other. For a ratio metric, aggregate numerator and denominator separately and use the delta method for its variance.

Questions & practice

Can you walk us through a risk stratification model you built and the specific features that were most predictive?

Medium · machine learning and modelling

Approach

  1. Set a baseline first, so any model has something honest to beat.
  2. Say how the offline result would be validated online before it is trusted.
  3. Frame the prediction: the label, the moment of prediction, and the action it triggers.

Follow-up

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

Bootstrap a confidence interval for a ratio-of-sums PMPM

Medium · bootstrap · ratio estimator · resampling unit

You have one row per member for a fully run-out incurred year: member_id, member_months, allowed_amount. Report allowed PMPM, defined as sum(allowed_amount) divided by sum(member_months), with a 95 percent confidence interval from a bootstrap you write yourself. No library resampler. Resample members with replacement, recompute the ratio on each of 2,000 replicates, take a percentile interval, and seed the generator so the result reproduces. In two sentences, state why resampling claim lines instead of members would be wrong.

Approach

  1. Name the estimator precisely: PMPM is a ratio of sums, not the mean of per-member ratios. The two differ whenever exposure correlates with spend, and it does, because members who churn out mid-year are systematically different from members covered all twelve months.
  2. Resample the unit of independence, which is the member, and recompute numerator and denominator together on the same draw. Recomputing only the numerator against a fixed denominator understates variance and is a common slip.
  3. Pull member_months and allowed_amount into numpy arrays once, then draw indices with rng.integers(0, n, size=n) per replicate. Index draws over arrays run one to two orders of magnitude faster than DataFrame.sample, which is the difference between 2,000 replicates and 200.
  4. Take the 2.5th and 97.5th percentiles of the replicate ratios. Expect an interval that is asymmetric around the point estimate, because healthcare spend is right skewed. That asymmetry is the method working, not a bug to centre away.
  5. Answer the line-resampling question concretely: the many lines of one high-cost member are not independent draws, so line resampling shrinks the interval toward zero width, and member_months has no line-level analogue, so the denominator becomes undefined.

Follow-up

  • Half a percent of members have a transplant or a long NICU stay. Does a percentile interval still have nominal coverage, and what would you do about the tail?
  • The question changes to comparing PMPM across provider panels. What becomes the resampling unit and why?
  • How would you use the same replicates to test whether this year's PMPM differs from last year's, given the same members appear in both?

Proportion of days covered with shifted, truncated refill intervals

Hard · interval merging · adherence · path dependence

pharmacy_claim has fill_id, member_id, therapeutic_class_code, fill_date, days_supply, reversal_flag, reversed_fill_id. For one therapeutic class and a fixed 12-month window, compute proportion of days covered per member: distinct days on which a dispensed days_supply covers the day, divided by days from the member's first in-window fill through the window end. An early refill shifts coverage forward rather than stacking, and coverage is truncated at the window end. Drop both rows of every reversed pair. Return member_id, pdc, and the share at pdc >= 0.80 among members with at least 2 fills and at least 91 days of follow-up.

Approach

  1. Remove reversals as pairs first. Drop every row with reversal_flag true, and also drop the fill_ids those rows point at through reversed_fill_id. Dropping only the flagged row leaves a dispense that was never collected in the exposure.
  2. Walk fills per member in fill_date order carrying a cursor: start = max(fill_date, previous_end + 1 day), end = start + days_supply - 1. The shift is path dependent, so a plain cumsum over days_supply does not reproduce it. Use itertools.accumulate or a per-member loop over numpy arrays, not a row-wise apply over the whole frame.
  3. Truncate the last interval at the window end before measuring. Without truncation a 90-day fill dispensed on the final day pushes the covered-day count past the denominator and PDC above 1.0.
  4. Use the denominator the definition states: first in-window fill_date through window end, inclusive. Not a flat 365, and not first fill to last fill, which is a different metric that rewards early discontinuation.
  5. Apply the eligibility filter before computing the >= 0.80 share, and report the size of that denominator next to the share. A share without its denominator is not reviewable.

Worked solution (40 min)

  1. Filter to the therapeutic class and the window, then remove reversed pairs by dropping flagged rows and the fill_ids in reversed_fill_id.
  2. Sort by member_id, fill_date. Per member, accumulate start = max(fill_date, prior_end + 1 day) and end = start + days_supply - 1.
  3. Clip every interval's end at the window end and drop intervals whose start is past it.
  4. Covered days per member = sum of (end - start + 1) over the shifted intervals, which are disjoint by construction.
  5. Denominator = (window_end - first_fill_date).days + 1. Divide, then filter to members with >= 2 fills and denominator >= 91 and compute the share at or above 0.80.

Expected result: Per-member PDC in [0, 1], plus one share. Worked case: fills at day 0 (30 days), day 20 (30 days) and day 55 (30 days) in a 180-day denominator give intervals 0-29, 30-59 and 60-89, so 90 covered days and PDC = 0.50. Change the window to 60 days with fills at days 0, 20 and 40 and the shifted intervals truncate to 0-59, giving PDC = 1.00 while a days-supply sum would report 90/60 = 1.50.

Verify it yourself

  • No member has PDC above 1.0. Any value above 1.0 means intervals stacked instead of shifting, or the final interval was not truncated.
  • A member with a single 30-day fill at the start of a 180-day denominator scores 30/180 = 0.167 and is excluded from the share by the two-fill rule.
  • For one member, rebuild covered days as the size of a Python set of date ordinals over the raw fills and confirm it matches the interval arithmetic.
  • Shifting every fill_date forward by the same number of days changes each denominator but leaves the covered-day counts unchanged except at the truncation boundary.

Follow-up

  • How does PDC differ from medication possession ratio, and which of the two can exceed 1.0?
  • A member switches to a different ingredient inside the same therapeutic class mid-window. Should the intervals chain, and what does that do to the class-level number?
  • Members who die or lose coverage mid-window get a short denominator and often a high PDC. If you then compare mortality by adherence category, what bias have you built in and how do you remove it?

Find inpatient encounters with no resulted lab during the stay

Medium · anti-join · null semantics · event matching

encounter holds encounter_id, patient_id, encounter_type, admit_ts, discharge_ts and facility_id. lab_result holds result_id, order_id, patient_id, encounter_id (NULL for outpatient standing orders), loinc_code, specimen_collected_ts, resulted_ts and result_status. Return every inpatient encounter discharged in 2025 with no final or corrected lab_result linked to it. A colleague wrote WHERE encounter_id NOT IN (SELECT encounter_id FROM lab_result) and got zero rows back. Say why, write the correct query, then say what changes when labs must instead be matched on patient_id with the specimen collected between admit_ts and discharge_ts.

Approach

  1. Name the mechanism rather than the symptom. x NOT IN (subquery) expands to x <> y1 AND x <> y2 AND ..., and a single NULL y makes that chain UNKNOWN, never TRUE. Since lab_result.encounter_id is nullable by design for standing orders, this query can only ever return zero rows.
  2. Rewrite as NOT EXISTS, or LEFT JOIN with an IS NULL filter. Both treat a NULL key as no match rather than as unknown. Adding IS NOT NULL inside the NOT IN subquery also works, but NOT EXISTS is the habit that survives someone making another column nullable later.
  3. Put the result_status predicate inside the correlated subquery or the ON clause, not in an outer WHERE. Outside, it turns the anti-join back into an inner join and an encounter whose only labs were cancelled disappears instead of qualifying.
  4. For the timestamp variant, match on patient_id with specimen_collected_ts inside the stay rather than resulted_ts. A specimen drawn an hour before discharge can result the next day, and anchoring on resulted_ts would wrongly call that stay lab-free.
  5. Restrict to encounter_type 'inpatient' and discharge_ts in 2025, and report open encounters with a NULL discharge_ts as a separate count instead of letting the filter swallow them.

Worked solution (20 min)

  1. Demonstrate the cause: SELECT COUNT(*) FROM lab_result WHERE encounter_id IS NULL returns a non-zero number.
  2. Write the NOT EXISTS version with result_status IN ('final','corrected') inside the correlated subquery.
  3. Write the LEFT JOIN version with the same predicate in the ON clause and WHERE l.result_id IS NULL, then compare counts.
  4. Build the timestamp variant joining on patient_id with specimen_collected_ts >= admit_ts AND < discharge_ts.
  5. Report both counts side by side and explain which encounters differ between the two definitions.

Expected result: One row per qualifying inpatient encounter with encounter_id, patient_id, facility_id, admit_ts and discharge_ts. The count is strictly below total 2025 inpatient discharges and strictly above zero, while the NOT IN version returns exactly zero rows.

Verify it yourself

  • NOT EXISTS and LEFT JOIN with IS NULL return identical row counts.
  • Adding AND encounter_id IS NOT NULL inside the NOT IN subquery reproduces the NOT EXISTS count exactly.
  • No returned encounter_id appears anywhere in lab_result with result_status in ('final','corrected').
  • The patient-and-timestamp variant returns fewer encounters than the encounter_id variant, since it also catches labs whose encounter link is missing.

Follow-up

  • Write the LEFT JOIN form and say exactly where the result_status predicate must sit for the two forms to agree.
  • How would you separate encounters whose only labs were cancelled from encounters with no lab rows at all?
  • Some encounters carry member_id NULL because the person index did not match. What does that do to a payer-side version of this measure?

Turn overlapping coverage spans into fractional member-month denominators

Medium · intervals · gaps and islands · denominators

member_enrollment holds span_id, member_id, plan_id, product_type, effective_date and termination_date, which is NULL while the span is active. A member can hold several spans in a year, and back-dated plan changes make spans overlap. Return one row per calendar month of 2025 with total member-months, where a member contributes covered days in the month divided by that month's length, and a day covered by two overlapping spans counts once. Both span endpoints are inclusive. Collapse overlaps with window functions before joining a month calendar, and do not assume one span per member.

Approach

  1. Normalise the open end first. COALESCE(termination_date, DATE '9999-12-31') or clip to the reporting end, because a NULL termination_date makes every BETWEEN comparison unknown and drops exactly the members who are still covered.
  2. Merge overlapping spans per member before the calendar join. Order by effective_date, carry a running MAX of prior termination_date with a frame ending one row before, and open a new island where effective_date exceeds that running max plus one day, which keeps adjacent spans contiguous rather than splitting them.
  3. Clip each merged island to the reporting year, then cross join to a twelve-row month calendar and keep pairs that intersect.
  4. Compute covered days as LEAST(island_end, month_end) minus GREATEST(island_start, month_start) plus one, and divide by the actual length of that month rather than a flat 30, so February and the 31-day months are not distorted.
  5. Sum the fractions by month. Merging after the calendar join also works but forces a DISTINCT over member-days, which stops scaling at population size.

Follow-up

  • Where does a continuous-enrolment filter with an allowable 45-day gap belong, and how does that change the island boundary rule?
  • One human appears under two member_ids after a master person index merge. What does that do to member-months, and how would you detect it?
  • How do you treat a span that terminates on the day it starts, and what does that row usually represent?

How do you manage shifting priorities when working on a long-term clinical research project?

Medium · product sense and metrics

Approach

  1. Decompose the metric into the rates that drive it, and say which one you would check first.
  2. Name one primary metric, then the guardrail that stops it being gamed.
  3. Restate the decision this analysis has to support, and who acts on the answer.

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?

Explain the difference between time-series analysis and survival analysis in the context of tracking patient treatment duration.

Medium

Approach

  1. Clarify what is being asked and what a complete answer would contain.
  2. State your assumptions explicitly before working the problem.
  3. Say what you would check first and why it is the highest-information step.

Follow-up

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

How would you approach identifying barriers to therapy adherence using unstructured clinical notes?

Medium

Approach

  1. State your assumptions explicitly before working the problem.
  2. Clarify what is being asked and what a complete answer would contain.
  3. Say what you would check first and why it is the highest-information step.

Follow-up

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

Power a readmission trial on a rare binary outcome

Easy · power analysis · minimum detectable effect · rare events

A care-transitions programme (pharmacist call plus a seven-day follow-up visit) will be tested on index inpatient discharges drawn from encounter, excluding planned admissions, acute-to-acute transfers, AMA discharges, and dispositions of expired or hospice. Baseline 30-day unplanned readmission on eligible stays is 15.8 percent. Leadership wants to detect a 1.5 percentage point absolute reduction, two-sided alpha 0.05, 80 percent power, 1:1 individual randomisation at discharge. Give the required index stays per arm, and the minimum detectable absolute effect if only 4,000 eligible stays per arm accrue in the study window.

Approach

  1. Write the two-proportion sample size formula and state its preconditions: normal approximation, two-sided test, equal allocation, and the outcome measured on index stays rather than on members, since one member can contribute several index stays.
  2. Plug in p1 = 0.158, p2 = 0.143, and (z_0.975 + z_0.80)^2 = (1.960 + 0.842)^2 = 7.849. Report the answer as index stays, and separately as the calendar time it implies given the observed monthly eligible volume.
  3. Invert the same formula for the fixed-N case: solve for delta with n = 4,000 per arm, and say whether you used pooled or arm-specific variance because the two answers differ by about 0.1 percentage points.
  4. Translate the MDE into the relative reduction it implies and hand it back to leadership before the study starts, so the question becomes whether that effect is worth running rather than whether the null result was a failure.
  5. Flag the two adjustments that will make the real number larger: if a member can appear more than once, cluster on member_id, and if the programme is delivered by unit or by discharging team rather than to individuals, an individual-level calculation is the wrong model entirely.

Worked solution (20 min)

  1. Compute (1.960 + 0.842)^2 = 7.849.
  2. Compute the variance sum: 0.158 x 0.842 = 0.1330, 0.143 x 0.857 = 0.1226, total 0.2556.
  3. n per arm = 7.849 x 0.2556 / 0.015^2 = 7.849 x 1,136 = 8,916, so round to about 8,920 per arm.
  4. For the MDE at n = 4,000, solve delta = sqrt(7.849 x variance sum / 4,000); with arm-specific variance this gives 0.0221, with pooled variance at p = 0.158 it gives 0.0229.
  5. Express the MDE as a relative effect: 0.023 / 0.158 is about a 15 percent relative reduction.

Expected result: About 8,900 index stays per arm (roughly 17,800 total) to detect 1.5 percentage points. With 4,000 per arm the MDE is about 2.2 to 2.3 percentage points absolute, which is a 14 to 15 percent relative reduction; state which variance convention you used.

Verify it yourself

  • Halving the target effect should roughly quadruple N: at 3.0 points the formula gives about 2,130 per arm, and 8,916 / 2,130 is about 4.2.
  • Confirm the normal approximation holds: expected events per arm are 0.158 x 8,916 = about 1,409, far above the usual threshold of 10.
  • Divide required N by observed monthly eligible index stays and check the implied study duration against the decision deadline.

Follow-up

  • The same programme is delivered by discharge unit, not to individual patients. What changes in the calculation?
  • How would you handle a member who has three eligible index stays during the study window?
  • Leadership proposes powering on a composite of readmission or ED revisit instead. What does that buy and what does it cost?

Avoidable admissions fell the quarter a programme launched

Hard · mix shift · regression to the mean · reclassification · seasonality

Ambulatory care sensitive admissions per 1,000 member-years fell 18 percent in the quarter a care-management programme launched, enrolling the top 2 percent of members by prior-year spend. You have encounter, member_enrollment including a product line added mid-quarter, and medical_claim_line. Emergency visits per 1,000 rose 9 percent over the same quarter and observation stays rose as well. Produce a decomposition that states how much of the 18 percent is attributable to the programme, and state the design you would need before claiming any of it.

Approach

  1. Rebuild the denominator from coverage spans as member-years, counting partial coverage fractionally, and recompute the rate with and without the product line that entered mid-quarter. A newly added, structurally healthier population inflates the denominator and deflates every rate built on it without a single admission being avoided.
  2. Freeze the numerator's code list to one version. The ambulatory care sensitive list is defined on ICD-10-CM principal diagnosis codes, and in the United States that code set is updated effective October 1, so a quarter spanning that boundary can gain or lose qualifying codes. Recompute both quarters against a single code set version.
  3. Decompose the remaining change with a Kitagawa split across product_type and prior-year risk decile: the mix term is the population getting younger or healthier, the within term is the only place a programme effect can live.
  4. Test reclassification directly. An inpatient stay recorded as an observation stay is not an avoided admission. Compute total acute contacts per 1,000 member-years as inpatient plus observation plus emergency, and check whether that total moved at all. If it is flat while inpatient falls, care was relabelled and deflected, not prevented.
  5. Compare to the same quarter of the prior year rather than the adjacent quarter. Several ambulatory care sensitive conditions, including heart failure decompensation and bacterial pneumonia, are strongly seasonal, so a quarter-over-quarter comparison confounds the programme with the calendar.
  6. Address selection last and explicitly. The enrolled cohort was chosen on an extreme of prior-year spend, so it regresses toward the mean with no intervention at all, because the selecting year captured both chronic severity and one-off events. A pre-post design on this cohort will report savings every time. The minimum credible design is a concurrent comparison group selected by the same rule in the same period, or a regression discontinuity at the 2 percent threshold, with a parallel-trends check on at least four pre-periods.

Follow-up

  • The parallel-trends check fails on two of the four pre-periods. What do you do, without abandoning the question?
  • Express the effect you can defend as an absolute risk difference and a number needed to treat, with the baseline rate stated. Why is that more useful here than a relative reduction?
  • The programme cannot be withheld from anyone. Sketch a rollout design that still identifies an effect, and say what secular trend does to the estimate.

Suggested practice checklist

Instead of guessing where the week should go, day one measures it under a fixed rubric and allocates the remaining hours in proportion to the gaps. The method is deliberately rigid: the allocation is written down before any studying starts and is not renegotiated when a topic turns out to be unpleasant.

Day 1 — Diagnostic, scored before you study anything

  • Sit a 100-minute timed diagnostic in four blocks: 30 minutes of SQL across three prompts, 25 minutes of short-answer statistics, 25 minutes on one modelling or case prompt, and 20 minutes delivering one behavioural story aloud.
  • Score each block from 0 to 3 on a fixed rubric where 3 is correct and fluent, 2 is correct but slow or prompted, 1 is partially correct, and 0 is stuck, grading the output rather than how the attempt felt.
  • Allocate the hours for days two to five roughly in proportion to 3 minus the score in each block, write the allocation down, and commit to not revising it midweek.

Deliverable: A scored rubric and a fixed hour allocation for the rest of the week.

Day 2 — Largest gap: find the boundary rather than the subject

  • Break the weakest area into five named sub-skills (for query work: grain control, window frames, date arithmetic, set logic with NULLs, and reading a query plan) and rate each one, so the rest of the week targets a sub-skill instead of a subject.
  • Solve three problems chosen to sit just above where the rating drops off, and for each write the first move you failed to make.
  • Re-solve one of them from memory four hours later, on paper, with nothing open.

Deliverable: A five-item sub-skill map with the two blocking sub-skills circled.

Day 3 — Largest gap: drill the blocking sub-skill

  • Do eight short repetitions of the same shape rather than eight different problems, so what you practise is the pattern and not the puzzle.
  • Write the rule you now hold in one sentence, then test it against a case built to break it: a ranking function over a column with ties, or a two-sample test on observations that are obviously dependent.
  • Have someone else read your one-sentence rule and find the precondition you left out.

Deliverable: One rule statement with its preconditions attached and one counterexample that would have caught the incomplete version.

Day 4 — Second gap, plus maintenance on your strongest area

  • Run the same sub-skill map and boundary protocol on the second-largest gap, compressed into half the day.
  • Spend 25 timed minutes on your strongest area to stop it decaying, choosing the hardest problem you can still finish rather than an easy warm-up.
  • Compare how the two areas fail: whether you lose time on recall, on setup, or on arithmetic, because the fix differs for each.

Deliverable: A second sub-skill map plus a one-line diagnosis of how each area fails you.

Day 5 — The gap that is not a skill

  • Record yourself answering one technical and one behavioural prompt, then count two things in the playback: how many seconds before your first clarifying question, and how many sentences you started without knowing where they ended.
  • Rewrite your three most-used stock phrases into shorter versions, and practise saying "I do not know, here is how I would find out" without softening it into a guess.
  • Deliver one answer again with a hard 90-second limit to force structure before detail.

Deliverable: Two recordings with a counted improvement in time-to-first-question.

Day 6 — Retest under day-one conditions

  • Sit the same 100-minute diagnostic structure with new prompts of comparable difficulty and score it on the identical rubric.
  • Compare block by block, and for any block that did not move, change the method rather than adding hours: a block stuck at 1 usually means the practice was too varied, not too short.
  • Write which single block you would still lose the offer on.

Deliverable: A second scored rubric placed next to the first, with one named remaining risk.

Day 7 — Full loop under interview conditions

  • Run a 60-minute mock covering the two blocks that moved least, with an interviewer instructed to interrupt and change direction.
  • Write your recovery script for the moment you go blank: restate the question, state your assumption, name the first thing you would check.
  • Reduce the week to the rule statements you wrote, each with its preconditions attached, then say every one of them out loud without reading it and cut any you cannot state in a single sentence, since a rule you have to reconstruct mid-answer will not survive being interrupted.

Deliverable: A one-page card holding the recovery script and only the rules you could state from memory.

Stories where someone disagreed with you

Have two ready. In one, the data was on your side and you had to move someone who outranked you. In the other, the pushback was correct and you changed position. The second is the harder story and it lands better, because it shows you separate being right from being attached to an answer. Name the person's actual objection.

How do you handle missing values or data quality issues in longitudinal patient records?

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 did you decide not to do, and why?
  • What would you do differently if you ran that project again?

Tell us about a time you identified a data quality issue that threatened the validity of your analysis; how did you resolve 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?

Describe a time you had to explain a complex analytical result to a non-technical client.

Medium · behavioural and stakeholder questions

Approach

  1. Pick a story where you drove the decision, not one where you observed it.
  2. Close with what you would do differently, concretely.
  3. 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?