1. What is the difference between WHERE and HAVING?
WHERE filters rows before aggregation, HAVING filters groups after GROUP BY.
BI Developer interviews are about turning data into decisions: reporting SQL, dashboard and KPI design, honest visualisation, and the judgment to define a metric once and defend it to stakeholders. Expect questions on measures vs dimensions, dashboard performance, and diagnosing a number that suddenly looks wrong. Real questions with worked answers below.
A BI Developer loop tests whether you can turn data into a decision someone will actually make: reporting SQL that is correct at the grain the dashboard shows, KPI design, honest visualization, and the judgment to define a metric and defend it in a room. The technical bar is real, but the differentiator is taste: knowing which chart answers the question and which one just fills the space.
Recruiter screen, then a SQL screen focused on reporting shapes: aggregates at several grains, pivots, period-over-period comparisons. The onsite adds a dashboard design round (design the executive view for this business, which KPIs, which drill-downs), a tool round in whatever the company runs (Power BI, Tableau, Looker), a metrics case (a number moved, or two dashboards disagree), and a stakeholder or behavioral session.
SQL: correct aggregation, especially the classic BI bugs of averaging an averaged rate or summing a ratio. Dashboard design: a small number of KPIs with owners, a clear hierarchy from summary to detail, and restraint. Tool round: data model choices (star schema, relationships, measures) more than clicking. Case: a method for finding why a number moved, and a plan for making two dashboards agree, usually by defining the metric once upstream.
Practice reporting SQL at multiple grains and check every aggregate for the grain trap. Then rehearse two dashboard designs end to end, from the executive question down to the drill path, and be ready to defend every chart. Learn the modeling side of your tool (measures, relationships, calculated columns and when not to use them) rather than its formatting menus.
Prepare a story about a dashboard that changed what someone did. It is the strongest thing a BI candidate can say.
A dashboard with twenty tiles and no hierarchy. A rate computed by averaging rates. Building a metric inside the tool that already exists differently in the warehouse. And answering why the number moved with a guess instead of a method.
WHERE filters rows before aggregation, HAVING filters groups after GROUP BY.
Use conditional aggregation: MAX(CASE WHEN metric='x' THEN value END).
MRR, churn, LTV/CAC, activation, engagement cohorts, retention curves.
Push back with questions, not a wall of charts: what decision does this drive, who acts on it, how often, and what would make them act differently? Then design to that decision. Everything dashboards get built once and never opened, a dashboard is a decision tool, not a data dump.
Lead with the few metrics tied to their goals, each with context (target, trend, and variance) not a bare number. One screen, no scrolling, an obvious good/bad direction. Detail lives one click down for whoever needs it. The 30-second read is are we on track and where is the problem.
A dimension is what you slice by (date, region, product), a measure is what you aggregate (revenue, count, rate). Mixing them up (averaging an already-averaged rate, or summing a ratio) is the classic BI bug. A measure has to aggregate correctly at every grain the user can drill to.
Usually the query, not the tool: too fine a grain pulled to the client, a live query where an extract would do, or unfiltered scans. Pre-aggregate in the warehouse to the grain the dashboard actually shows, push filters down, and cache or extract where freshness allows. Row-level detail behind a summary should load on demand, not upfront.
Aggregate to month, then LAG the metric over ordered months: (this_month - LAG(metric) OVER (ORDER BY month)) / LAG(metric) OVER (ORDER BY month). Guard against divide-by-zero, and join to a month spine so a missing month reads as a gap rather than being silently skipped.
Name and define each version explicitly rather than shipping one ambiguous revenue (gross vs net, booked vs recognized) and document the definition on the dashboard itself. Get teams to agree the canonical one where you can, and where you can't, label them so nobody argues over a number that was quietly measuring two things.
Truncated axes that exaggerate change, dual axes that imply correlation, pie charts with too many slices, a rate shown as a raw count. Pick the chart for the question: trend to a line, comparison to a bar, part-to-whole to a stacked bar. Label units, start counts at zero, and drop the decoration: the goal is an honest, fast read.
Reconcile totals against a trusted source (finance, the source system, a known-good query), spot-check a few rows end to end, and confirm filters and date logic behave at the edges (empty selection, a single day, a year boundary) at every drill level. A dashboard that is wrong once loses trust for good, so validation is the job, not an afterthought.
Decide whether it is real or an artifact: did upstream data change, did a join fan out, did a filter break, or did one real event drive it. Segment to localize it, compare against the source of truth, and only then explain it to stakeholders. Reporting a broken number as real is worse than catching it late: verify before you raise it.