Power BI Interview Questions - Practice Real Quiz

Reviewed by Mark Dickie · Last updated

Power BI is Microsoft's business analytics platform for connecting to data, transforming it, modeling relationships, and publishing interactive reports and dashboards. For an interview, you should know the full workflow: importing data with Power Query, building a star-schema model, writing DAX measures that calculate correctly across filter context, and designing visuals that answer a specific business question. Interviewers also test whether you understand row context versus filter context, how calculated columns differ from measures, and how the Power BI Service handles refresh schedules, row-level security, and workspace collaboration.

What does a Power BI interview typically test?

Most rounds split into hands-on building and conceptual knowledge. You may be asked to build a report from a raw dataset on the spot, fix a broken measure, or explain why a DAX formula returns an unexpected total. Conceptual questions target data modeling choices, refresh architecture, and governance.

AreaWhat they check
Power Query (M)Data ingestion, transformations, merging queries, parameter usage
Data modelingStar schema design, relationship cardinality, bidirectional filters
DAXCalculated columns vs. measures, row context, filter context, iterator functions
VisualizationsChoosing the right chart, conditional formatting, drill-through, bookmarks
Power BI ServiceWorkspaces, app publishing, scheduled refresh, row-level security

How should you prepare for a Power BI interview?

  1. Build at least one end-to-end report from messy source data so you can talk through every transformation and modeling decision.
  2. Practice writing DAX measures by hand without the auto-generated suggestions, since whiteboard questions ask for the formula itself.
  3. Learn the refresh architecture for both Import and DirectQuery modes, including when gateway configuration is required.
  4. Review row-level security setup and how dynamic RLS patterns pass a username through a DAX filter.
  5. Get comfortable explaining why a total row shows a different number than the sum of its visual rows — this is one of the most common conceptual questions.

Use the quiz below to check where you stand before the real thing.

Key facts

  • Tarmac has 91 Power BI interview questions on this topic, 25 of them on this page, at difficulty 1–5 of 5.
  • Tarmac last reviewed these Power BI interview questions on 31 August 2026.

At a glance

Questions25 shown · 91 in the bank
Difficulty1–5 of 5
FormatsFind the bug, Flashcard, True / false, Multiple choice, Ordering, Multiple answer, Fill in the blank, Short answer, Code output

What you'll review

  1. star schema design
  2. dax context
  3. query folding
  4. measures vs calculated columns
  5. workspaces and apps
  6. bidirectional filtering
  7. relationship functions
  8. import vs directquery
  9. vertipaq engine
  10. row level security
  11. query execution pipeline
  12. calculate function
  13. iterator functions
  14. incremental refresh

Practice questions

Power BI/data-modelling/star-schema-design

The following text defines a Power BI star-schema data model for sales analytics. The model has a single design bug that violates star-schema principles. Identify the buggy line number (1-based).#

// Sales Star Schema
DimProduct:  ProductKey(PK), ProductName, Category
DimCustomer: CustomerKey(PK), CustomerName, City
DimDate:     DateKey(PK), FullDate, Month, Year
FactSales:   SalesKey(PK), ProductKey, CustomerKey, OrderDateKey, SalesAmount

// Relationships (* = Many, 1 = One):
FactSales[ProductKey]    *--1  DimProduct[ProductKey]
FactSales[CustomerKey]   *--1  DimCustomer[CustomerKey]
FactSales[OrderDateKey]  *--1  DimDate[DateKey]
FactSales[SalesAmount]   *--1  DimProduct[ProductKey]
Show answer

The bug is on line 11.

Why:

Line 11 creates a relationship on FactSales[SalesAmount], which is a measure/fact column — not a foreign key. In a star schema, relationships must join a foreign key in the fact table to a primary key in a dimension table. Additionally, DimProduct[ProductKey] already participates in the relationship on line 8, so line 11 would create an ambiguous filter path between the same two tables.

Power BI/dax/dax-context

In DAX, what is filter context?#

Show answer

Filter context is the set of filters applied to the data model at evaluation time. It determines which rows from the underlying tables are visible when a measure or expression is evaluated. It originates from report visuals, slicers, filter pane settings, and can be programmatically modified using the CALCULATE function.

Why:

Filter context is one of the two fundamental evaluation contexts in DAX (the other being row context). At difficulty 1, the key recall point is that filter context determines which rows are visible during evaluation and comes from user interactions in the report (slicers, visual cross-filtering) as well as programmatic filter arguments.

Power BI/power-query/query-folding

True or False: In Power Query, query folding occurs when transformations defined in Power Query are translated into a native query (e.g., SQL) and pushed down to the underlying data source for execution rather than being processed locally by the Power Query engine.#

Options

Show answer

True. Query folding is the process by which Power Query translates transformation steps into a native query (such as SQL) and pushes execution to the underlying data source instead of processing the data locally. This reduces data transfer and speeds up refreshes. Once a non-foldable step is introduced, later steps fall back to local processing.

Why:

Query folding is exactly this mechanism: Power Query translates transformation steps (such as filtering, sorting, grouping, and selecting columns) into a native source query — most commonly a SQL SELECT statement — and sends it to the data source so the source engine does the heavy lifting. This reduces the volume of data transferred to Power BI and improves refresh performance. When folding breaks (e.g., after adding a non-foldable step), subsequent steps are processed locally, which can be much slower.

Power BI/dax/measures-vs-calculated-columns

What is the most fundamental difference between a measure and a calculated column in a Power BI semantic model?#

Options

Show answer

A Power BI measure is a DAX formula evaluated dynamically at query time based on the current filter context and is never stored as a value in the model, while a calculated column is evaluated once per row at data-refresh time and its results are materialized and stored in the compressed in-memory model — consuming memory and disk exactly like an imported column. Because a measure costs no extra storage and responds live to whatever filters a report applies, the standard guidance is to prefer a measure whenever a calculation can be expressed dynamically, reserving calculated columns for values you need to filter, slice, group by, or reference in a row-level security rule.

Why:

A measure's DAX expression is re-evaluated every time it's placed in a visual, responding to whatever filter context that visual, its slicers, and its page filters currently apply — the result is never written back into the model, so it costs no extra storage. A calculated column's formula runs once per row during data refresh (or when the model is otherwise recalculated), and the resulting value for every row is materialized and stored in the compressed in-memory model exactly like a column loaded from the source, which means it consumes VertiPaq storage and refresh time regardless of whether a report ever uses it. That's why the standard guidance is to prefer a measure whenever the calculation can be expressed dynamically — a calculated column is reserved for cases where the value has to exist as a discrete row value, such as something you need to filter, slice, or group by, or a row-level security condition.

Power BI/data-modelling/star-schema-design

In Power BI data modeling, what's the primary reason a star schema (fact table surrounded by single-layer, denormalized dimension tables) is recommended over a snowflake schema (dimensions further normalized into multi-hop chains of related tables)?#

Options

Show answer

A star schema is recommended over a snowflake schema in Power BI because it keeps every dimension exactly one relationship hop away from the fact table, giving shorter and simpler filter-propagation paths, fewer relationships for the VertiPaq engine to traverse per query, and a flatter Fields list for report authors — at the cost of some denormalized repetition inside the dimension tables. A snowflake schema adds extra relationship hops for little practical benefit, since dimension tables are almost always small relative to fact tables, so the storage saved by further normalizing them rarely outweighs the added query complexity.

Why:

In a star schema every dimension sits exactly one relationship away from the fact table it describes, so a filter applied to a dimension (say, filtering Product by category) only has to propagate across a single relationship to reach the fact table — fewer hops means fewer relationships the engine has to traverse to resolve a visual's query, and it also gives report authors a flatter, more predictable Fields list. A snowflake schema normalizes a dimension further (Product → Subcategory → Category, each its own table), which mirrors relational database design but adds extra relationship hops that filters must cross, and typically adds little practical benefit inside a semantic model, since the dimension tables involved are almost always small relative to fact tables — the storage saved by normalizing them further is rarely worth the added query complexity. Dimension-to-dimension relationships are technically possible in Power BI (b is wrong), refresh time is not the deciding factor here since dimension tables are the smaller side of the model (c is wrong), and the two designs do measurably differ in query-time relationship traversal (d is wrong).

Power BI/sharing-security/workspaces-and-apps

Order the typical steps for building and distributing Power BI content to business users through a workspace and an app.#

Put these in order

Show answer

Power BI content distribution follows a fixed sequence: a workspace is created to hold the semantic model and reports, content creators build and publish reports and dashboards into that workspace, an app is then configured from the workspace's content by choosing which items and which audience to include, the app is published to generate a distributable read-optimized version, and finally business users consume that published app without needing any access to the underlying workspace.

Why:

A workspace has to exist before anything can be published into it, so it's the starting point, and it's also where the actual authoring happens — reports and semantic models are built and iterated on there by people with edit permissions. An app is a separate, curated distribution layer built from a workspace's content: configuring it means picking which reports and dashboards it exposes and to whom, which only makes sense once that content already exists in the workspace. Publishing the app is what actually generates the distributable version consumers open, and consumption comes last: business users interact with the read-optimized app, not the workspace itself, which is exactly the separation that lets a team keep iterating on drafts inside the workspace without exposing half-finished work to the wider audience using the app.

Power BI/data-modelling/bidirectional-filtering

When designing a Power BI model, which practices align with recommended guidance for bidirectional relationship filtering? (Select all that apply.)#

Options

Pick every one that applies.

Show answer

Recommended Power BI practice is to keep relationships single-directional by default and enable bidirectional filtering only when a specific requirement justifies it. When row-level security must cross a relationship, use the dedicated 'Apply security filter in both directions' option rather than enabling full bidirectional filtering on that relationship.

Why:

Microsoft guidance is to keep relationships single-directional by default and enable bidirectional only when justified (b). For row-level security, the specific 'Apply security filter in both directions' toggle is the targeted way to propagate RLS without making the whole relationship bidirectional (c). Setting every relationship bidirectional (a) and never using it at all (d) are both incorrect extremes.

Power BI/data-modelling/relationship-functions

Arrange the steps to manually create a relationship between two tables in Power BI Desktop's Model view, from first action to last.#

Put these in order

Show answer

To manually create a relationship in Power BI Desktop, open the Model view, drag a field from one table onto the matching field in another table, set the cardinality and cross-filter direction in the relationship dialog, then confirm to save the relationship. Each step depends on the one before it.

Why:

Creating a manual relationship in the Model view follows a fixed sequence: you first switch to Model view, then drag a field from one table onto the corresponding field in another table to initiate the relationship, then configure cardinality and cross-filter direction in the dialog that appears, and finally confirm to persist the relationship in the model.

Power BI/storage-modes/import-vs-directquery

Which of these are true statements about Import mode vs. DirectQuery mode for a Power BI semantic model? Select all that apply.#

Options

Pick every one that applies.

Show answer

Import mode loads and compresses a copy of the source data into Power BI's in-memory VertiPaq engine, so report queries run against that in-memory copy and are only ever as current as the last refresh. DirectQuery leaves the data at the source and translates each report visual's query into a native query sent to the source at query time, so data is always current at the cost of query latency depending on the source. DirectQuery does not always outperform Import — every interaction round-trips to the source rather than an in-memory columnstore — and its usable DAX surface is narrower than Import mode's, since not every DAX construct translates into every source's native query language.

Why:

Import mode's defining behavior is that it copies and column-compresses the source data into VertiPaq, Power BI's in-memory analytical engine, so every report query is answered from that fast in-memory copy — which is also exactly why the data is only ever as fresh as the last refresh (a and d). DirectQuery instead never copies the data: each visual's query gets translated into a native query against the live source at the moment someone views the report, so the numbers are always current, but every interaction now depends on that source's own query latency (b). DirectQuery is not a universal performance win — it trades query latency and DAX limitations for freshness, and it's frequently slower than Import for typical reporting workloads because every click round-trips to the source instead of hitting an in-memory columnstore (c is wrong). DirectQuery also has real constraints on which DAX functions and constructs it supports, since not every DAX expression can be translated into every source's native query language — some functions (RANKX in a calculated column or RLS rule, for instance) are explicitly unsupported in DirectQuery (e is wrong).

Power BI/power-query/query-folding

Query folding is Power Query's ability to translate the transformation steps of a query into a single native query statement that runs at the data source, instead of pulling raw data into the Power Query engine and transforming it locally.#

Options

Show answer

True. Query folding is Power Query's ability to translate a chain of applied transformation steps into a single native query statement — such as one SQL SELECT with WHERE and GROUP BY clauses — that runs at the data source, so the source's own engine does the filtering and aggregation and only the already-transformed result travels back over the wire, instead of Power Query pulling raw rows and transforming them locally.

Why:

True. When query folding succeeds, Power Query doesn't retrieve raw source rows and then filter, group, or reshape them itself — it instead compiles the chain of applied steps down into one native query (for example, a single SQL SELECT statement with WHERE and GROUP BY clauses) and sends that to the source, so the source's own engine does the work and only the already-transformed result comes back over the wire. This matters enormously for refresh performance and source load: a query that folds fully might pull back a few thousand filtered, aggregated rows, while the same query with folding broken partway through could pull back the entire source table and do the filtering locally in the comparatively slower Power Query mashup engine. DirectQuery and Dual storage mode tables require folding to work at all, since every visual's query has to become a native query at the source in real time.

Power BI/storage-modes/vertipaq-engine

What is the VertiPaq engine in Power BI, and why does column-oriented storage make it fast?#

Show answer

VertiPaq is the in-memory analytical engine that stores an Import-mode semantic model — it's the same engine that underlies Analysis Services Tabular and Power Pivot. Instead of storing data row by row like a transactional database, it stores each column separately and compresses it using techniques like dictionary encoding (replacing repeated values with small integer references) and run-length encoding, which works especially well because a typical column has far fewer distinct values than rows. Because a query like a SUM or a filter only needs to touch the specific columns involved, not whole rows, VertiPaq can scan just those compressed columns instead of reading every column of every matching row — and because the data is already sitting compressed in memory rather than on disk, aggregations over millions of rows return in a fraction of a second. Cardinality (the number of distinct values in a column) is the single biggest lever on how well a column compresses and how fast it queries, which is why data-modeling advice like 'use whole numbers instead of high-precision decimals' and 'split a high-cardinality datetime into separate date and time columns' exists.

Why:

VertiPaq's columnar, compressed, in-memory design is the mechanical reason Import-mode Power BI models feel instant even over large datasets: a query only pays for the columns it actually touches, those columns are already compressed and resident in memory, and low-cardinality columns compress extremely well because there are few distinct values to encode. This is also why cardinality-reduction advice (fewer distinct values per column, splitting datetime into date + time, avoiding needless calculated columns with unique values) is treated as a first-class performance lever in Power BI modeling — it's a direct lever on how well VertiPaq can compress and scan the data.

Power BI/sharing-security/row-level-security

What is Row-Level Security (RLS) in Power BI, and what's the difference between static and dynamic RLS?#

Show answer

Row-Level Security restricts which rows of model data a given user can see, by defining one or more roles in Power BI Desktop, each with a DAX filter expression (evaluating to TRUE/FALSE per row) applied to a table, and then assigning users or security groups to those roles once the report is published to the Power BI service. Static RLS hardcodes the allowed values directly in the role's DAX filter (for example, Region[Country] = "Australia"), so a separate role has to be created and maintained per value or group of values. Dynamic RLS instead looks up the signed-in user's identity — typically with the USERPRINCIPALNAME() or USERNAME() DAX function — against a mapping table in the model (a table of usernames to allowed regions, for instance), so a single role and a single filter expression can serve every user, each seeing only the rows their mapping-table entry permits, without needing a new role for every new user.

Why:

RLS is Power BI's mechanism for row-level data isolation inside a shared semantic model — one report, one dataset, but each viewer only sees the rows their role allows. Static RLS is simple to set up but doesn't scale past a handful of fixed segments, since every new value needs its own role. Dynamic RLS trades a bit of setup complexity (a mapping table plus a USERPRINCIPALNAME()-based filter) for scaling to any number of users without touching the model again — which is why it's the standard approach for any RLS scenario beyond a small, static set of categories.

Power BI/storage-modes/query-execution-pipeline

Order the stages of what happens, from data refresh to a rendered number, when a report visual displays a measure against an Import-mode semantic model.#

Put these in order

Show answer

The pipeline runs in a fixed order: Power Query extracts and transforms source data (folding into the source query where possible), the results load into VertiPaq as a compressed in-memory model, a user then interacts with the report which causes a visual to generate a DAX query, that query's filters resolve into a filter context, the measure's DAX expression evaluates against that filter context over the in-memory columns, and finally the resulting scalar value renders in the visual. Filter context always has to be resolved before a measure can evaluate against it — the ordering can't be reversed.

Why:

Everything downstream of a rendered number depends on the model already being loaded, so Power Query's extract-transform-load work and VertiPaq's compression happen first, at refresh time, entirely before any report is opened. From there, the report-time sequence is triggered by user interaction: a slicer click or a visual just rendering for the first time causes that visual to generate a DAX query, which resolves into a filter context before any aggregation can happen — filter context has to exist before a measure can be evaluated against it, not after. Only once the filter context is set does the measure's DAX expression actually run against the compressed in-memory columns, and only then does a single scalar value exist to hand back to the visual for rendering. Getting this order backward — for instance, imagining the DAX expression evaluates before filter context is resolved — is exactly the kind of confusion that makes 'why did my measure return the wrong number for this filter' hard to debug without a clear mental model of the pipeline.

Power BI/data-modelling/star-schema-design

In a Power BI star schema, the central table that holds quantitative measures (such as Sales Amount or Order Quantity) and contains foreign keys referencing surrounding dimension tables is called the _____ table.#

Show answer

In a Power BI star schema, the central table that holds quantitative measures (such as Sales Amount or Order Quantity) and contains foreign keys referencing surrounding dimension tables is called the fact table.

Why:

The hub of a star schema is the fact table — it stores additive numeric measures at the grain of an event (e.g., a sales line) and foreign keys pointing to dimension tables that radiate outward like the points of a star.

Power BI/data-modelling/star-schema-design

In a well-designed Power BI star schema, each dimension table sits on the _____ side of a one-to-many relationship, while the fact table sits on the many side.#

Show answer

In a well-designed Power BI star schema, each dimension table sits on the one side of a one-to-many relationship, while the fact table sits on the many side.

Why:

Dimension tables contain unique rows for each entity (e.g., one row per ProductKey), so they occupy the 'one' side of the relationship. The fact table has many rows referencing the same dimension key, placing it on the 'many' side. This 1-to-many direction is what makes filter propagation from dimension to fact work correctly.

Power BI/dax/calculate-function

A calculated column on the Sales table is defined as = CALCULATE(SUM(Sales[Amount])) with no filter arguments, inside a table that already has row context for the current row. What does wrapping SUM in CALCULATE with no extra filter arguments actually do here, and why does the result differ from writing plain SUM(Sales[Amount]) in that same calculated column?#

Options

Show answer

Wrapping SUM in CALCULATE with no extra filter arguments performs context transition: it converts the current row context into an equivalent filter context that constrains every column to the current row's own values, so SUM inside it evaluates only over that single row. Plain SUM(Sales[Amount]) with no CALCULATE ignores row context entirely and returns the grand total across the whole table for every row, which is why the two versions produce different results in a calculated column even though they look similar.

Why:

Outside of CALCULATE, a plain aggregation like SUM(Sales[Amount]) is evaluated in whatever filter context is currently active — and by itself, row context does not automatically become filter context, so with no ambient filter, SUM(Sales[Amount]) ignores the current row entirely and returns the grand total across the whole Sales table for every single row. CALCULATE is what performs context transition: when it wraps an expression while a row context is active, it converts that row context into an equivalent filter context that constrains every column to the current row's exact values, so the SUM inside it now only sees rows matching that filter — in a fact table with no duplicate keys, that reduces to just the current row's own Amount. This row-context-to-filter-context conversion is exactly what people rely on (often without wrapping it explicitly, since a plain measure reference gets an implicit CALCULATE wrapper) when they write DAX that behaves differently at the row level than the plain aggregate would.

Power BI/data-modelling/bidirectional-filtering

Which of these are accurate, Microsoft-documented statements about bi-directional (both-direction) cross-filtering relationships in a Power BI model? Select all that apply.#

Options

Pick every one that applies.

Show answer

Bi-directional relationships generally require more processing than single-direction ones and can hurt query performance as their count grows, which is why Microsoft's own guidance recommends minimizing their use. A one-to-one relationship must be bi-directional — Power BI offers no single-direction option for it — and bi-directional filtering is also what produces the 'slicer options with data' effect, where one slicer selection dynamically narrows another slicer's options, which some report users find confusing. For dimension-to-dimension analysis through a bridging fact table, the recommended approach is activating bi-directional filtering only inside the specific measure that needs it via CROSSFILTER, rather than making the underlying relationship permanently bi-directional.

Why:

Microsoft's own relationship guidance is explicit that bi-directional relationships require more processing and can hurt query performance as their count grows, so the general recommendation is to minimize them (a). One-to-one relationships are a special case that must be bi-directional — Power BI doesn't offer a single-direction option for them (b). Bi-directional filtering is also what produces the 'slicer options with data' effect, where selecting a value in one slicer dynamically narrows what's available in another, a behavior some report users find confusing because the options change without an obvious cause (d). For dimension-to-dimension analysis through a bridging fact table, Microsoft's guidance recommends the opposite of (c): rather than making the relationship permanently bi-directional in the model (which pays the performance cost on every query that touches it), activate bi-directional filtering just for the specific measure that needs it using the CROSSFILTER function inside CALCULATE. And (e) is simply false — the performance cost is the entire reason the guidance says to minimize bi-directional relationships in the first place.

Power BI/dax/iterator-functions

This measure is meant to rank each product by its total sales, but every product comes back tied at rank 1 in the report. Which line causes the bug?#

1| Product Sales Rank =
2| RANKX(
3|     ALL('Product'),
4|     SUM('Sales'[Amount])
5| )

Options

Show answer

Line 4 — SUM('Sales'[Amount]) is a plain aggregation with no CALCULATE around it, so it never performs context transition: it ignores RANKX's per-product row context entirely and evaluates to the same grand total for every single product, which is why every row ties at rank 1

Why:

RANKX evaluates its expression argument once per row of the table it's iterating, in that row's row context — but a plain aggregation function like SUM does not automatically respect row context the way a fully-fledged measure does. Row context only becomes filter context through context transition, and that transition only happens when CALCULATE (or CALCULATETABLE) wraps the expression, or implicitly, when the expression is a measure reference (every measure carries an implicit CALCULATE around its own definition). Here, SUM('Sales'[Amount]) is neither: it's a raw aggregation with no CALCULATE, so on every iteration of ALL('Product') it just evaluates in whatever filter context is already active outside RANKX — which, with no filter applied, is the grand total across the entire Sales table, identical for every product. The fix is RANKX(ALL('Product'), CALCULATE(SUM('Sales'[Amount]))) — wrapping the SUM in CALCULATE forces context transition, converting each product's row context into a filter context that constrains Sales to just that product's rows before summing, which is what actually makes the totals — and the ranks — differ per product. ALL('Product') is valid as RANKX's table argument (b is wrong), the default order argument ranks descending rather than ascending so no product is being pushed to a 'lowest rank' (c is wrong), and identical ranking for every row is never the intended behavior of RANKX (d is wrong) — it's the textbook symptom of a missing context transition, which is exactly why this pattern shows up repeatedly in real DAX debugging.

Power BI/power-query/query-folding

This Power Query M query is imported from a large SQL Server Orders table and takes far longer to refresh than a teammate's report against the same source. Which step is the reason query folding breaks and the entire table gets pulled into memory before it's filtered?#

1| let
2|     Source = Sql.Database("sales-server", "SalesDB"),
3|     Orders = Source{[Schema="dbo",Item="Orders"]}[Data],
4|     AddFlag = Table.AddColumn(Orders, "IsBigOrder", each if [Amount] > 1000 then "Big" else "Small"),
5|     FilteredRows = Table.SelectRows(AddFlag, each [OrderDate] >= #date(2026,1,1))
6| in
7|     FilteredRows

Options

Show answer

Line 4 — Table.AddColumn with a row-by-row each if ... then ... else ... custom column has no SQL equivalent the mashup engine can generate, so it breaks query folding at that step; every step after it, including the date filter on line 5, then runs locally against the entire unfiltered Orders table already pulled into memory instead of folding into the source query

Why:

Query folding works by translating the chain of applied steps into one native query the source can run — but it can only fold a step if that step has an equivalent in the source's query language. A row-wise custom column built from a conditional M expression like each if [Amount] > 1000 then "Big" else "Small" has no direct SQL translation, so the moment the mashup engine hits AddFlag, it has to give up on further folding: it pulls the full result of everything folded so far — which, since nothing upstream filtered anything yet, means the entire Orders table — into memory, and evaluates AddFlag and every step after it, including the date filter on line 5, locally. Line 5's Table.SelectRows on [OrderDate] >= #date(2026,1,1) is a completely foldable predicate on its own (it would become a WHERE clause) — the problem isn't that step itself, it's that it was placed after the step that already broke folding (c is wrong, and b and d are wrong because selecting the Data column and using Sql.Database are both perfectly normal, foldable starting points). Microsoft's own query-folding guidance says exactly this: when a step prevents folding, move the steps that can fold earlier in the sequence so the mashup engine factors them into the native query before it gives up — here that means filtering Orders by date on line 5 first, then adding the non-foldable IsBigOrder column afterward, so the SQL WHERE clause does the heavy filtering at the source and the row-wise logic only has to run over the already-filtered, much smaller result set.

Power BI/dax/dax-context

Explain the difference between row context and filter context in DAX, and why row context alone does not automatically apply a filter across a relationship to a related table.#

Show answer

Row context is 'the current row' — it exists automatically inside a calculated column, or inside any function that iterates a table row by row (like SUMX, FILTER, or RANKX), and it gives you access to that row's own column values. Filter context is the set of filters currently constraining which rows of every table are visible — built up from slicers, visual-level filters, page filters, and CALCULATE's filter arguments — and it's what aggregation functions like SUM actually respond to. The two don't automatically translate into each other: being 'on' a row in one table doesn't by itself filter a related table, because relationships propagate filter context, not row context — a fact table row's row context doesn't reach into a related dimension table unless you explicitly bridge it, either with RELATED/RELATEDTABLE (which follow the relationship directly) or with CALCULATE, which performs context transition by converting the current row context into an equivalent filter context that then propagates across relationships like any other filter. Without one of those, a plain aggregation evaluated inside a row-context iteration just reflects whatever filter context was already active, ignoring the current row entirely — which is exactly the bug behind measures that mysteriously return the same value for every row.

Why:

Row context is local to 'the current row' inside a calculated column or a table iterator; filter context is the global set of active filters that aggregation functions respond to. Relationships propagate filter context automatically, but they do not propagate row context — so simply being on a row of one table gives you no automatic visibility into a related table's rows unless you explicitly bridge the two, either by following the relationship directly with RELATED/RELATEDTABLE, or by using CALCULATE, which performs context transition: it converts the current row context into an equivalent filter context, which then flows across relationships exactly like a slicer selection would. This distinction is the root cause of a huge share of real DAX bugs — a plain aggregation with no CALCULATE, evaluated inside row context, just answers to whatever filter context already existed rather than reacting to the current row, which is why it silently returns the same total everywhere instead of erroring out.

Power BI/power-query/incremental-refresh

Why does incremental refresh exist for large Power BI fact tables, and how do the RangeStart/RangeEnd parameters make it work?#

Show answer

Without incremental refresh, every scheduled refresh reprocesses the entire fact table from scratch, which for a table with hundreds of millions of historical rows can take hours, strain the source system with a full extract every time, and risk timing out against the Power BI service's refresh limits. Incremental refresh solves this by partitioning the table on a date column and only reprocessing the partitions that actually changed, instead of the whole table. You configure it in Power BI Desktop by defining two date/time parameters named exactly RangeStart and RangeEnd, then filtering the fact table's Power Query query by that date column using those parameters as the lower and upper bounds; when you publish and configure the incremental refresh policy in the service (how much historical data to keep, how recent a window to refresh), Power BI uses those same parameters to automatically generate and manage separate partitions behind the scenes. On each subsequent scheduled refresh, it only re-pulls and reprocesses the partitions inside the configured 'refresh' window (recent, still-changing data) and leaves the older, already-processed historical partitions untouched, which is what turns a refresh from a full table scan into a much smaller, much faster incremental load.

Why:

Reprocessing an entire large fact table on every scheduled refresh doesn't scale — it's slow, it hammers the source with a full extract each time, and it can exceed the service's refresh time limits. Incremental refresh fixes this by splitting the table into date-based partitions and refreshing only the partitions that plausibly changed. The mechanism is the RangeStart and RangeEnd parameters: you filter the Power Query query for the fact table by a date column using those two parameters as bounds, and once the incremental refresh policy is configured in the Power BI service, it uses that same filter logic to automatically create and manage partitions — refreshing only the recent 'refresh period' window on each run while leaving older, already-loaded historical partitions alone. That's the difference between a refresh that reprocesses everything every time and one that scales to very large fact tables.

Power BI/data-modelling/relationship-functions

A Power BI model has two tables. Products has rows: (ProductID=1, Category="Electronics"), (ProductID=2, Category="Clothing"). Sales has rows: (ProductID=1, Amount=100), (ProductID=1, Amount=200), (ProductID=2, Amount=50). There is a many-to-one relationship from Sales[ProductID] to Products[ProductID] with single-direction filtering (Products filters Sales). The following DAX measure is evaluated on a report page with no external filters applied. What numeric value does it return?#

Electronics Sales = 
CALCULATE(
    SUM(Sales[Amount]),
    FILTER(
        Sales,
        RELATED(Products[Category]) = "Electronics"
    )
)
Show answer
300
Why:

CALCULATE's FILTER argument iterates row-by-row over the Sales table. For each Sales row, RELATED(Products[Category]) traverses the many-to-one relationship from Sales[ProductID] to Products[ProductID] to retrieve the corresponding category. The two rows with ProductID=1 resolve to "Electronics" (Amounts 100 and 200), while the ProductID=2 row resolves to "Clothing" and is excluded. SUM of the remaining Amounts = 100 + 200 = 300. RELATED works here because the filter direction from Products to Sales means the lookup can traverse from the many side (Sales) to the one side (Products).

Power BI/data-modelling/relationship-functions

A Power BI model has a DateTable with a [Date] column and a Sales table with columns OrderDate, ShipDate, and Amount. Sales rows are:#

ShippedOnDate = 
CALCULATE(
    SUM(Sales[Amount]),
    USERELATIONSHIP(DateTable[Date], Sales[ShipDate])
)

Options

Show answer
50
Why:

USERELATIONSHIP temporarily activates the inactive relationship on ShipDate and deactivates the active relationship on OrderDate for the duration of the CALCULATE. The report filter DateTable[Date] = 2024-01-01 therefore propagates through Sales[ShipDate] instead of Sales[OrderDate]. Only the third row (ShipDate = 2024-01-01, Amount = 50) satisfies this filter, so the result is 50. Option (b) 150 is what the active OrderDate relationship would yield (rows with OrderDate = 2024-01-01: 100 + 50). Option (c) 300 is the sum of rows where ShipDate = 2024-01-02 (a date-misreading error). Option (d) 350 is the unfiltered total of all rows.

Power BI/data-modelling/bidirectional-filtering

In a Power BI data model, you set a relationship's cross-filter direction to 'Both' (bidirectional). The model already contains an alternative active filter-propagation path connecting the same two tables through a chain of other relationships. What is the exact term — used in the Power BI Desktop error dialog — for the condition that prevents the relationship from being activated?#

Show answer

Power BI raises an ambiguity error. The error dialog states that the relationship cannot be active because it would create ambiguity. This occurs when bidirectional cross-filtering on a relationship would result in two or more equally-valid filter propagation paths between the same pair of tables, making it impossible for the VertiPaq engine to deterministically choose which path should propagate the filter context.

Why:

When bidirectional cross-filtering is enabled on a relationship, the VertiPaq engine checks whether the resulting graph creates multiple equally-valid filter propagation paths between the same two tables. If it does, the engine cannot deterministically resolve which path to use, so it raises an ambiguity error and refuses to activate the relationship. The exact term used in the Power BI Desktop error dialog is 'ambiguity' — the message reads that the relationship cannot be active because it would create ambiguity. This is a model-design-time check, not a query-time one.

Related interview questions

The other 66 questions

This page shows 25. A free account opens the rest and marks your answers, which a page of answers can't do. Miss one and it returns a few days later, then a week after that, until you stop missing it.

Start free

Free · the whole bank · 100 graded answers per 30 days · written feedback and job-ad quizzes on the paid plan

What moved, monthly

One email a month when the bulletin comes out: what moved in the markets we track, and the new question topics we published. Confirm your address to join. Unsubscribe any time.