Skip to content
Power BI

How to Build Your Paginated Report Dataset from a Power BI Semantic Model

Caf2Code Thought Leadership
September 16, 2026 10 min read

You have a paginated report connected to your semantic model. So you open the Query Designer, drag in the same fields you'd drag onto a canvas in Power BI Desktop, and run it — and get thousands of rows of nonsense. Your model is fine. Your connection is fine. The query did precisely what you asked. This post is about that gap.

Editor’s update — September 2026: This post first ran in May 2023 and has been rewritten. The Power BI “dataset” is now a semantic model, but the paginated report’s own dataset kept its name — which is exactly what this post is about. There is also a faster way to build the query than the original described, so that has been added and put first.

Paginated Reports 101 — Part 3 of 5. This post is hands-on. It assumes you’ve built the model in the sample files and setup guide and connected to it in Part 2. Every figure below will then match your screen.

You have a paginated report connected to your semantic model. So you open the Query Designer, drag in the same fields you’d drag onto a canvas in Power BI Desktop, and run it.

You almost certainly get thousands of rows in a broken format, and everything looks terrible.

Your model is fine, your connection is fine, and the query did precisely what you asked. The issue is that Report Builder treats your request differently from Power BI Desktop. This post is about that gap.

What you’re actually building

Part 2 covered three things that have all been called a “dataset.” The one that matters here is the third: the paginated report’s dataset, a single query that returns a single flat table. It is the building block of your paginated report.

Slow down on this, because if you’re used to Power BI Desktop it is genuinely different from what you know. A semantic model is a small database with tables, relationships and measures, and it works out how to aggregate things on your behalf when you drop a field on a canvas. A paginated report dataset has none of that: one query, one result set, no relationships, no model, and no aggregation unless you explicitly asked for it.

Everything that follows is a consequence of that last sentence.

Open Report Builder, right-click Datasets and choose Add Dataset. Then click Query Designer.

The Dataset Properties dialog in Report Builder, with the dataset Name set to SmoreSales, the Data source set to PowerBIBlogs_SmoreSales, and the Query Designer button highlighted.
Name the dataset, confirm the data source, then go into the Query Designer.

You now get a different view of the same data that exists in your semantic model. For clarity, here is a side-by-side: the semantic model in Power BI Desktop on the right, the Query Designer on the left.

Side-by-side comparison. On the left, Report Builder's Query Designer showing a field list of Measures, Dim Customer, Dim Date, Dim Product and Smore Sales Table. On the right, the same model in Power BI Desktop model view showing the star schema and its relationships.
Same model, two views. The Query Designer shows you the fields but none of the relationships that make Desktop feel effortless.

Why your total came back 3,601 times

The model here is small: one fact table called Smore Sales Table with 12,000 order lines, plus product, customer and date dimensions. Two measures are defined on it, Total Quantity and Total Sales.

Watch what happens when you ask for a raw column instead of a measure. Drag the Quantity column into the Query Designer and it generates something like this:

EVALUATE
    SUMMARIZECOLUMNS ( 'Smore Sales Table'[Quantity] )

Run it and you get 18 rows. Eighteen, because there are exactly 18 distinct values in that column and the query returned one row for each.

Report Builder Query Designer results showing a single Quantity column with 18 distinct values listed: 24, 8, 12, 18, 60, 2, 6, 96, 3, 120, 48, 9, 4, 36, 144, 16, 30, 72.
Eighteen rows, one per distinct quantity. Not a total.

Eighteen rows is small enough to look like a mystery rather than a pattern. Try the same thing with a higher-cardinality column. SalesAmount, being currency with promotional pricing behind it, has many more distinct values:

EVALUATE
    SUMMARIZECOLUMNS ( 'Smore Sales Table'[SalesAmount] )

3,601 rows. One per distinct value again, and now it is obvious something has gone sideways. Add a second raw column and the row count multiplies rather than adds, because you’re asking for every distinct combination.

Query Designer results showing two columns, Quantity and SalesAmount, with many rows all having Quantity 12 and different SalesAmount values, and a long red arrow indicating a very large scrollbar.
That scrollbar is the point. Two raw columns multiply out to every distinct combination.

Ask for the measure instead:

EVALUATE
    SUMMARIZECOLUMNS ( "Total Quantity", [Total Quantity] )

One row. 410,120. This is what you wanted the first time.

Query Designer showing the Total Quantity measure selected in the field list under Measures, and a single result row reading 410120.
One measure, one row, the right number.

What Power BI Desktop silently does for you

If you’ve spent time in Power BI Desktop, dragging a numeric column onto a visual and watching it sum itself is completely normal. That’s the source of the confusion: Desktop was doing something on your behalf that it never told you about.

When you drop a numeric column into a visual, Desktop wraps it in an aggregation for you. That’s an implicit measure. You asked for Quantity, Desktop decided you meant SUM of Quantity, and it was right, so you never gave it a second thought.

Report Builder’s Query Designer is more literal. It builds exactly the query you described and nothing more. SUMMARIZECOLUMNS groups; it does not aggregate unless you hand it something to aggregate with. A raw column becomes a list of distinct values, which is a sensible thing for a grouping function to return and a useless thing to put in a financial report.

Put differently: SUMMARIZECOLUMNS is not SUM, and Report Builder will not guess what you “really meant.” For reports designed to print, that literal-mindedness is a feature.

So use measures. Always.

Your semantic model likely already has measures. If it doesn’t, build them upstream in Power BI Desktop rather than fighting with DAX inside Report Builder.

Treat this as a rule rather than a preference: for any number you intend to display, use a measure defined in the semantic model, not a raw fact-table column.

In the Query Designer, measures carry a small calculator icon in the field list. Microsoft’s own guidance says the same, and the reasons go beyond correct row counts:

  • The definition lives in one place. If someone revises how net revenue is calculated, your paginated report inherits the change. If you summed a raw column yourself, it doesn’t.
  • Fewer rows cross the wire. A measure returns aggregated results. A raw column returns every distinct value and asks your report to deal with it.
  • It matches the on-screen report. Same measure, same number, no awkward conversation about which version is right.

If you need a number the model doesn’t have a measure for, treat that as a signal. Nine times out of ten the right fix is to add the measure to the semantic model, where every report can use it, rather than working around it inside one .rdl where nothing else can see it.

Dimension attributes are a different matter. Product name, region, customer, dates: drag those in as columns, because grouping is exactly what you want from them. The rule is about the numbers.

The shortcut: let Power BI write the query for you

Now that you know what a good query looks like, here’s the faster way to get one. You almost never have to write these by hand, and if there’s already an analytical report built on the same model, this is the first workflow to reach for.

Copy the query out of Power BI Desktop
1

Open the .pbix in Power BI Desktop and put a flat table on the canvas — a table, not a matrix. Drop in every field you want in the paginated report, using measures for the numbers.

2

Go to View and open Performance Analyzer.

3

Click Start recording, then Refresh visuals.

4

Expand the entry for your table and click Copy query.

5

Back in Report Builder, add a dataset, open the Query Designer, make sure DAX is selected, and switch off Design Mode. Paste the query in.

6

Click Execute Query (the ! button) to confirm it runs and returns what you expect.

Design Mode is worth knowing where to find. With it on you get the drag-and-drop grid. With it off you get the raw DAX text pane, which is the only place you can paste a query. If you ever open the Query Designer and find there’s nothing to drag onto, that’s the toggle.

Three things to watch for on the way through.

Delete the TOPN. Desktop often wraps its query in a TOPN clause to limit what a visual has to render on screen. Left in place, your paginated report will truncate with no obvious sign that it did. Take it out.
  • Turn off totals. Microsoft’s walkthrough has you slide the Totals toggle off before recording the query.
  • DirectQuery models need at least one measure. If your semantic model uses DirectQuery rather than import, Microsoft requires that the dataset include a measure.

Building one from scratch

Sometimes there’s no existing report to lift a query from. The Query Designer handles that too.

An empty Report Builder Query Designer with the model field list expanded on the left showing Measures, KPIs, Dim Customer, Dim Date, Dim Product and Smore Sales Table, and an empty query area reading "Drag levels or measures here to add to the query."
The empty Query Designer. Dimension attributes and measures both come from this list.
Build the query by hand
1

In the Report Data pane, right-click Datasets and choose Add Dataset.

2

Name it something you’ll recognize in three months, pick your data source, and click Query Designer.

3

Drag your dimension attributes and your measures across from the field list on the left.

4

Click OK. Report Builder writes the DAX for you.

Report Builder Query Designer with six fields dragged across and numbered one to six: RegionName, CustomerName, Category, ProductName, Total Quantity and Total Sales. The source fields are highlighted in the model tree on the left.
Four dimension attributes and two measures. Attributes left, measures right.

Execute the query, then click OK. You should end up with something close to this:

EVALUATE
SUMMARIZECOLUMNS (
    'Dim Customer'[RegionName],
    'Dim Customer'[CustomerName],
    'Dim Product'[Category],
    'Dim Product'[ProductName],
    "Total Quantity", 'Smore Sales Table'[Total Quantity],
    "Total Sales", 'Smore Sales Table'[Total Sales]
)
The Dataset Properties dialog showing the generated DAX query in the Query box: EVALUATE SUMMARIZECOLUMNS with the four dimension columns and the two named measures, with the OK button highlighted.
The generated DAX, ready to accept.

Click OK once more. While you’re in there, note the folder structure: Data Sources and Datasets are separate nodes in the Report Data pane, and a single data source can feed several datasets. That matters when one report needs two differently-shaped result sets from the same model.

Report Builder's Report Data pane showing Data Sources containing PowerBIBlogs_SmoreSales, and Datasets containing SmoreSales with its six fields: RegionName, CustomerName, Category, ProductName, Total_Quantity and Total_Sales.
One data source, one dataset, six fields. The dataset’s fields are what you lay out on the page.

Keep the field list short

You are building one wide flat table, and every column you add gets fetched every time the report runs — unless it ran in the last ten minutes, which Part 4 covers. Unlike a traditional Power BI report, there is nothing sitting behind this telling the report what to include.

Take a light hand. You only need the columns that actually have to print.

It’s tempting to pull in a few extra columns in case somebody asks later. Resist it. In an analytical model those columns cost you almost nothing; here they drive up refresh time every time someone runs the report. For the detail behind that, see Microsoft’s data retrieval guidance.

Cutting columns is only half the battle, because rows need trimming too. Cutting columns keeps the customer’s address out of a revenue report. It doesn’t stop the East sales team’s customers from showing up in the Midwest team’s report. That’s next.

DAX or MDX?

Use DAX.

MDX exists for a narrow set of cases: query-level calculated members, or server aggregates in non-detail groups. If you have no idea what those are, you don’t need MDX, and the DAX designer is the one Microsoft points you toward for semantic model connections.

Now lay the table

A dataset on its own displays nothing. It’s a result set sitting in memory waiting to be told where to go.

Report Builder's Insert ribbon tab with the Table button open and Insert Table highlighted in the dropdown, over a blank report design surface reading "Click to add title".
Insert → Table → Insert Table, then drop it on the design surface.
Report Builder design surface with a three-column table placeholder. Red arrows show fields being dragged from the dataset field list on the left into the table's Header and Data cells.
Drag fields from the dataset into the columns. Dimension attributes on the left, measures on the right, reads best in that order.
Report Builder design surface showing the completed six-column table with headers Region Name, Customer Name, Category, Product Name, Total Quantity and Total Sales, and a detail row of field placeholders beneath.
Six fields laid out. This is what the design surface should look like before you run it.

Click Run to preview, and you’ll get this.

Report Builder preview showing the rendered report with the six-column table populated with real data rows across regions South, Midwest and Northeast, product category Chocolate, and Total Quantity and Total Sales values.
Plain, unformatted, and running onto more pages than you want. The numbers are right, though.

What you’re looking at is a Tablix, Report Builder’s one control for tables, matrices and lists. It will look plain, almost certainly run onto more pages than you want, and the headers won’t repeat yet. All of that is fixed in Part 5.

Your numbers should be right now, though. Check the total against the model before you go any further, because everything from here on assumes the underlying data is correct.

To check, right-click the bottom row, select Insert Row, then Outside Group – Below.

Report Builder design surface with a right-click context menu open on the table's detail row, showing Insert Row expanded and Outside Group - Below highlighted.
Add a row outside the detail group to hold a grand total.

In the rightmost cell, type:

=Sum(Fields!Total_Sales.Value)
Report Builder design surface showing the new total row added below the detail row, with the expression =Sum(Fields!Total_Sales.Value) entered in the rightmost cell under Total Sales.
The grand total expression in the Total Sales column.
Check your number. Run the report again. If you used the sample files and set up the semantic model as described, the last row should read $2,968,210.33. Depending on your formatting you might see a plain decimal rather than currency — that’s cosmetic, and Part 5 deals with it.

Where this goes next

You have a dataset returning the right numbers and a table displaying them. What you don’t have is any control over how much data comes back, which matters the moment the report is aimed at a real audience rather than a test.

Nobody needs all 12,000 order lines, which this query groups down to 1,920 rows. The Midwest sales team needs the Midwest rows, East needs East, and finance needs last month’s numbers for everyone. Getting the report to return only that — and deciding whether the reader chooses or you choose for them — is the next post.

Next in this series — Part 4 Adding Parameters and Filters to Your Paginated Report

Need help with Power BI or Paginated Reports?

Whether you're building reports from scratch or troubleshooting a tricky parameter setup, our team has been in the weeds on this stuff. Let's talk.