SQL for AI Company Interviews — What OpenAI and Anthropic Actually Ask

Updated July 2026·12 min read·Every example runnable

The surprise in an AI-lab data interview is how little of it is about AI. You get asked who retained, which accounts went quiet, what counts as a session, and which 10% of users drive most of the load. Those are product-analytics questions, and they resolve to four SQL patterns. This guide covers all four with queries you can run right now.

Contents

  1. Why usage data changes the questions
  2. Pattern 1 — Cohort retention
  3. Pattern 2 — Sessionization
  4. Pattern 3 — Usage percentiles
  5. Pattern 4 — Event dedup
  6. Four mistakes that end interviews
  7. Practice these patterns

Why usage data changes the questions

An ecommerce analyst asks what sold. An AI-lab analyst asks what happened — and the underlying table is an event log where one person might appear four hundred times in an hour and then vanish for a week. That shape changes which SQL matters.

Three consequences show up in interviews over and over:

The interview signal: these rounds test whether you convert a fuzzy product question into a precise, defensible definition. Interviewers care less about your syntax than about whether you said out loud what "active" means before you typed anything.

Pattern 1 — Cohort retention

The question sounds like "do people stick around?" The SQL job is to anchor every account to its own starting point, then measure activity relative to that anchor — not to the calendar.

Cohort retention: anchor, offset, count
WITH first_seen AS (
  SELECT customer_id, MIN(order_date) AS cohort_day
  FROM orders GROUP BY customer_id
),
activity AS (
  SELECT o.customer_id, f.cohort_day, o.order_date,
         CAST(julianday(o.order_date) - julianday(f.cohort_day) AS INT) / 7 AS week_offset
  FROM orders o
  JOIN first_seen f ON f.customer_id = o.customer_id
)
SELECT cohort_day, week_offset, COUNT(DISTINCT customer_id) AS users
FROM activity
GROUP BY cohort_day, week_offset
ORDER BY cohort_day, week_offset

Two things make this an interview question rather than a syntax exercise. First, week_offset is computed per account, so week 1 means a different calendar week for everybody — that is the whole point. Second, COUNT(DISTINCT customer_id) and not COUNT(*): retention counts people, and someone who fired forty events on day three is still one retained person.

The trap: grouping by calendar week instead of cohort week. The query runs, the numbers look plausible, and you have answered a different question. Say your anchoring out loud before you write it.

Pattern 2 — Sessionization

Raw events are not sessions. You create sessions by declaring a gap rule: if two consecutive events from the same account are further apart than the threshold, the second starts a new session. It is LAG plus a running sum, and it is asked constantly.

Gap-based sessionization
WITH ordered AS (
  SELECT customer_id, order_id, order_date,
         LAG(order_date) OVER (
           PARTITION BY customer_id ORDER BY order_date, order_id
         ) AS prev_date
  FROM orders
),
flagged AS (
  SELECT *,
    CASE WHEN prev_date IS NULL
           OR julianday(order_date) - julianday(prev_date) > 7
         THEN 1 ELSE 0 END AS is_new_session
  FROM ordered
)
SELECT customer_id, order_id, order_date,
       SUM(is_new_session) OVER (
         PARTITION BY customer_id ORDER BY order_date, order_id
       ) AS session_id
FROM flagged
ORDER BY customer_id, order_date

The mechanism worth being able to explain: a running SUM over a 0/1 flag turns "this row starts something new" into a stable group id. Every row inside the same session shares the number, so you can group by it afterwards. Change the 7 to any threshold your product justifies — 30 minutes for a web app, days for an API where bursts are normal.

Practice sessionization challenges →

Pattern 3 — Usage percentiles

API usage is a power law. The mean is a fiction — it sits above almost every account and below the handful that dominate. Interviewers ask for percentile splits to see whether you know that.

Decile buckets with NTILE
SELECT name, salary,
       NTILE(10) OVER (ORDER BY salary) AS decile
FROM employees
ORDER BY salary DESC, name

NTILE(10) splits the ordered rows into ten buckets of near-equal size — decile 10 is the heaviest. The natural follow-up, and the one that separates candidates: what share of total volume does the top decile account for? That is a windowed SUM over the whole table divided into a windowed SUM over the bucket, and being able to reach for it without hesitating reads as fluency.

Know the difference: NTILE makes equal-sized buckets. PERCENT_RANK gives each row its relative position from 0 to 1. "Split accounts into deciles" is NTILE; "what percentile is this account in" is PERCENT_RANK. Interviewers ask which you would use and why.

Pattern 4 — Event dedup

Event pipelines deliver at least once, which means duplicates. Aggregating before deduping produces numbers that are quietly wrong — the failure mode most likely to reach a dashboard unnoticed.

Keep one row per logical event
WITH ranked AS (
  SELECT *,
    ROW_NUMBER() OVER (
      PARTITION BY order_id ORDER BY order_date
    ) AS rn
  FROM orders
)
SELECT * FROM ranked WHERE rn = 1

ROW_NUMBER rather than RANK, deliberately: ties must collapse to exactly one row. RANK would keep both duplicates at position 1 and defeat the purpose. That distinction is a common follow-up question.

Four mistakes that end interviews

  1. Counting events when the question asks about people. COUNT(*) where COUNT(DISTINCT account_id) was meant. Silent, plausible, wrong.
  2. Anchoring retention to the calendar. Cohorts are relative to each account's own start. Group by calendar week and you have measured seasonality, not retention.
  3. Reporting an average of a skewed distribution. If the top decile drives most of the volume, the mean describes nobody. Reach for percentiles unprompted.
  4. Aggregating before deduping. Duplicate events inflate every downstream number, and nothing errors. Dedup first, then aggregate.

What actually gets you hired: narrating the definition before writing SQL. "I'm treating an account as active if it has at least one event that week, and anchoring week zero to its first event — does that match how you think about it?" That sentence is worth more than a clever window function.

Practice these patterns

Reading them is not the same as producing them cold in a shared editor. Each of these has a company-tagged practice set that runs in the browser, with an AI tutor that explains why a query is wrong instead of handing over the answer.

Practice AI-lab SQL patterns free

Cohort retention, sessionization, usage percentiles and event dedup — on runnable datasets, with step-by-step hints when you get stuck.

Start practicing →