<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Chris Webb&#039;s BI Blog</title>
	<atom:link href="https://blog.crossjoin.co.uk/feed/" rel="self" type="application/rss+xml" />
	<link>https://blog.crossjoin.co.uk</link>
	<description>Microsoft Fabric, Power BI, Analysis Services, DAX, M, MDX, Power Query, Power Pivot and Excel</description>
	<lastBuildDate>Sun, 27 Sep 2026 17:49:52 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	

<image>
	<url>https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2023/06/cropped-2023-headshot.jpg?fit=32%2C32&#038;ssl=1</url>
	<title>Chris Webb&#039;s BI Blog</title>
	<link>https://blog.crossjoin.co.uk</link>
	<width>32</width>
	<height>32</height>
</image> 
<site xmlns="com-wordpress:feed-additions:1">16411407</site>	<item>
		<title>Improvements To Power Query Integration In Power BI Report Builder</title>
		<link>https://blog.crossjoin.co.uk/2026/09/27/improvements-to-power-query-integration-in-power-bi-report-builder/</link>
					<comments>https://blog.crossjoin.co.uk/2026/09/27/improvements-to-power-query-integration-in-power-bi-report-builder/#respond</comments>
		
		<dc:creator><![CDATA[Chris Webb]]></dc:creator>
		<pubDate>Sun, 27 Sep 2026 17:49:52 +0000</pubDate>
				<category><![CDATA[Power BI Report Builder]]></category>
		<category><![CDATA[Power Query]]></category>
		<guid isPermaLink="false">https://blog.crossjoin.co.uk/?p=38950</guid>

					<description><![CDATA[There are some nice improvements to Power Query integration in the latest version of Power BI Report Builder that, while they are documented, didn&#8217;t get an official blog post but which I think deserve to be highlighted. First of all the &#8220;Get Data&#8221; button has been renamed &#8220;Power Query&#8221;: Secondly, and most importantly, there&#8217;s a &#8230; <a href="https://blog.crossjoin.co.uk/2026/09/27/improvements-to-power-query-integration-in-power-bi-report-builder/" class="more-link">Continue reading <span class="screen-reader-text">Improvements To Power Query Integration In Power BI Report Builder</span> <span class="meta-nav">&#8594;</span></a>]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">There are some nice improvements to Power Query integration in the latest version of Power BI Report Builder that, while they are <a href="https://learn.microsoft.com/en-us/power-bi/paginated-reports/report-builder/connect-snowflake-databricks-power-query-online">documented</a>, didn&#8217;t get an official blog post but which I think deserve to be highlighted. First of all the &#8220;Get Data&#8221; button has been renamed &#8220;Power Query&#8221;:</p>



<figure class="wp-block-image size-full"><a href="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/09/image-8.png?ssl=1"><img data-recalc-dims="1" decoding="async" width="240" height="121" data-attachment-id="38957" data-permalink="https://blog.crossjoin.co.uk/2026/09/27/improvements-to-power-query-integration-in-power-bi-report-builder/image-680/" data-orig-file="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/09/image-8.png?fit=240%2C121&amp;ssl=1" data-orig-size="240,121" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;,&quot;alt&quot;:&quot;&quot;}" data-image-title="image" data-image-description="" data-image-caption="" data-large-file="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/09/image-8.png?fit=240%2C121&amp;ssl=1" src="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/09/image-8.png?resize=240%2C121&#038;ssl=1" alt="" class="wp-image-38957"/></a></figure>



<p class="wp-block-paragraph">Secondly, and most importantly, there&#8217;s a new custom property tab for Power Query datasets:</p>



<figure class="wp-block-image size-full"><a href="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/09/image-6.png?ssl=1"><img data-recalc-dims="1" fetchpriority="high" decoding="async" width="789" height="639" data-attachment-id="38953" data-permalink="https://blog.crossjoin.co.uk/2026/09/27/improvements-to-power-query-integration-in-power-bi-report-builder/image-678/" data-orig-file="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/09/image-6.png?fit=789%2C639&amp;ssl=1" data-orig-size="789,639" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;,&quot;alt&quot;:&quot;&quot;}" data-image-title="image" data-image-description="" data-image-caption="" data-large-file="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/09/image-6.png?fit=789%2C639&amp;ssl=1" src="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/09/image-6.png?resize=789%2C639&#038;ssl=1" alt="" class="wp-image-38953" srcset="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/09/image-6.png?w=789&amp;ssl=1 789w, https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/09/image-6.png?resize=300%2C243&amp;ssl=1 300w, https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/09/image-6.png?resize=768%2C622&amp;ssl=1 768w" sizes="(max-width: 789px) 100vw, 789px" /></a></figure>



<p class="wp-block-paragraph">As well as showing the M code used for the dataset (at the top) and a list of any M parameters (at the bottom), you can now see the ID of the Cloud Connection used by the dataset in the middle of the pane, copy it, and then press the manage button to go to the &#8220;Manage Connections and Gateways&#8221; pane in the Fabric portal, paste the ID into the search box and find the Cloud Connection used by the dataset, so you can edit it or refresh the credentials if you need to:</p>



<figure class="wp-block-image size-large"><a href="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/09/image-7.png?ssl=1"><img data-recalc-dims="1" decoding="async" width="1024" height="373" data-attachment-id="38955" data-permalink="https://blog.crossjoin.co.uk/2026/09/27/improvements-to-power-query-integration-in-power-bi-report-builder/image-679/" data-orig-file="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/09/image-7.png?fit=1075%2C392&amp;ssl=1" data-orig-size="1075,392" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;,&quot;alt&quot;:&quot;&quot;}" data-image-title="image" data-image-description="" data-image-caption="" data-large-file="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/09/image-7.png?fit=1024%2C373&amp;ssl=1" src="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/09/image-7.png?resize=1024%2C373&#038;ssl=1" alt="" class="wp-image-38955" srcset="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/09/image-7.png?resize=1024%2C373&amp;ssl=1 1024w, https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/09/image-7.png?resize=300%2C109&amp;ssl=1 300w, https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/09/image-7.png?resize=768%2C280&amp;ssl=1 768w, https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/09/image-7.png?w=1075&amp;ssl=1 1075w" sizes="(max-width: 1024px) 100vw, 1024px" /></a></figure>



<p class="wp-block-paragraph">As a Power Query fan I have always been a big fan of its integration in Report Builder and this makes it much easier to use.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.crossjoin.co.uk/2026/09/27/improvements-to-power-query-integration-in-power-bi-report-builder/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">38950</post-id>	</item>
		<item>
		<title>Find Unused Objects In Power BI Semantic Models With Semantic Link Labs</title>
		<link>https://blog.crossjoin.co.uk/2026/09/20/find-unused-objects-in-power-bi-semantic-models-with-semantic-link-labs/</link>
					<comments>https://blog.crossjoin.co.uk/2026/09/20/find-unused-objects-in-power-bi-semantic-models-with-semantic-link-labs/#comments</comments>
		
		<dc:creator><![CDATA[Chris Webb]]></dc:creator>
		<pubDate>Sun, 20 Sep 2026 16:59:18 +0000</pubDate>
				<category><![CDATA[Power BI]]></category>
		<category><![CDATA[Semantic Link Labs]]></category>
		<category><![CDATA[Workspace Monitoring]]></category>
		<guid isPermaLink="false">https://blog.crossjoin.co.uk/?p=38899</guid>

					<description><![CDATA[A few weeks ago I wrote about how Semantic Link Labs now has tools with interactive UIs and showed how you could use this to view lineage and so Vertipaq-Analyzer-stuff in a notebook. I didn&#8217;t show what I think is the coolest new feature though: the ability to find the tables, columns and measures in &#8230; <a href="https://blog.crossjoin.co.uk/2026/09/20/find-unused-objects-in-power-bi-semantic-models-with-semantic-link-labs/" class="more-link">Continue reading <span class="screen-reader-text">Find Unused Objects In Power BI Semantic Models With Semantic Link Labs</span> <span class="meta-nav">&#8594;</span></a>]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">A few weeks ago I wrote about how <a href="https://blog.crossjoin.co.uk/2026/08/23/tools-with-interactive-uis-in-fabric-notebooks-with-semantic-link-labs/">Semantic Link Labs now has tools with interactive UIs</a> and showed how you could use this to view lineage and so Vertipaq-Analyzer-stuff in a notebook. I didn&#8217;t show what I think is the coolest new feature though: <a href="https://semantic-link-labs.readthedocs.io/en/stable/sempy_labs.semantic_model.html#sempy_labs.semantic_model.find_unused_objects">the ability to find the tables, columns and measures in a semantic model that aren&#8217;t used</a> and which therefore could be deleted. There are tons of excellent third-party tools that do this available already of course but the advantage of using Semantic Link Labs for this is that you can automate the process of finding unused columns and run it from a notebook and, crucially, you have two ways of finding those unused columns: from analysing the structure of downstream reports and from analysing DAX queries captured in Workspace Monitoring.</p>



<p class="wp-block-paragraph">To test this I used a simple semantic model with one table in a workspace with Workspace Monitoring enabled:</p>



<figure class="wp-block-image size-full"><a href="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/09/image-2.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" width="229" height="199" data-attachment-id="38904" data-permalink="https://blog.crossjoin.co.uk/2026/09/20/find-unused-objects-in-power-bi-semantic-models-with-semantic-link-labs/image-674/" data-orig-file="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/09/image-2.png?fit=229%2C199&amp;ssl=1" data-orig-size="229,199" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;,&quot;alt&quot;:&quot;&quot;}" data-image-title="image" data-image-description="" data-image-caption="" data-large-file="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/09/image-2.png?fit=229%2C199&amp;ssl=1" src="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/09/image-2.png?resize=229%2C199&#038;ssl=1" alt="" class="wp-image-38904"/></a></figure>



<p class="wp-block-paragraph">I then created a report with a single visual showing the Person Count measure broken down by gender:</p>



<figure class="wp-block-image size-full"><a href="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/09/image-3.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" width="590" height="376" data-attachment-id="38906" data-permalink="https://blog.crossjoin.co.uk/2026/09/20/find-unused-objects-in-power-bi-semantic-models-with-semantic-link-labs/image-675/" data-orig-file="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/09/image-3.png?fit=590%2C376&amp;ssl=1" data-orig-size="590,376" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;,&quot;alt&quot;:&quot;&quot;}" data-image-title="image" data-image-description="" data-image-caption="" data-large-file="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/09/image-3.png?fit=590%2C376&amp;ssl=1" src="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/09/image-3.png?resize=590%2C376&#038;ssl=1" alt="" class="wp-image-38906" srcset="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/09/image-3.png?w=590&amp;ssl=1 590w, https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/09/image-3.png?resize=300%2C191&amp;ssl=1 300w" sizes="auto, (max-width: 590px) 100vw, 590px" /></a></figure>



<p class="wp-block-paragraph">Next I created a notebook with the following code that uses <a href="https://semantic-link-labs.readthedocs.io/en/stable/sempy_labs.semantic_model.html#sempy_labs.semantic_model.find_unused_objects">find_unused_objects</a>:</p>


<div class="wp-block-code">
	<div class="cm-editor">
		<div class="cm-scroller">
			
<pre>
<code><div class="cm-line">%pip install semantic-link-labs</div><div class="cm-line"></div><div class="cm-line">import sempy_labs as labs</div><div class="cm-line"></div><div class="cm-line">labs.semantic_model.find_unused_objects(</div><div class="cm-line">    dataset = &quot;insertsemanticmodelidhere&quot;,</div><div class="cm-line">    workspace = &quot;insertworkspaceidhere&quot;,</div><div class="cm-line">    method = &quot;WorkspaceMonitoring&quot;,</div><div class="cm-line">    visualize=True</div><div class="cm-line">)</div></code></pre>
		</div>
	</div>
</div>


<p class="wp-block-paragraph">This displayed the following widget which queried Workspace Monitoring and found three DAX queries in the previous seven hours:</p>



<figure class="wp-block-image size-full"><a href="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/09/image-4.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" width="695" height="379" data-attachment-id="38909" data-permalink="https://blog.crossjoin.co.uk/2026/09/20/find-unused-objects-in-power-bi-semantic-models-with-semantic-link-labs/image-676/" data-orig-file="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/09/image-4.png?fit=695%2C379&amp;ssl=1" data-orig-size="695,379" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;,&quot;alt&quot;:&quot;&quot;}" data-image-title="image" data-image-description="" data-image-caption="" data-large-file="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/09/image-4.png?fit=695%2C379&amp;ssl=1" src="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/09/image-4.png?resize=695%2C379&#038;ssl=1" alt="" class="wp-image-38909" srcset="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/09/image-4.png?w=695&amp;ssl=1 695w, https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/09/image-4.png?resize=300%2C164&amp;ssl=1 300w" sizes="auto, (max-width: 695px) 100vw, 695px" /></a></figure>



<p class="wp-block-paragraph">Clicking the Analyze button showed me &#8211; as expected &#8211; that only the Gender and Person Count measures had been used in these three queries and that all the rest of the columns were unused:</p>



<figure class="wp-block-image size-full"><a href="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/09/image-5.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" width="695" height="405" data-attachment-id="38911" data-permalink="https://blog.crossjoin.co.uk/2026/09/20/find-unused-objects-in-power-bi-semantic-models-with-semantic-link-labs/image-677/" data-orig-file="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/09/image-5.png?fit=695%2C405&amp;ssl=1" data-orig-size="695,405" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;,&quot;alt&quot;:&quot;&quot;}" data-image-title="image" data-image-description="" data-image-caption="" data-large-file="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/09/image-5.png?fit=695%2C405&amp;ssl=1" src="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/09/image-5.png?resize=695%2C405&#038;ssl=1" alt="" class="wp-image-38911" srcset="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/09/image-5.png?w=695&amp;ssl=1 695w, https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/09/image-5.png?resize=300%2C175&amp;ssl=1 300w" sizes="auto, (max-width: 695px) 100vw, 695px" /></a></figure>



<p class="wp-block-paragraph">Of course you don&#8217;t need to use the widget and can get a pandas dataframe back instead.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.crossjoin.co.uk/2026/09/20/find-unused-objects-in-power-bi-semantic-models-with-semantic-link-labs/feed/</wfw:commentRss>
			<slash:comments>3</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">38899</post-id>	</item>
		<item>
		<title>Find What Changed And When In Your Power BI Semantic Model</title>
		<link>https://blog.crossjoin.co.uk/2026/09/13/find-what-changed-and-when-in-your-power-bi-semantic-model/</link>
					<comments>https://blog.crossjoin.co.uk/2026/09/13/find-what-changed-and-when-in-your-power-bi-semantic-model/#comments</comments>
		
		<dc:creator><![CDATA[Chris Webb]]></dc:creator>
		<pubDate>Sun, 13 Sep 2026 10:03:39 +0000</pubDate>
				<category><![CDATA[DAX]]></category>
		<category><![CDATA[DAX Studio]]></category>
		<category><![CDATA[Performance Tuning]]></category>
		<category><![CDATA[Power BI]]></category>
		<guid isPermaLink="false">https://blog.crossjoin.co.uk/?p=38871</guid>

					<description><![CDATA[Here&#8217;s a situation I&#8217;ve found myself in many times. You&#8217;re called to help someone whose Power BI report is suddenly very slow. You ask whether any changes were made to the semantic model around the time performance got worse and the answer is no, absolutely not. You then spend anything from a few hours to &#8230; <a href="https://blog.crossjoin.co.uk/2026/09/13/find-what-changed-and-when-in-your-power-bi-semantic-model/" class="more-link">Continue reading <span class="screen-reader-text">Find What Changed And When In Your Power BI Semantic Model</span> <span class="meta-nav">&#8594;</span></a>]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">Here&#8217;s a situation I&#8217;ve found myself in many times. You&#8217;re called to help someone whose Power BI report is suddenly very slow. You ask whether any changes were made to the semantic model around the time performance got worse and the answer is no, absolutely not. You then spend anything from a few hours to a few days trying to fix the problem and when you find it, it turns out that someone did make a &#8216;minor&#8217; change to the semantic model after all and this was the cause of it all. Wouldn&#8217;t it be good if you could see when things like measures were last changed? Well you can.</p>



<p class="wp-block-paragraph">Many of the DAX <a href="https://learn.microsoft.com/en-us/dax/info-functions-dax">INFO functions</a>, which allow you to query semantic model metadata, have a ModifiedTime column which tells you the date and time that an object was last changed. So for example the INFO.MEASURES() (but not INFO.VIEW.MEASURES() ) function will tell you the date and time each measure in your semantic model was modified. You can query it like so from either the DAX query view in Desktop or the Service, or DAX Studio:</p>


<div class="wp-block-code">
	<div class="cm-editor">
		<div class="cm-scroller">
			
<pre>
<code><div class="cm-line">EVALUATE</div><div class="cm-line">SELECTCOLUMNS (</div><div class="cm-line">    INFO.MEASURES (),</div><div class="cm-line">    &quot;Name&quot;, [Name],</div><div class="cm-line">    &quot;Last Modified&quot;, [ModifiedTime],</div><div class="cm-line">    &quot;Expression&quot;, [Expression]</div><div class="cm-line">)</div><div class="cm-line">ORDER BY [Last Modified] DESC</div></code></pre>
		</div>
	</div>
</div>


<p class="wp-block-paragraph">Here&#8217;s an example of the output of this query:</p>



<figure class="wp-block-image size-full"><a href="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/09/image.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" width="686" height="115" data-attachment-id="38877" data-permalink="https://blog.crossjoin.co.uk/2026/09/13/find-what-changed-and-when-in-your-power-bi-semantic-model/image-672/" data-orig-file="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/09/image.png?fit=686%2C115&amp;ssl=1" data-orig-size="686,115" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;,&quot;alt&quot;:&quot;&quot;}" data-image-title="image" data-image-description="" data-image-caption="" data-large-file="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/09/image.png?fit=686%2C115&amp;ssl=1" src="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/09/image.png?resize=686%2C115&#038;ssl=1" alt="" class="wp-image-38877" srcset="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/09/image.png?w=686&amp;ssl=1 686w, https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/09/image.png?resize=300%2C50&amp;ssl=1 300w" sizes="auto, (max-width: 686px) 100vw, 686px" /></a></figure>



<p class="wp-block-paragraph">Of course if you&#8217;re troubleshooting a problem you will want to look at more than just the measures. I therefore put together this rather lengthy DAX query which looks at measures, calculated columns, calculation groups and lots of other things and gives you a list of all the things that have been modified, sorted in descending order by modification date:</p>


<div class="wp-block-code">
	<div class="cm-editor">
		<div class="cm-scroller">
			
<pre>
<code><div class="cm-line">DEFINE</div><div class="cm-line">    /* Set to NOW() - 7 to see only the last week of changes */</div><div class="cm-line">    VAR _ChangedSince = DATE(1900, 1, 1)</div><div class="cm-line"></div><div class="cm-line">    /* Lookups reused across sections */</div><div class="cm-line">    VAR _Tables = SELECTCOLUMNS(INFO.TABLES(), &quot;TableID&quot;, [ID], &quot;TableName&quot;, [Name])</div><div class="cm-line">    VAR _Roles = SELECTCOLUMNS(INFO.ROLES(), &quot;RoleID&quot;, [ID], &quot;RoleName&quot;, [Name])</div><div class="cm-line">    VAR _Perspectives = SELECTCOLUMNS(INFO.PERSPECTIVES(), &quot;PerspectiveID&quot;, [ID], &quot;PerspectiveName&quot;, [Name])</div><div class="cm-line"></div><div class="cm-line">    /* Joined by the definition&apos;s own ObjectID: older models have no FormatStringDefinitionID column */</div><div class="cm-line">    VAR _FormatStringDefs = SELECTCOLUMNS(INFO.FORMATSTRINGDEFINITIONS(), &quot;OwnerID&quot;, [ObjectID], &quot;ModifiedTime&quot;, [ModifiedTime], &quot;Expression&quot;, [Expression])</div><div class="cm-line"></div><div class="cm-line">    /* Detail rows run on drillthrough / show-as-table; joined by ObjectID like format strings */</div><div class="cm-line">    VAR _DetailRowsDefs = SELECTCOLUMNS(INFO.DETAILROWSDEFINITIONS(), &quot;OwnerID&quot;, [ObjectID], &quot;ModifiedTime&quot;, [ModifiedTime], &quot;Expression&quot;, [Expression])</div><div class="cm-line"></div><div class="cm-line">    /* Bi-directional relationships appear once per direction: keep one row per relationship */</div><div class="cm-line">    VAR _RelNames = GROUPBY(INFO.VIEW.RELATIONSHIPS(), [ID], &quot;RelName&quot;, MINX(CURRENTGROUP(), [Relationship]))</div><div class="cm-line"></div><div class="cm-line">    /* ---------- 1. Calculation logic: DAX that runs at query time ---------- */</div><div class="cm-line">    VAR _Calculations =</div><div class="cm-line">        UNION(</div><div class="cm-line">            SELECTCOLUMNS(</div><div class="cm-line">                NATURALINNERJOIN(_Tables, SELECTCOLUMNS(INFO.CALCULATIONGROUPS(), &quot;TableID&quot;, [TableID], &quot;ModifiedTime&quot;, [ModifiedTime])),</div><div class="cm-line">                &quot;Object Type&quot;, &quot;Calculation Group&quot;, &quot;Name&quot;, [TableName], &quot;Last Modified&quot;, [ModifiedTime], &quot;Expression&quot;, &quot;&quot;</div><div class="cm-line">            ),</div><div class="cm-line">            SELECTCOLUMNS(INFO.CALCULATIONITEMS(),</div><div class="cm-line">                &quot;Object Type&quot;, &quot;Calculation Item&quot;, &quot;Name&quot;, [Name], &quot;Last Modified&quot;, [ModifiedTime], &quot;Expression&quot;, [Expression]),</div><div class="cm-line">            SELECTCOLUMNS(INFO.MEASURES(),</div><div class="cm-line">                &quot;Object Type&quot;, &quot;Measure&quot;, &quot;Name&quot;, [Name], &quot;Last Modified&quot;, [ModifiedTime], &quot;Expression&quot;, [Expression]),</div><div class="cm-line">            SELECTCOLUMNS(</div><div class="cm-line">                NATURALINNERJOIN(_FormatStringDefs, SELECTCOLUMNS(INFO.MEASURES(), &quot;OwnerID&quot;, [ID], &quot;Owner&quot;, &quot;measure &quot; &amp; [Name])),</div><div class="cm-line">                &quot;Object Type&quot;, &quot;Dynamic Format String&quot;, &quot;Name&quot;, &quot;Format string of &quot; &amp; [Owner], &quot;Last Modified&quot;, [ModifiedTime], &quot;Expression&quot;, [Expression]</div><div class="cm-line">            ),</div><div class="cm-line">            SELECTCOLUMNS(</div><div class="cm-line">                NATURALINNERJOIN(_FormatStringDefs, SELECTCOLUMNS(INFO.CALCULATIONITEMS(), &quot;OwnerID&quot;, [ID], &quot;Owner&quot;, &quot;calculation item &quot; &amp; [Name])),</div><div class="cm-line">                &quot;Object Type&quot;, &quot;Dynamic Format String&quot;, &quot;Name&quot;, &quot;Format string of &quot; &amp; [Owner], &quot;Last Modified&quot;, [ModifiedTime], &quot;Expression&quot;, [Expression]</div><div class="cm-line">            ),</div><div class="cm-line">            SELECTCOLUMNS(</div><div class="cm-line">                NATURALINNERJOIN(_DetailRowsDefs, SELECTCOLUMNS(INFO.MEASURES(), &quot;OwnerID&quot;, [ID], &quot;Owner&quot;, &quot;measure &quot; &amp; [Name])),</div><div class="cm-line">                &quot;Object Type&quot;, &quot;Detail Rows Expression&quot;, &quot;Name&quot;, &quot;Detail rows of &quot; &amp; [Owner], &quot;Last Modified&quot;, [ModifiedTime], &quot;Expression&quot;, [Expression]</div><div class="cm-line">            ),</div><div class="cm-line">            SELECTCOLUMNS(</div><div class="cm-line">                NATURALINNERJOIN(_DetailRowsDefs, SELECTCOLUMNS(INFO.TABLES(), &quot;OwnerID&quot;, [ID], &quot;Owner&quot;, &quot;table &quot; &amp; [Name])),</div><div class="cm-line">                &quot;Object Type&quot;, &quot;Detail Rows Expression&quot;, &quot;Name&quot;, &quot;Detail rows of &quot; &amp; [Owner], &quot;Last Modified&quot;, [ModifiedTime], &quot;Expression&quot;, [Expression]</div><div class="cm-line">            )</div><div class="cm-line">        )</div><div class="cm-line"></div><div class="cm-line">    /* ---------- 2. Model structure: what the engine has to scan and join ---------- */</div><div class="cm-line">    VAR _Structure =</div><div class="cm-line">        UNION(</div><div class="cm-line">            SELECTCOLUMNS(INFO.MODEL(),</div><div class="cm-line">                &quot;Object Type&quot;, &quot;Model&quot;, &quot;Name&quot;, [Name], &quot;Last Modified&quot;, [ModifiedTime], &quot;Expression&quot;, &quot;&quot;),</div><div class="cm-line">            SELECTCOLUMNS(</div><div class="cm-line">                NATURALINNERJOIN(</div><div class="cm-line">                    SELECTCOLUMNS(INFO.TABLES(), &quot;ID&quot;, [ID], &quot;ModifiedTime&quot;, [ModifiedTime]),</div><div class="cm-line">                    SELECTCOLUMNS(INFO.VIEW.TABLES(), &quot;ID&quot;, [ID], &quot;TableName&quot;, [Name], &quot;Expression&quot;, [Expression])</div><div class="cm-line">                ),</div><div class="cm-line">                &quot;Object Type&quot;, IF([Expression] = &quot;&quot;, &quot;Table&quot;, &quot;Calculated Table&quot;), &quot;Name&quot;, [TableName], &quot;Last Modified&quot;, [ModifiedTime], &quot;Expression&quot;, [Expression]</div><div class="cm-line">            ),</div><div class="cm-line">            SELECTCOLUMNS(</div><div class="cm-line">                NATURALINNERJOIN(</div><div class="cm-line">                    SELECTCOLUMNS(INFO.COLUMNS(), &quot;ID&quot;, [ID], &quot;ModifiedTime&quot;, [ModifiedTime], &quot;Expression&quot;, [Expression]),</div><div class="cm-line">                    SELECTCOLUMNS(FILTER(INFO.VIEW.COLUMNS(), [DataCategory] &lt;&gt; &quot;RowNumber&quot;), &quot;ID&quot;, [ID], &quot;ColumnName&quot;, &quot;&apos;&quot; &amp; [Table] &amp; &quot;&apos;[&quot; &amp; [Name] &amp; &quot;]&quot;)</div><div class="cm-line">                ),</div><div class="cm-line">                &quot;Object Type&quot;, IF([Expression] = &quot;&quot;, &quot;Column&quot;, &quot;Calculated Column&quot;), &quot;Name&quot;, [ColumnName], &quot;Last Modified&quot;, [ModifiedTime], &quot;Expression&quot;, [Expression]</div><div class="cm-line">            ),</div><div class="cm-line">            SELECTCOLUMNS(</div><div class="cm-line">                NATURALINNERJOIN(</div><div class="cm-line">                    SELECTCOLUMNS(INFO.RELATIONSHIPS(), &quot;ID&quot;, [ID], &quot;ModifiedTime&quot;, [ModifiedTime]),</div><div class="cm-line">                    SELECTCOLUMNS(_RelNames, &quot;ID&quot;, [ID], &quot;RelName&quot;, [RelName])</div><div class="cm-line">                ),</div><div class="cm-line">                &quot;Object Type&quot;, &quot;Relationship&quot;, &quot;Name&quot;, [RelName], &quot;Last Modified&quot;, [ModifiedTime], &quot;Expression&quot;, &quot;&quot;</div><div class="cm-line">            ),</div><div class="cm-line">            SELECTCOLUMNS(</div><div class="cm-line">                NATURALINNERJOIN(_Tables, SELECTCOLUMNS(INFO.HIERARCHIES(), &quot;TableID&quot;, [TableID], &quot;HierarchyName&quot;, [Name], &quot;ModifiedTime&quot;, [ModifiedTime])),</div><div class="cm-line">                &quot;Object Type&quot;, &quot;Hierarchy&quot;, &quot;Name&quot;, [TableName] &amp; &quot;[&quot; &amp; [HierarchyName] &amp; &quot;]&quot;, &quot;Last Modified&quot;, [ModifiedTime], &quot;Expression&quot;, &quot;&quot;</div><div class="cm-line">            )</div><div class="cm-line">        )</div><div class="cm-line"></div><div class="cm-line">    /* ---------- 3. Data loading: M queries, partitions, refresh ---------- */</div><div class="cm-line">    VAR _DataLoading =</div><div class="cm-line">        UNION(</div><div class="cm-line">            SELECTCOLUMNS(</div><div class="cm-line">                NATURALINNERJOIN(_Tables, SELECTCOLUMNS(INFO.PARTITIONS(), &quot;TableID&quot;, [TableID], &quot;PartitionName&quot;, [Name], &quot;ModifiedTime&quot;, [ModifiedTime], &quot;QueryDefinition&quot;, [QueryDefinition])),</div><div class="cm-line">                &quot;Object Type&quot;, &quot;Partition&quot;, &quot;Name&quot;, [TableName] &amp; &quot; / &quot; &amp; [PartitionName], &quot;Last Modified&quot;, [ModifiedTime], &quot;Expression&quot;, [QueryDefinition]</div><div class="cm-line">            ),</div><div class="cm-line">            SELECTCOLUMNS(INFO.EXPRESSIONS(),</div><div class="cm-line">                &quot;Object Type&quot;, &quot;M Expression / Parameter&quot;, &quot;Name&quot;, [Name], &quot;Last Modified&quot;, [ModifiedTime], &quot;Expression&quot;, [Expression]),</div><div class="cm-line">            SELECTCOLUMNS(</div><div class="cm-line">                NATURALINNERJOIN(</div><div class="cm-line">                    SELECTCOLUMNS(INFO.TABLES(), &quot;TableID&quot;, [ID], &quot;TableName&quot;, [Name], &quot;ModifiedTime&quot;, [ModifiedTime]),</div><div class="cm-line">                    SELECTCOLUMNS(INFO.REFRESHPOLICIES(), &quot;TableID&quot;, [TableID], &quot;SourceExpression&quot;, [SourceExpression])</div><div class="cm-line">                ),</div><div class="cm-line">                &quot;Object Type&quot;, &quot;Refresh Policy&quot;, &quot;Name&quot;, [TableName], &quot;Last Modified&quot;, [ModifiedTime], &quot;Expression&quot;, [SourceExpression]</div><div class="cm-line">            )</div><div class="cm-line">        )</div><div class="cm-line"></div><div class="cm-line">    /* ---------- 4. Security and perspectives ---------- */</div><div class="cm-line">    VAR _SecurityAndPerspectives =</div><div class="cm-line">        UNION(</div><div class="cm-line">            SELECTCOLUMNS(INFO.ROLES(),</div><div class="cm-line">                &quot;Object Type&quot;, &quot;Role&quot;, &quot;Name&quot;, [Name], &quot;Last Modified&quot;, [ModifiedTime], &quot;Expression&quot;, &quot;&quot;),</div><div class="cm-line">            SELECTCOLUMNS(</div><div class="cm-line">                NATURALINNERJOIN(_Tables, NATURALINNERJOIN(_Roles, SELECTCOLUMNS(INFO.TABLEPERMISSIONS(), &quot;RoleID&quot;, [RoleID], &quot;TableID&quot;, [TableID], &quot;ModifiedTime&quot;, [ModifiedTime], &quot;FilterExpression&quot;, [FilterExpression]))),</div><div class="cm-line">                &quot;Object Type&quot;, &quot;RLS Filter&quot;, &quot;Name&quot;, [RoleName] &amp; &quot; / &quot; &amp; [TableName], &quot;Last Modified&quot;, [ModifiedTime], &quot;Expression&quot;, [FilterExpression]</div><div class="cm-line">            ),</div><div class="cm-line">            SELECTCOLUMNS(INFO.PERSPECTIVES(),</div><div class="cm-line">                &quot;Object Type&quot;, &quot;Perspective&quot;, &quot;Name&quot;, [Name], &quot;Last Modified&quot;, [ModifiedTime], &quot;Expression&quot;, &quot;&quot;),</div><div class="cm-line">            SELECTCOLUMNS(</div><div class="cm-line">                NATURALINNERJOIN(_Tables, NATURALINNERJOIN(_Perspectives, SELECTCOLUMNS(INFO.PERSPECTIVETABLES(), &quot;PerspectiveID&quot;, [PerspectiveID], &quot;TableID&quot;, [TableID], &quot;ModifiedTime&quot;, [ModifiedTime]))),</div><div class="cm-line">                &quot;Object Type&quot;, &quot;Perspective Table&quot;, &quot;Name&quot;, [PerspectiveName] &amp; &quot; / &quot; &amp; [TableName], &quot;Last Modified&quot;, [ModifiedTime], &quot;Expression&quot;, &quot;&quot;</div><div class="cm-line">            )</div><div class="cm-line">        )</div><div class="cm-line"></div><div class="cm-line">    /* ---------- 5. OPTIONAL: newer compatibility levels only ----------</div><div class="cm-line">       UDFs and hybrid-table data coverage definitions don&apos;t exist on older models, and referencing</div><div class="cm-line">       them fails the WHOLE query at compile time with &quot;references an object or property that is</div><div class="cm-line">       unavailable in the current edition of the server&quot;. If you see that error, comment out this</div><div class="cm-line">       VAR and remove _NewerFeatures from the final UNION below. */</div><div class="cm-line">    VAR _NewerFeatures =</div><div class="cm-line">        UNION(</div><div class="cm-line">            SELECTCOLUMNS(INFO.USERDEFINEDFUNCTIONS(),</div><div class="cm-line">                &quot;Object Type&quot;, &quot;UDF&quot;, &quot;Name&quot;, [Name], &quot;Last Modified&quot;, [ModifiedTime], &quot;Expression&quot;, [Expression]),</div><div class="cm-line">            SELECTCOLUMNS(</div><div class="cm-line">                NATURALINNERJOIN(</div><div class="cm-line">                    SELECTCOLUMNS(INFO.PARTITIONS(), &quot;PartitionID&quot;, [ID], &quot;PartitionName&quot;, [Name]),</div><div class="cm-line">                    SELECTCOLUMNS(INFO.DATACOVERAGEDEFINITIONS(), &quot;PartitionID&quot;, [PartitionID], &quot;ModifiedTime&quot;, [ModifiedTime], &quot;Expression&quot;, [Expression])</div><div class="cm-line">                ),</div><div class="cm-line">                &quot;Object Type&quot;, &quot;Data Coverage Definition&quot;, &quot;Name&quot;, [PartitionName], &quot;Last Modified&quot;, [ModifiedTime], &quot;Expression&quot;, [Expression]</div><div class="cm-line">            )</div><div class="cm-line">        )</div><div class="cm-line"></div><div class="cm-line">EVALUATE</div><div class="cm-line">FILTER(</div><div class="cm-line">    UNION(_Calculations, _Structure, _DataLoading, _SecurityAndPerspectives</div><div class="cm-line">    , _NewerFeatures</div><div class="cm-line">    ),</div><div class="cm-line">    [Last Modified] &gt; _ChangedSince</div><div class="cm-line">)</div><div class="cm-line">ORDER BY [Last Modified] DESC</div></code></pre>
		</div>
	</div>
</div>


<figure class="wp-block-image size-full"><a href="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/09/image-1.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" width="889" height="515" data-attachment-id="38880" data-permalink="https://blog.crossjoin.co.uk/2026/09/13/find-what-changed-and-when-in-your-power-bi-semantic-model/image-673/" data-orig-file="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/09/image-1.png?fit=889%2C515&amp;ssl=1" data-orig-size="889,515" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;,&quot;alt&quot;:&quot;&quot;}" data-image-title="image" data-image-description="" data-image-caption="" data-large-file="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/09/image-1.png?fit=889%2C515&amp;ssl=1" src="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/09/image-1.png?resize=889%2C515&#038;ssl=1" alt="" class="wp-image-38880" srcset="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/09/image-1.png?w=889&amp;ssl=1 889w, https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/09/image-1.png?resize=300%2C174&amp;ssl=1 300w, https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/09/image-1.png?resize=768%2C445&amp;ssl=1 768w, https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/09/image-1.png?resize=740%2C430&amp;ssl=1 740w" sizes="auto, (max-width: 889px) 100vw, 889px" /></a></figure>



<p class="wp-block-paragraph">The part of the query that checks for changes in newer features, such as DAX UDFs, may error on older models with lower compatibility levels so you may need to comment that, and the part of the UNION that references it, out. Instructions on how to do this are in the comments in the query.</p>



<p class="wp-block-paragraph">It&#8217;s also worth pointing out that sometimes the modification dates change when you don&#8217;t expect them to. For example I saw that when I added a calculation group to my semantic model all the modification dates of my measures were changed too, probably because adding a semantic model in Desktop changes the discourage implicit measures property on the model automatically. But overall it seems to behave sensibly enough for it to be useful so give it a try and let me know what you think. I can also imagine it being useful to combine this information with the list of measures, columns etc that are touched by a given DAX query (something I wrote about <a href="https://blog.crossjoin.co.uk/2024/10/20/finding-the-columns-touched-by-a-dax-query/">here</a>) so you can see whether any objects that the query uses have changed recently.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.crossjoin.co.uk/2026/09/13/find-what-changed-and-when-in-your-power-bi-semantic-model/feed/</wfw:commentRss>
			<slash:comments>4</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">38871</post-id>	</item>
		<item>
		<title>Choosing A Power BI Storage Mode For Reporting On Data From Azure Databricks</title>
		<link>https://blog.crossjoin.co.uk/2026/09/06/choosing-a-power-bi-storage-mode-for-reporting-on-data-from-azure-databricks/</link>
					<comments>https://blog.crossjoin.co.uk/2026/09/06/choosing-a-power-bi-storage-mode-for-reporting-on-data-from-azure-databricks/#comments</comments>
		
		<dc:creator><![CDATA[Chris Webb]]></dc:creator>
		<pubDate>Sun, 06 Sep 2026 20:32:03 +0000</pubDate>
				<category><![CDATA[Composite Models]]></category>
		<category><![CDATA[Databricks]]></category>
		<category><![CDATA[Direct Lake]]></category>
		<category><![CDATA[DirectQuery]]></category>
		<category><![CDATA[Power BI]]></category>
		<guid isPermaLink="false">https://blog.crossjoin.co.uk/?p=38845</guid>

					<description><![CDATA[In case you haven&#8217;t already seen the blog post on the Power BI blog or the discussion on LinkedIn, we at Microsoft published a new white paper last week to help you decide which storage mode to use when you&#8217;re using Power BI to create semantic models and reports on data stored in Azure Databricks. &#8230; <a href="https://blog.crossjoin.co.uk/2026/09/06/choosing-a-power-bi-storage-mode-for-reporting-on-data-from-azure-databricks/" class="more-link">Continue reading <span class="screen-reader-text">Choosing A Power BI Storage Mode For Reporting On Data From Azure Databricks</span> <span class="meta-nav">&#8594;</span></a>]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">In case you haven&#8217;t already seen the blog post on the Power BI blog or the discussion on LinkedIn, we at Microsoft published a new white paper last week to help you decide which storage mode to use when you&#8217;re using Power BI to create semantic models and reports on data stored in Azure Databricks. You can find the announcement and the link to the paper <a href="https://community.fabric.microsoft.com/blog/fbc_pbiupdatesblog/modern-power-bi-architecture-choices-for-reporting-on-azure-databricks-a-perform/5364286">here</a>.</p>



<p class="wp-block-paragraph">While the paper was commissioned by Microsoft it was written by an independent expert, <a href="https://dataleaps.co.uk/">Liping Huang</a>, who has extensive expertise with Power BI and Databricks and who has worked for both Microsoft and Databricks in the past. Liping is someone I have a huge amount of professional respect for and I think she did a great job on a very tricky project. I think the end result is very honest and fair. I&#8217;d also like to call out Eiki Sui from my team (if you can read Japanese check out his <a href="https://marshal115.hatenablog.com/">blog </a>&#8211; if you don&#8217;t then browser translation tools work well) for providing the initial inspiration and managing the project on the Microsoft side. </p>



<p class="wp-block-paragraph">So what does the white paper say? Which storage mode is best? Unsurprisingly, it depends and you need to read the whole thing. In order to keep the scope manageable the paper doesn&#8217;t test every single possible storage mode scenario and it also focuses on performance and excludes cost and governance considerations. Direct Lake on OneLake comes out on top in the majority of tests but a Composite Model with a DirectQuery fact table, Dual mode dimension tables and Import mode aggregations is best for larger data volumes, similar to what I described in this <a href="https://blog.crossjoin.co.uk/2026/06/28/power-bi-directquery-mode-a-better-choice-than-you-might-think/">blog post</a>. Of course your data, semantic models and reports will be different so the main aim of the paper is to help you run your own tests to decide what works best for you. </p>



<p class="wp-block-paragraph"></p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.crossjoin.co.uk/2026/09/06/choosing-a-power-bi-storage-mode-for-reporting-on-data-from-azure-databricks/feed/</wfw:commentRss>
			<slash:comments>3</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">38845</post-id>	</item>
		<item>
		<title>Referencing Images And Other Files In Power BI Reports Using OneLake URLs</title>
		<link>https://blog.crossjoin.co.uk/2026/08/30/referencing-images-and-other-files-in-power-bi-reports-using-onelake-urls/</link>
					<comments>https://blog.crossjoin.co.uk/2026/08/30/referencing-images-and-other-files-in-power-bi-reports-using-onelake-urls/#comments</comments>
		
		<dc:creator><![CDATA[Chris Webb]]></dc:creator>
		<pubDate>Sun, 30 Aug 2026 17:24:52 +0000</pubDate>
				<category><![CDATA[OneLake]]></category>
		<category><![CDATA[Power BI]]></category>
		<guid isPermaLink="false">https://blog.crossjoin.co.uk/?p=38799</guid>

					<description><![CDATA[Several years ago I wrote a very popular blog post about how to store images for your reports inside your Power BI semantic model. It solved the problem of how you could use display images (for example of products) inside your reports without making those images available via a public URL or personal OneDrive Embed &#8230; <a href="https://blog.crossjoin.co.uk/2026/08/30/referencing-images-and-other-files-in-power-bi-reports-using-onelake-urls/" class="more-link">Continue reading <span class="screen-reader-text">Referencing Images And Other Files In Power BI Reports Using OneLake URLs</span> <span class="meta-nav">&#8594;</span></a>]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">Several years ago I wrote a very <a href="https://blog.crossjoin.co.uk/2019/05/19/storing-large-images-in-power-bi-datasets/">popular blog</a> post about how to store images for your reports inside your Power BI semantic model. It solved the problem of how you could use display images (for example of products) inside your reports without making those images available via a public URL or personal OneDrive Embed Codes. I was very proud of how efficient the M code to do this was but the code was complicated and storing images as text inside a semantic model makes refreshes a lot slower and increases the size of your semantic model in memory, so it&#8217;s not ideal. The good news is that, if you have enabled Fabric in your tenant, the August 2026 release of Power BI brings a much better way of solving this problem: you can now <a href="https://community.fabric.microsoft.com/blog/fbc_pbiupdatesblog/power-bi-august-2026-feature-summary/5348434#community-5348434-mcetoc_1k0fv07o1_16">store your images (and indeed other files) inside OneLake and reference them from there</a>. This means you can store your images in a secure location, alongside all of your other data, and make them available for use in Power BI. What&#8217;s more this doesn&#8217;t just work for images, it also works for other types of files such as GeoJSON files used by map visuals.</p>



<p class="wp-block-paragraph">To illustrate how this works, I created a semantic model containing data from the 2024 UK general election. The details of the model don&#8217;t matter that much except for the fact that there was a column called Country Name containing the distinct values England, Scotland, Wales and Northern Ireland, and a measure called Total Electorate. I published the model to a workspace and then, in the same workspace, created a lakehouse. In the Files section of the lakehouse I created a new folder and then uploaded five jpg files of the flags of England, Scotland, Wales and Northern Ireland as well as the <a href="https://en.wikipedia.org/wiki/Union_Jack">Union Jack</a>. </p>



<figure class="wp-block-image size-full"><a href="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-24.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" width="600" height="366" data-attachment-id="38805" data-permalink="https://blog.crossjoin.co.uk/2026/08/30/referencing-images-and-other-files-in-power-bi-reports-using-onelake-urls/image-666/" data-orig-file="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-24.png?fit=600%2C366&amp;ssl=1" data-orig-size="600,366" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;,&quot;alt&quot;:&quot;&quot;}" data-image-title="image" data-image-description="" data-image-caption="" data-large-file="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-24.png?fit=600%2C366&amp;ssl=1" src="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-24.png?resize=600%2C366&#038;ssl=1" alt="" class="wp-image-38805" srcset="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-24.png?w=600&amp;ssl=1 600w, https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-24.png?resize=300%2C183&amp;ssl=1 300w" sizes="auto, (max-width: 600px) 100vw, 600px" /></a></figure>



<p class="wp-block-paragraph">I made a note of  IDs of the workspace and lakehouse. Then, in the semantic model, I created a measure with the following definition which returned the url of the image in my lakehouse for the selected country or, if no country was selected, returned the url of the Union Jack:</p>


<div class="wp-block-code">
	<div class="cm-editor">
		<div class="cm-scroller">
			
<pre>
<code class="language-sql"><div class="cm-line">Flag <span class="tok-operator">=</span></div><div class="cm-line"><span class="tok-keyword">IF</span> <span class="tok-punctuation">(</span></div><div class="cm-line">    HASONEVALUE <span class="tok-punctuation">(</span> <span class="tok-string">&apos;Election&apos;</span><span class="tok-punctuation">[</span>Country name<span class="tok-punctuation">]</span> <span class="tok-punctuation">)</span><span class="tok-punctuation">,</span></div><div class="cm-line">    <span class="tok-string2">&quot;https://onelake.dfs.fabric.microsoft.com/insertworkspaceidhere/insertlakehouseidhere/Files/Flags/&quot;</span></div><div class="cm-line">        <span class="tok-operator">&amp;</span> SELECTEDVALUE <span class="tok-punctuation">(</span> <span class="tok-string">&apos;Election&apos;</span><span class="tok-punctuation">[</span>Country name<span class="tok-punctuation">]</span> <span class="tok-punctuation">)</span> <span class="tok-operator">&amp;</span> <span class="tok-string2">&quot;.jpg&quot;</span><span class="tok-punctuation">,</span></div><div class="cm-line">    <span class="tok-string2">&quot;https://onelake.dfs.fabric.microsoft.com/insertworkspaceidhere/insertlakehouseidhere/Files/Flags/United Kingdom.jpg&quot;</span></div><div class="cm-line"><span class="tok-punctuation">)</span></div><div class="cm-line"></div></code></pre>
		</div>
	</div>
</div>


<p class="wp-block-paragraph">I then set the Data Category property of this measure to be Image URL:</p>



<figure class="wp-block-image size-full"><a href="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-25.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" width="253" height="668" data-attachment-id="38808" data-permalink="https://blog.crossjoin.co.uk/2026/08/30/referencing-images-and-other-files-in-power-bi-reports-using-onelake-urls/image-667/" data-orig-file="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-25.png?fit=253%2C668&amp;ssl=1" data-orig-size="253,668" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;,&quot;alt&quot;:&quot;&quot;}" data-image-title="image" data-image-description="" data-image-caption="" data-large-file="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-25.png?fit=253%2C668&amp;ssl=1" src="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-25.png?resize=253%2C668&#038;ssl=1" alt="" class="wp-image-38808" srcset="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-25.png?w=253&amp;ssl=1 253w, https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-25.png?resize=114%2C300&amp;ssl=1 114w" sizes="auto, (max-width: 253px) 100vw, 253px" /></a></figure>



<p class="wp-block-paragraph">Finally I create a report with a table visual in, dragged in the Country Name column, the Flag measure and the Total Electorate measure, and saw the flag images displayed in the table:</p>



<figure class="wp-block-image size-full is-resized"><a href="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-26.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" width="284" height="376" data-attachment-id="38810" data-permalink="https://blog.crossjoin.co.uk/2026/08/30/referencing-images-and-other-files-in-power-bi-reports-using-onelake-urls/image-668/" data-orig-file="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-26.png?fit=284%2C376&amp;ssl=1" data-orig-size="284,376" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;,&quot;alt&quot;:&quot;&quot;}" data-image-title="image" data-image-description="" data-image-caption="" data-large-file="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-26.png?fit=284%2C376&amp;ssl=1" src="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-26.png?resize=284%2C376&#038;ssl=1" alt="" class="wp-image-38810" style="width:397px;height:auto" srcset="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-26.png?w=284&amp;ssl=1 284w, https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-26.png?resize=227%2C300&amp;ssl=1 227w" sizes="auto, (max-width: 284px) 100vw, 284px" /></a></figure>



<p class="wp-block-paragraph">I then uploaded a GeoJSON file containing the outlines of the countries of the United Kingdom from the Office for National Statistics <a href="https://geoportal.statistics.gov.uk/">Open Geography Portal</a> to another folder called GeoJSON in my lakehouse:</p>



<figure class="wp-block-image size-full"><a href="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-27.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" width="759" height="262" data-attachment-id="38812" data-permalink="https://blog.crossjoin.co.uk/2026/08/30/referencing-images-and-other-files-in-power-bi-reports-using-onelake-urls/image-669/" data-orig-file="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-27.png?fit=759%2C262&amp;ssl=1" data-orig-size="759,262" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;,&quot;alt&quot;:&quot;&quot;}" data-image-title="image" data-image-description="" data-image-caption="" data-large-file="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-27.png?fit=759%2C262&amp;ssl=1" src="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-27.png?resize=759%2C262&#038;ssl=1" alt="" class="wp-image-38812" srcset="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-27.png?w=759&amp;ssl=1 759w, https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-27.png?resize=300%2C104&amp;ssl=1 300w" sizes="auto, (max-width: 759px) 100vw, 759px" /></a></figure>



<p class="wp-block-paragraph">I viewed the Properties for the file and copied its URL:</p>



<figure class="wp-block-image size-full"><a href="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-29.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" width="292" height="679" data-attachment-id="38816" data-permalink="https://blog.crossjoin.co.uk/2026/08/30/referencing-images-and-other-files-in-power-bi-reports-using-onelake-urls/image-671/" data-orig-file="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-29.png?fit=292%2C679&amp;ssl=1" data-orig-size="292,679" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;,&quot;alt&quot;:&quot;&quot;}" data-image-title="image" data-image-description="" data-image-caption="" data-large-file="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-29.png?fit=292%2C679&amp;ssl=1" src="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-29.png?resize=292%2C679&#038;ssl=1" alt="" class="wp-image-38816" srcset="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-29.png?w=292&amp;ssl=1 292w, https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-29.png?resize=129%2C300&amp;ssl=1 129w" sizes="auto, (max-width: 292px) 100vw, 292px" /></a></figure>



<p class="wp-block-paragraph">I then created a Shape Map visual, dragged the Country Name and Electorate measures into it, went to the Map Settings properties and set the Type to &#8220;URL&#8221; and pasted in the URL of the GeoJSON file from OneLake into the Enter A URL box. This gave me a Shape Map showing the outline of the UK and colouring representing the size of the electorate:</p>



<figure class="wp-block-image size-full"><a href="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-28.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" width="716" height="728" data-attachment-id="38814" data-permalink="https://blog.crossjoin.co.uk/2026/08/30/referencing-images-and-other-files-in-power-bi-reports-using-onelake-urls/image-670/" data-orig-file="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-28.png?fit=716%2C728&amp;ssl=1" data-orig-size="716,728" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;,&quot;alt&quot;:&quot;&quot;}" data-image-title="image" data-image-description="" data-image-caption="" data-large-file="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-28.png?fit=716%2C728&amp;ssl=1" src="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-28.png?resize=716%2C728&#038;ssl=1" alt="" class="wp-image-38814" srcset="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-28.png?w=716&amp;ssl=1 716w, https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-28.png?resize=295%2C300&amp;ssl=1 295w" sizes="auto, (max-width: 716px) 100vw, 716px" /></a></figure>



<p class="wp-block-paragraph">[Note: at the time of writing this doesn&#8217;t work with the Azure Maps visual but this will be fixed soon]</p>



<p class="wp-block-paragraph">Nothing here in terms of displaying images or using GeoJSON files with maps in Power BI reports is new. What is new, as I said, is where the images and the GeoJSON files are stored. The ability to store these files in OneLake means no more workarounds are needed to work with dynamic images as in the flag example, and it also means that you never need to upload a GeoJSON file containing sensitive data used by a map visual &#8211; you just need to store the GeoJSON file in OneLake and if you need to change it you simply replace the file without having to edit the report. And of course you can now automate the loading of these files into OneLake in the same way that you automate the loading of other types of data. If you&#8217;re a Power BI shop that hasn&#8217;t enabled Fabric yet then this is one more reason to do so.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.crossjoin.co.uk/2026/08/30/referencing-images-and-other-files-in-power-bi-reports-using-onelake-urls/feed/</wfw:commentRss>
			<slash:comments>4</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">38799</post-id>	</item>
		<item>
		<title>Tools With Interactive UIs In Fabric Notebooks With Semantic Link Labs</title>
		<link>https://blog.crossjoin.co.uk/2026/08/23/tools-with-interactive-uis-in-fabric-notebooks-with-semantic-link-labs/</link>
					<comments>https://blog.crossjoin.co.uk/2026/08/23/tools-with-interactive-uis-in-fabric-notebooks-with-semantic-link-labs/#comments</comments>
		
		<dc:creator><![CDATA[Chris Webb]]></dc:creator>
		<pubDate>Sun, 23 Aug 2026 15:49:31 +0000</pubDate>
				<category><![CDATA[Fabric]]></category>
		<category><![CDATA[Power BI]]></category>
		<category><![CDATA[Semantic Link Labs]]></category>
		<guid isPermaLink="false">https://blog.crossjoin.co.uk/?p=38757</guid>

					<description><![CDATA[There&#8217;s so much going on in the Fabric community that it can be hard to keep up with it all. Semantic Link Labs is a great example: in the six months or so since I last had a proper look at it my colleague Michael Kovalsky has done a whole load of cool things and &#8230; <a href="https://blog.crossjoin.co.uk/2026/08/23/tools-with-interactive-uis-in-fabric-notebooks-with-semantic-link-labs/" class="more-link">Continue reading <span class="screen-reader-text">Tools With Interactive UIs In Fabric Notebooks With Semantic Link Labs</span> <span class="meta-nav">&#8594;</span></a>]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">There&#8217;s so much going on in the Fabric community that it can be hard to keep up with it all. <a href="https://github.com/microsoft/semantic-link-labs">Semantic Link Labs</a> is a great example: in the six months or so since I last had a proper look at it my colleague Michael Kovalsky has done a whole load of <a href="https://www.linkedin.com/in/michaelkovalsky/recent-activity/all/">cool things</a> and it wasn&#8217;t until I had a chat with him recently that I realised how much had changed. Most importantly, for someone old-fashioned like me who still likes tools with a UI, a lot of new functionality has been added which has a UI and is usable with minimal coding.</p>



<p class="wp-block-paragraph">To illustrate this, I created a new Fabric notebook in a workspace and installed Semantic Link Labs:</p>


<div class="wp-block-code">
	<div class="cm-editor">
		<div class="cm-scroller">
			
<pre>
<code class="language-python"><div class="cm-line">%<span class="tok-variableName">pip</span> <span class="tok-variableName">install</span> <span class="tok-variableName">semantic</span><span class="tok-operator">-</span><span class="tok-variableName">link</span><span class="tok-operator">-</span><span class="tok-variableName">labs</span></div></code></pre>
		</div>
	</div>
</div>


<p class="wp-block-paragraph">I then headed over to the Semantic Link Labs <a href="https://github.com/microsoft/semantic-link-labs/wiki/Code-Examples">Code Examples</a> and copied some of the code from there into cells in my notebook. For example, the following code:</p>


<div class="wp-block-code">
	<div class="cm-editor">
		<div class="cm-scroller">
			
<pre>
<code class="language-python"><div class="cm-line"><span class="tok-keyword">import</span> <span class="tok-variableName">sempy_labs</span><span class="tok-operator">.</span><span class="tok-variableName">semantic_model</span></div><div class="cm-line"></div><div class="cm-line"><span class="tok-variableName">sempy_labs</span><span class="tok-operator">.</span><span class="tok-propertyName">semantic_model</span><span class="tok-operator">.</span><span class="tok-propertyName">lineage_view</span><span class="tok-punctuation">(</span><span class="tok-punctuation">)</span></div></code></pre>
		</div>
	</div>
</div>


<p class="wp-block-paragraph">&#8230;opened up a tool for exploring report and semantic model lineage appearing within the notebook. I could connect to a semantic model:</p>



<figure class="wp-block-image size-large"><a href="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-21.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" width="1024" height="415" data-attachment-id="38764" data-permalink="https://blog.crossjoin.co.uk/2026/08/23/tools-with-interactive-uis-in-fabric-notebooks-with-semantic-link-labs/image-663/" data-orig-file="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-21.png?fit=1404%2C569&amp;ssl=1" data-orig-size="1404,569" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;,&quot;alt&quot;:&quot;&quot;}" data-image-title="image" data-image-description="" data-image-caption="" data-large-file="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-21.png?fit=1024%2C415&amp;ssl=1" src="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-21.png?resize=1024%2C415&#038;ssl=1" alt="" class="wp-image-38764" srcset="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-21.png?resize=1024%2C415&amp;ssl=1 1024w, https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-21.png?resize=300%2C122&amp;ssl=1 300w, https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-21.png?resize=768%2C311&amp;ssl=1 768w, https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-21.png?resize=1200%2C486&amp;ssl=1 1200w, https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-21.png?resize=1100%2C446&amp;ssl=1 1100w, https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-21.png?w=1404&amp;ssl=1 1404w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></figure>



<p class="wp-block-paragraph">&#8230;and then see which reports are connected to it and even <a href="https://github.com/microsoft/semantic-link-labs/releases/tag/0.16.0">look for broken visuals</a> in those reports:</p>



<figure class="wp-block-image size-large"><a href="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-22.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" width="1024" height="412" data-attachment-id="38766" data-permalink="https://blog.crossjoin.co.uk/2026/08/23/tools-with-interactive-uis-in-fabric-notebooks-with-semantic-link-labs/image-664/" data-orig-file="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-22.png?fit=1407%2C566&amp;ssl=1" data-orig-size="1407,566" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;,&quot;alt&quot;:&quot;&quot;}" data-image-title="image" data-image-description="" data-image-caption="" data-large-file="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-22.png?fit=1024%2C412&amp;ssl=1" src="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-22.png?resize=1024%2C412&#038;ssl=1" alt="" class="wp-image-38766" srcset="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-22.png?resize=1024%2C412&amp;ssl=1 1024w, https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-22.png?resize=300%2C121&amp;ssl=1 300w, https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-22.png?resize=768%2C309&amp;ssl=1 768w, https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-22.png?resize=1200%2C483&amp;ssl=1 1200w, https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-22.png?resize=1100%2C443&amp;ssl=1 1100w, https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-22.png?w=1407&amp;ssl=1 1407w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></figure>



<p class="wp-block-paragraph">There&#8217;s also a version of <a href="https://semantic-link-labs.readthedocs.io/en/stable/sempy_labs.html#sempy_labs.vertipaq_analyzer">Vertipaq Analyzer</a>:</p>


<div class="wp-block-code">
	<div class="cm-editor">
		<div class="cm-scroller">
			
<pre>
<code><div class="cm-line">import sempy_labs as labs</div><div class="cm-line"></div><div class="cm-line">dataset = &apos;insert id or name of semantic model here&apos;</div><div class="cm-line">workspace = &apos;insert id or name of workspace here&apos;</div><div class="cm-line"></div><div class="cm-line">x = labs.vertipaq_analyzer(dataset=dataset, workspace=workspace)</div></code></pre>
		</div>
	</div>
</div>


<figure class="wp-block-image size-large"><a href="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-23.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" width="1024" height="302" data-attachment-id="38770" data-permalink="https://blog.crossjoin.co.uk/2026/08/23/tools-with-interactive-uis-in-fabric-notebooks-with-semantic-link-labs/image-665/" data-orig-file="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-23.png?fit=1561%2C461&amp;ssl=1" data-orig-size="1561,461" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;,&quot;alt&quot;:&quot;&quot;}" data-image-title="image" data-image-description="" data-image-caption="" data-large-file="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-23.png?fit=1024%2C302&amp;ssl=1" src="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-23.png?resize=1024%2C302&#038;ssl=1" alt="" class="wp-image-38770" srcset="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-23.png?resize=1024%2C302&amp;ssl=1 1024w, https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-23.png?resize=300%2C89&amp;ssl=1 300w, https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-23.png?resize=768%2C227&amp;ssl=1 768w, https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-23.png?resize=1536%2C454&amp;ssl=1 1536w, https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-23.png?resize=1200%2C354&amp;ssl=1 1200w, https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-23.png?resize=1100%2C325&amp;ssl=1 1100w, https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-23.png?w=1561&amp;ssl=1 1561w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></figure>



<p class="wp-block-paragraph">&#8230;and a whole load of other things which probably deserve their own blog post. So if, like me, you had assumed that Semantic Link Labs was for people who like writing code rather than using a UI, take another look &#8211; you&#8217;ll probably find something useful.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.crossjoin.co.uk/2026/08/23/tools-with-interactive-uis-in-fabric-notebooks-with-semantic-link-labs/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">38757</post-id>	</item>
		<item>
		<title>Displaying The Output Of Detail Rows Expressions In Power BI Reports Using The Paginated Report Visual</title>
		<link>https://blog.crossjoin.co.uk/2026/08/16/displaying-the-output-of-detail-rows-expressions-in-power-bi-reports-using-the-paginated-report-visual/</link>
					<comments>https://blog.crossjoin.co.uk/2026/08/16/displaying-the-output-of-detail-rows-expressions-in-power-bi-reports-using-the-paginated-report-visual/#comments</comments>
		
		<dc:creator><![CDATA[Chris Webb]]></dc:creator>
		<pubDate>Sun, 16 Aug 2026 15:28:15 +0000</pubDate>
				<category><![CDATA[DAX]]></category>
		<category><![CDATA[Paginated reports]]></category>
		<category><![CDATA[Power BI]]></category>
		<guid isPermaLink="false">https://blog.crossjoin.co.uk/?p=38655</guid>

					<description><![CDATA[In last week&#8217;s post I mentioned that while Power BI reports (unlike Excel PivotTables) do not support the Detail Rows Expression feature, it is possible to partially work around this limitation by using the paginated report visual. In this post I&#8217;ll show you how I was able to do this and what is and isn&#8217;t &#8230; <a href="https://blog.crossjoin.co.uk/2026/08/16/displaying-the-output-of-detail-rows-expressions-in-power-bi-reports-using-the-paginated-report-visual/" class="more-link">Continue reading <span class="screen-reader-text">Displaying The Output Of Detail Rows Expressions In Power BI Reports Using The Paginated Report Visual</span> <span class="meta-nav">&#8594;</span></a>]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">In <a href="https://blog.crossjoin.co.uk/2026/08/09/using-detail-rows-expressions-to-drill-to-a-different-fact-table-in-power-bi/">last week&#8217;s post</a> I mentioned that while Power BI reports (unlike Excel PivotTables) do not support the <a href="https://www.sqlbi.com/articles/controlling-drillthrough-in-excel-pivottables-connected-to-power-bi-or-analysis-services/">Detail Rows Expression</a> feature, it is possible to <em>partially</em> work around this limitation by using the paginated report visual. In this post I&#8217;ll show you how I was able to do this and what is and isn&#8217;t possible.</p>



<p class="wp-block-paragraph">Starting with the same semantic model I used for last week&#8217;s post, already published, the first major task was to create a paginated report to show the data returned by a measure&#8217;s Detail Rows Expression. I opened Power BI Report Builder, created a new paginated report and created a connection back to that semantic model. Next I created two <a href="https://learn.microsoft.com/en-us/power-bi/paginated-reports/report-data/report-embedded-datasets-report-builder">datasets</a> (in the paginated report sense of the term) called Customer and Product that listed all the values from the Customer column of the Customer table and the Product column of the Product table. Here are the two DAX queries I used:</p>


<div class="wp-block-code">
	<div class="cm-editor">
		<div class="cm-scroller">
			
<pre>
<code><div class="cm-line">EVALUATE VALUES(&apos;Customer&apos;[Customer])</div><div class="cm-line"></div><div class="cm-line">EVALUATE VALUES(&apos;Product&apos;[Product])</div></code></pre>
		</div>
	</div>
</div>


<p class="wp-block-paragraph">I then created two paginated report parameters, also called Customer and Product, which were bound to these two datasets and which were set to allow multiple values. Here&#8217;s what the Customer parameter looked like:</p>



<figure class="wp-block-image size-full"><a href="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-10.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" width="577" height="485" data-attachment-id="38661" data-permalink="https://blog.crossjoin.co.uk/2026/08/16/displaying-the-output-of-detail-rows-expressions-in-power-bi-reports-using-the-paginated-report-visual/image-652/" data-orig-file="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-10.png?fit=577%2C485&amp;ssl=1" data-orig-size="577,485" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;,&quot;alt&quot;:&quot;&quot;}" data-image-title="image" data-image-description="" data-image-caption="" data-large-file="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-10.png?fit=577%2C485&amp;ssl=1" src="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-10.png?resize=577%2C485&#038;ssl=1" alt="" class="wp-image-38661" srcset="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-10.png?w=577&amp;ssl=1 577w, https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-10.png?resize=300%2C252&amp;ssl=1 300w" sizes="auto, (max-width: 577px) 100vw, 577px" /></a></figure>



<figure class="wp-block-image size-full"><a href="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-11.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" width="573" height="481" data-attachment-id="38663" data-permalink="https://blog.crossjoin.co.uk/2026/08/16/displaying-the-output-of-detail-rows-expressions-in-power-bi-reports-using-the-paginated-report-visual/image-653/" data-orig-file="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-11.png?fit=573%2C481&amp;ssl=1" data-orig-size="573,481" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;,&quot;alt&quot;:&quot;&quot;}" data-image-title="image" data-image-description="" data-image-caption="" data-large-file="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-11.png?fit=573%2C481&amp;ssl=1" src="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-11.png?resize=573%2C481&#038;ssl=1" alt="" class="wp-image-38663" srcset="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-11.png?w=573&amp;ssl=1 573w, https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-11.png?resize=300%2C252&amp;ssl=1 300w" sizes="auto, (max-width: 573px) 100vw, 573px" /></a></figure>



<p class="wp-block-paragraph">The Product parameter was set up the same way but bound to the Product dataset.</p>



<p class="wp-block-paragraph">I then created a third dataset called Drillthrough. To get the columns for the dataset I first bound it to this DAX query:</p>


<div class="wp-block-code">
	<div class="cm-editor">
		<div class="cm-scroller">
			
<pre>
<code><div class="cm-line">EVALUATE</div><div class="cm-line">DETAILROWS([Sales Amount])</div></code></pre>
		</div>
	</div>
</div>


<p class="wp-block-paragraph">Next I set up two query parameters on this dataset, also called Customer and Product, and bound them to the two report parameters created above:</p>



<figure class="wp-block-image size-full"><a href="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-12.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" width="682" height="640" data-attachment-id="38667" data-permalink="https://blog.crossjoin.co.uk/2026/08/16/displaying-the-output-of-detail-rows-expressions-in-power-bi-reports-using-the-paginated-report-visual/image-654/" data-orig-file="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-12.png?fit=682%2C640&amp;ssl=1" data-orig-size="682,640" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;,&quot;alt&quot;:&quot;&quot;}" data-image-title="image" data-image-description="" data-image-caption="" data-large-file="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-12.png?fit=682%2C640&amp;ssl=1" src="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-12.png?resize=682%2C640&#038;ssl=1" alt="" class="wp-image-38667" srcset="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-12.png?w=682&amp;ssl=1 682w, https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-12.png?resize=300%2C282&amp;ssl=1 300w" sizes="auto, (max-width: 682px) 100vw, 682px" /></a></figure>



<p class="wp-block-paragraph">I then changed the query for the dataset to the following so it could reference the two query parameters:</p>


<div class="wp-block-code">
	<div class="cm-editor">
		<div class="cm-scroller">
			
<pre>
<code><div class="cm-line">EVALUATE</div><div class="cm-line">CALCULATETABLE(</div><div class="cm-line">	DETAILROWS([Sales Amount]),</div><div class="cm-line">	RSCustomDaxFilter(@Customer,EqualToCondition,[Customer].[Customer],String),</div><div class="cm-line">	RSCustomDaxFilter(@Product,EqualToCondition,[Product].[Product],String)</div><div class="cm-line">)</div></code></pre>
		</div>
	</div>
</div>


<p class="wp-block-paragraph">Side note: if you&#8217;re wondering what the RSCustomDaxFilter() function is, it&#8217;s not a real DAX function but it&#8217;s a feature of paginated reports that allows you to handle multi-value parameters in DAX queries relatively easily. I blogged about it back in 2019 <a href="https://blog.crossjoin.co.uk/2019/11/03/power-bi-report-builder-and-rscustomdaxfilter/">here</a> and John Kerski has a good post on it <a href="https://www.kerski.tech/bringing-dataops-to-power-bi-part46/">here</a>. It looks like the feature has been improved since 2019 in that the above query gets translated to DAX that looks something like this:</p>


<div class="wp-block-code">
	<div class="cm-editor">
		<div class="cm-scroller">
			
<pre>
<code><div class="cm-line">EVALUATE</div><div class="cm-line">CALCULATETABLE (</div><div class="cm-line">    DETAILROWS ( [Sales Amount] ),</div><div class="cm-line">    FILTER (</div><div class="cm-line">        VALUES ( &apos;Customer&apos;[Customer] ),</div><div class="cm-line">        ( &apos;Customer&apos;[Customer] IN { &quot;Chris&quot;, &quot;Helen&quot; } )</div><div class="cm-line">    ),</div><div class="cm-line">    FILTER (</div><div class="cm-line">        VALUES ( &apos;Product&apos;[Product] ),</div><div class="cm-line">        ( &apos;Product&apos;[Product] IN { &quot;Apples&quot;, &quot;Oranges&quot; } )</div><div class="cm-line">    )</div><div class="cm-line">)</div></code></pre>
		</div>
	</div>
</div>


<p class="wp-block-paragraph">The DAX generated now uses the IN operator rather than the multiple OR conditions that it used to, which is an improvement.</p>



<p class="wp-block-paragraph">Finally I put a table on the report to display the output of the Drillthrough dataset. Here&#8217;s what the report looked like in design mode:</p>



<figure class="wp-block-image size-full"><a href="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-13.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" width="940" height="451" data-attachment-id="38673" data-permalink="https://blog.crossjoin.co.uk/2026/08/16/displaying-the-output-of-detail-rows-expressions-in-power-bi-reports-using-the-paginated-report-visual/image-655/" data-orig-file="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-13.png?fit=940%2C451&amp;ssl=1" data-orig-size="940,451" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;,&quot;alt&quot;:&quot;&quot;}" data-image-title="image" data-image-description="" data-image-caption="" data-large-file="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-13.png?fit=940%2C451&amp;ssl=1" src="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-13.png?resize=940%2C451&#038;ssl=1" alt="" class="wp-image-38673" srcset="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-13.png?w=940&amp;ssl=1 940w, https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-13.png?resize=300%2C144&amp;ssl=1 300w, https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-13.png?resize=768%2C368&amp;ssl=1 768w" sizes="auto, (max-width: 940px) 100vw, 940px" /></a></figure>



<p class="wp-block-paragraph">And here&#8217;s what it looked like when I ran it:</p>



<figure class="wp-block-image size-full"><a href="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-14.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" width="616" height="476" data-attachment-id="38676" data-permalink="https://blog.crossjoin.co.uk/2026/08/16/displaying-the-output-of-detail-rows-expressions-in-power-bi-reports-using-the-paginated-report-visual/image-656/" data-orig-file="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-14.png?fit=616%2C476&amp;ssl=1" data-orig-size="616,476" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;,&quot;alt&quot;:&quot;&quot;}" data-image-title="image" data-image-description="" data-image-caption="" data-large-file="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-14.png?fit=616%2C476&amp;ssl=1" src="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-14.png?resize=616%2C476&#038;ssl=1" alt="" class="wp-image-38676" srcset="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-14.png?w=616&amp;ssl=1 616w, https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-14.png?resize=300%2C232&amp;ssl=1 300w" sizes="auto, (max-width: 616px) 100vw, 616px" /></a></figure>



<p class="wp-block-paragraph">I then published the paginated report.</p>



<p class="wp-block-paragraph">The second major task was to use this paginated report in a Power BI report. I opened Power BI Desktop, created a live connection to my published semantic model, then created a page with a simple matrix visual on it showing the Sales Amount measure broken down by Customer and Product:</p>



<figure class="wp-block-image size-full"><a href="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-15.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" width="280" height="199" data-attachment-id="38680" data-permalink="https://blog.crossjoin.co.uk/2026/08/16/displaying-the-output-of-detail-rows-expressions-in-power-bi-reports-using-the-paginated-report-visual/image-657/" data-orig-file="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-15.png?fit=280%2C199&amp;ssl=1" data-orig-size="280,199" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;,&quot;alt&quot;:&quot;&quot;}" data-image-title="image" data-image-description="" data-image-caption="" data-large-file="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-15.png?fit=280%2C199&amp;ssl=1" src="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-15.png?resize=280%2C199&#038;ssl=1" alt="" class="wp-image-38680"/></a></figure>



<p class="wp-block-paragraph">I then created a second page and configured it as a <a href="https://www.mssqltips.com/sqlservertip/7763/power-bi-drill-through-new-report-user-interface/">drillthrough page</a> and configured it to accept drillthroughs on Customer and Product:</p>



<figure class="wp-block-image size-full"><a href="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-16.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" width="307" height="612" data-attachment-id="38683" data-permalink="https://blog.crossjoin.co.uk/2026/08/16/displaying-the-output-of-detail-rows-expressions-in-power-bi-reports-using-the-paginated-report-visual/image-658/" data-orig-file="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-16.png?fit=307%2C612&amp;ssl=1" data-orig-size="307,612" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;,&quot;alt&quot;:&quot;&quot;}" data-image-title="image" data-image-description="" data-image-caption="" data-large-file="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-16.png?fit=307%2C612&amp;ssl=1" src="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-16.png?resize=307%2C612&#038;ssl=1" alt="" class="wp-image-38683" srcset="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-16.png?w=307&amp;ssl=1 307w, https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-16.png?resize=150%2C300&amp;ssl=1 150w" sizes="auto, (max-width: 307px) 100vw, 307px" /></a></figure>



<p class="wp-block-paragraph">I then added a Paginated Report visual to the page, dragged the Customer and Product columns into the Parameters pane:</p>



<figure class="wp-block-image size-full"><a href="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-17.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" width="420" height="423" data-attachment-id="38686" data-permalink="https://blog.crossjoin.co.uk/2026/08/16/displaying-the-output-of-detail-rows-expressions-in-power-bi-reports-using-the-paginated-report-visual/image-659/" data-orig-file="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-17.png?fit=420%2C423&amp;ssl=1" data-orig-size="420,423" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;,&quot;alt&quot;:&quot;&quot;}" data-image-title="image" data-image-description="" data-image-caption="" data-large-file="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-17.png?fit=420%2C423&amp;ssl=1" src="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-17.png?resize=420%2C423&#038;ssl=1" alt="" class="wp-image-38686" srcset="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-17.png?w=420&amp;ssl=1 420w, https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-17.png?resize=298%2C300&amp;ssl=1 298w, https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-17.png?resize=150%2C150&amp;ssl=1 150w, https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-17.png?resize=200%2C200&amp;ssl=1 200w" sizes="auto, (max-width: 420px) 100vw, 420px" /></a></figure>



<p class="wp-block-paragraph">And then linked the visual up to the published paginated report and mapped the paginated report&#8217;s parameters to the parameters in the visual&#8217;s parameters pane:</p>



<figure class="wp-block-image size-full"><a href="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-18.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" width="970" height="339" data-attachment-id="38689" data-permalink="https://blog.crossjoin.co.uk/2026/08/16/displaying-the-output-of-detail-rows-expressions-in-power-bi-reports-using-the-paginated-report-visual/image-660/" data-orig-file="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-18.png?fit=970%2C339&amp;ssl=1" data-orig-size="970,339" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;,&quot;alt&quot;:&quot;&quot;}" data-image-title="image" data-image-description="" data-image-caption="" data-large-file="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-18.png?fit=970%2C339&amp;ssl=1" src="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-18.png?resize=970%2C339&#038;ssl=1" alt="" class="wp-image-38689" srcset="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-18.png?w=970&amp;ssl=1 970w, https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-18.png?resize=300%2C105&amp;ssl=1 300w, https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-18.png?resize=768%2C268&amp;ssl=1 768w" sizes="auto, (max-width: 970px) 100vw, 970px" /></a></figure>



<p class="wp-block-paragraph">Finished! With all that done I could right-click on a cell in the matrix visual and drill through to the paginated report visual on the other page:</p>



<figure class="wp-block-image size-full"><a href="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-19.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" width="685" height="477" data-attachment-id="38692" data-permalink="https://blog.crossjoin.co.uk/2026/08/16/displaying-the-output-of-detail-rows-expressions-in-power-bi-reports-using-the-paginated-report-visual/image-661/" data-orig-file="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-19.png?fit=685%2C477&amp;ssl=1" data-orig-size="685,477" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;,&quot;alt&quot;:&quot;&quot;}" data-image-title="image" data-image-description="" data-image-caption="" data-large-file="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-19.png?fit=685%2C477&amp;ssl=1" src="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-19.png?resize=685%2C477&#038;ssl=1" alt="" class="wp-image-38692" srcset="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-19.png?w=685&amp;ssl=1 685w, https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-19.png?resize=300%2C209&amp;ssl=1 300w" sizes="auto, (max-width: 685px) 100vw, 685px" /></a></figure>



<figure class="wp-block-image size-full"><a href="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-20.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" width="533" height="365" data-attachment-id="38695" data-permalink="https://blog.crossjoin.co.uk/2026/08/16/displaying-the-output-of-detail-rows-expressions-in-power-bi-reports-using-the-paginated-report-visual/image-662/" data-orig-file="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-20.png?fit=533%2C365&amp;ssl=1" data-orig-size="533,365" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;,&quot;alt&quot;:&quot;&quot;}" data-image-title="image" data-image-description="" data-image-caption="" data-large-file="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-20.png?fit=533%2C365&amp;ssl=1" src="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-20.png?resize=533%2C365&#038;ssl=1" alt="" class="wp-image-38695" srcset="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-20.png?w=533&amp;ssl=1 533w, https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-20.png?resize=300%2C205&amp;ssl=1 300w" sizes="auto, (max-width: 533px) 100vw, 533px" /></a></figure>



<p class="wp-block-paragraph">There is, however, one big problem with this approach: it is hard-coded to work with just one measure. If you have multiple measures in your source visual then you have no way of knowing which measure a user has clicked on &#8211; so there&#8217;s no way you could pass that measure&#8217;s name to the paginated report. This is a limitation of the drill through feature in Power BI; the only workaround I can think of would be to either use calculation groups or the measures table technique (as described <a href="https://community.fabric.microsoft.com/t5/Desktop/Drill-through-for-calculated-measure/m-p/1086091">here</a>) instead of multiple measures so that you can capture the selection of the &#8220;measure&#8221; as the selection on a column.</p>



<p class="wp-block-paragraph">I still hope that one day that workarounds like this won&#8217;t be necessary and that Power BI reports support drill to detail in the same way that Excel PivotTables do. If you agree, please leave a comment!</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.crossjoin.co.uk/2026/08/16/displaying-the-output-of-detail-rows-expressions-in-power-bi-reports-using-the-paginated-report-visual/feed/</wfw:commentRss>
			<slash:comments>5</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">38655</post-id>	</item>
		<item>
		<title>Using Detail Rows Expressions To Drill To A Different Fact Table In Power BI</title>
		<link>https://blog.crossjoin.co.uk/2026/08/09/using-detail-rows-expressions-to-drill-to-a-different-fact-table-in-power-bi/</link>
					<comments>https://blog.crossjoin.co.uk/2026/08/09/using-detail-rows-expressions-to-drill-to-a-different-fact-table-in-power-bi/#comments</comments>
		
		<dc:creator><![CDATA[Chris Webb]]></dc:creator>
		<pubDate>Sun, 09 Aug 2026 21:26:19 +0000</pubDate>
				<category><![CDATA[Aggregations]]></category>
		<category><![CDATA[DirectQuery]]></category>
		<category><![CDATA[Import Mode]]></category>
		<category><![CDATA[Power BI]]></category>
		<guid isPermaLink="false">https://blog.crossjoin.co.uk/?p=38611</guid>

					<description><![CDATA[If you have a DirectQuery fact table in Power BI you can use user-defined aggregations to improve query performance; querying a smaller, summarised copy of your data in an Import mode aggregation table is always going to be faster than querying a large fact table containing all your detail data that is in DirectQuery mode. &#8230; <a href="https://blog.crossjoin.co.uk/2026/08/09/using-detail-rows-expressions-to-drill-to-a-different-fact-table-in-power-bi/" class="more-link">Continue reading <span class="screen-reader-text">Using Detail Rows Expressions To Drill To A Different Fact Table In Power BI</span> <span class="meta-nav">&#8594;</span></a>]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">If you have a DirectQuery fact table in Power BI you can use user-defined <a href="https://learn.microsoft.com/en-us/power-bi/transform-model/aggregations-advanced">aggregations</a> to improve query performance; querying a smaller, summarised copy of your data in an Import mode aggregation table is always going to be faster than querying a large fact table containing all your detail data that is in DirectQuery mode. What&#8217;s more a composite model like this can have a much smaller footprint in memory than a model where all your tables are in Import or Direct Lake mode, which means you can use a smaller Fabric capacity SKU. However, in some cases you can take the same tables that you would use to create a composite model like this and solve the same problem slightly differently without using aggregations.</p>



<p class="wp-block-paragraph">To illustrate, consider the following semantic model:</p>



<figure class="wp-block-image size-full"><a href="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-6.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" width="945" height="543" data-attachment-id="38627" data-permalink="https://blog.crossjoin.co.uk/2026/08/09/using-detail-rows-expressions-to-drill-to-a-different-fact-table-in-power-bi/image-648/" data-orig-file="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-6.png?fit=945%2C543&amp;ssl=1" data-orig-size="945,543" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;,&quot;alt&quot;:&quot;&quot;}" data-image-title="image" data-image-description="" data-image-caption="" data-large-file="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-6.png?fit=945%2C543&amp;ssl=1" src="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-6.png?resize=945%2C543&#038;ssl=1" alt="" class="wp-image-38627" srcset="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-6.png?w=945&amp;ssl=1 945w, https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-6.png?resize=300%2C172&amp;ssl=1 300w, https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-6.png?resize=768%2C441&amp;ssl=1 768w" sizes="auto, (max-width: 945px) 100vw, 945px" /></a></figure>



<p class="wp-block-paragraph">There are two dimension tables in Dual mode, a totally hidden fact table called SalesDetail in DirectQuery mode which contains transaction-level data:</p>



<figure class="wp-block-image size-full"><a href="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-4.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" width="383" height="249" data-attachment-id="38620" data-permalink="https://blog.crossjoin.co.uk/2026/08/09/using-detail-rows-expressions-to-drill-to-a-different-fact-table-in-power-bi/image-646/" data-orig-file="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-4.png?fit=383%2C249&amp;ssl=1" data-orig-size="383,249" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;,&quot;alt&quot;:&quot;&quot;}" data-image-title="image" data-image-description="" data-image-caption="" data-large-file="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-4.png?fit=383%2C249&amp;ssl=1" src="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-4.png?resize=383%2C249&#038;ssl=1" alt="" class="wp-image-38620" srcset="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-4.png?w=383&amp;ssl=1 383w, https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-4.png?resize=300%2C195&amp;ssl=1 300w" sizes="auto, (max-width: 383px) 100vw, 383px" /></a></figure>



<p class="wp-block-paragraph">&#8230;and a fact table called SalesSummary in Import mode which contains an aggregated copy of the same data:</p>



<figure class="wp-block-image size-full"><a href="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-5.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" width="292" height="156" data-attachment-id="38624" data-permalink="https://blog.crossjoin.co.uk/2026/08/09/using-detail-rows-expressions-to-drill-to-a-different-fact-table-in-power-bi/image-647/" data-orig-file="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-5.png?fit=292%2C156&amp;ssl=1" data-orig-size="292,156" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;,&quot;alt&quot;:&quot;&quot;}" data-image-title="image" data-image-description="" data-image-caption="" data-large-file="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-5.png?fit=292%2C156&amp;ssl=1" src="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-5.png?resize=292%2C156&#038;ssl=1" alt="" class="wp-image-38624"/></a></figure>



<p class="wp-block-paragraph">There is one visible measure called Sales Amount which sums up data from the Sales column on the SalesSummary table:</p>


<div class="wp-block-code">
	<div class="cm-editor">
		<div class="cm-scroller">
			
<pre>
<code class="language-mathematica"><div class="cm-line"><span class="tok-keyword">Sales</span> <span class="tok-keyword">Amount</span> <span class="tok-operator">=</span> <span class="tok-keyword">SUM</span><span class="tok-punctuation">(</span><span class="tok-keyword">SalesSummary</span><span class="tok-punctuation">[</span><span class="tok-keyword">Sales</span><span class="tok-punctuation">])</span></div></code></pre>
		</div>
	</div>
</div>


<p class="wp-block-paragraph">At this point, an end user would only be able to query data from the SalesSummary table &#8211; which would be nice and fast because they are querying the aggregated data. But since the SalesDetail table is hidden there&#8217;s no way an end user can query it (or at least query it <em>easily</em> because remember, folks, hiding an object is not security). So how can they get at that detailed, transaction-level data that all end users love?</p>



<p class="wp-block-paragraph">The answer is through the use of Detail Rows Expressions, the finest feature in the whole of Power BI that nobody knows about. Marco has a great article on it <a href="https://www.sqlbi.com/articles/controlling-drillthrough-in-excel-pivottables-connected-to-power-bi-or-analysis-services/">here</a> that I suggest you read but basically it allows you to configure a DAX table expression associated with a measure that is usually used to show all the rows that contribute to the value that the measure displays. I&#8217;m going to use it that way here but the important point about it is that you can use it to return a table expression from anywhere in your semantic model &#8211; not just the table where your measure gets its data.</p>



<p class="wp-block-paragraph">So for example, I can set the Detail Rows Expression on the Sales Amount measure to this:</p>


<div class="wp-block-code">
	<div class="cm-editor">
		<div class="cm-scroller">
			
<pre>
<code class="language-sql"><div class="cm-line">SELECTCOLUMNS <span class="tok-punctuation">(</span></div><div class="cm-line">    <span class="tok-string">&apos;SalesDetail&apos;</span><span class="tok-punctuation">,</span></div><div class="cm-line">    <span class="tok-string2">&quot;Order ID&quot;</span><span class="tok-punctuation">,</span> <span class="tok-string">&apos;SalesDetail&apos;</span><span class="tok-punctuation">[</span>OrderID<span class="tok-punctuation">]</span><span class="tok-punctuation">,</span></div><div class="cm-line">    <span class="tok-string2">&quot;Product&quot;</span><span class="tok-punctuation">,</span> <span class="tok-string">&apos;SalesDetail&apos;</span><span class="tok-punctuation">[</span>Product<span class="tok-punctuation">]</span><span class="tok-punctuation">,</span></div><div class="cm-line">    <span class="tok-string2">&quot;Customer&quot;</span><span class="tok-punctuation">,</span> <span class="tok-string">&apos;SalesDetail&apos;</span><span class="tok-punctuation">[</span>Customer<span class="tok-punctuation">]</span><span class="tok-punctuation">,</span></div><div class="cm-line">    <span class="tok-string2">&quot;Sales Amount&quot;</span><span class="tok-punctuation">,</span> <span class="tok-string">&apos;SalesDetail&apos;</span><span class="tok-punctuation">[</span>Sales<span class="tok-punctuation">]</span></div><div class="cm-line"><span class="tok-punctuation">)</span></div></code></pre>
		</div>
	</div>
</div>


<p class="wp-block-paragraph">Even though the Sales Amount measure sums up data from the Sales column on the <strong>SalesSummary</strong> table, when an end user clicks Show Details on the Sales Amount measure in an Excel PivotTable:</p>



<figure class="wp-block-image size-full"><a href="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-7.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" width="526" height="608" data-attachment-id="38635" data-permalink="https://blog.crossjoin.co.uk/2026/08/09/using-detail-rows-expressions-to-drill-to-a-different-fact-table-in-power-bi/image-649/" data-orig-file="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-7.png?fit=526%2C608&amp;ssl=1" data-orig-size="526,608" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;,&quot;alt&quot;:&quot;&quot;}" data-image-title="image" data-image-description="" data-image-caption="" data-large-file="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-7.png?fit=526%2C608&amp;ssl=1" src="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-7.png?resize=526%2C608&#038;ssl=1" alt="" class="wp-image-38635" srcset="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-7.png?w=526&amp;ssl=1 526w, https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-7.png?resize=260%2C300&amp;ssl=1 260w" sizes="auto, (max-width: 526px) 100vw, 526px" /></a></figure>



<p class="wp-block-paragraph">&#8230;they can get the detail rows from the <strong>SalesDetail</strong> table showing all the order data for the cell they clicked on:</p>



<figure class="wp-block-image size-full"><a href="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-8.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" width="419" height="142" data-attachment-id="38638" data-permalink="https://blog.crossjoin.co.uk/2026/08/09/using-detail-rows-expressions-to-drill-to-a-different-fact-table-in-power-bi/image-650/" data-orig-file="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-8.png?fit=419%2C142&amp;ssl=1" data-orig-size="419,142" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;,&quot;alt&quot;:&quot;&quot;}" data-image-title="image" data-image-description="" data-image-caption="" data-large-file="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-8.png?fit=419%2C142&amp;ssl=1" src="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-8.png?resize=419%2C142&#038;ssl=1" alt="" class="wp-image-38638" srcset="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-8.png?w=419&amp;ssl=1 419w, https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-8.png?resize=300%2C102&amp;ssl=1 300w" sizes="auto, (max-width: 419px) 100vw, 419px" /></a></figure>



<p class="wp-block-paragraph">Thus the Detail Rows Expression allows you to &#8220;drill to detail&#8221; from the SalesSummary table to the hidden SalesDetail table. This works because the Customer and Product dimension tables are related to both SalesSummary and SalesDetail, so whatever selection has been applied to SalesSummary is also be applied to SalesDetail.</p>



<p class="wp-block-paragraph">What are the advantages of doing this instead of configuring SalesSummary as an aggregation table? Because data from the SalesDetail table is only available via the Detail Rows Expression feature then it gives you as a semantic model developer a lot more control over how end users access that detail fact data: you can make sure they get the rows they need in the most efficient way because you have total control over the DAX used and you can also prevent them from dumping out large amounts of data by writing controls on how much data can be returned. For example you could write some logic in your Detail Rows Expression that ensures data is only returned if a single date is selected. With this approach users would not be able to drag all the Order IDs into a PivotTable (potentially running a very expensive query) because they could not see the Order ID column to do so.</p>



<p class="wp-block-paragraph">There are plenty of disadvantages to this technique too though, compared to building aggregations. First and foremost you can only make use of Detail Rows Expressions in Excel PivotTables; I wish we supported them natively in Power BI reports but we don&#8217;t. It is possible, however, to use the Paginated Report Visual in a Power BI report to partially work around this limitation and I&#8217;ll show you how in my next post. Also, while this allows you to have one Import mode table with aggregated data and one DirectQuery fact table, with aggregations you can have multiple Import mode aggregation tables for a single DirectQuery fact table which can result in even better performance. And of course it might be that you actually want your end users to see and access all the data in your DirectQuery fact table and query it however they want.</p>



<p class="wp-block-paragraph">This is in fact an old technique I remember from the days of Analysis Services Multidimensional, but it has somehow been forgotten. I wanted to blog about it, though, because as DirectQuery and composite models become more and more important I think it deserves to be used more.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.crossjoin.co.uk/2026/08/09/using-detail-rows-expressions-to-drill-to-a-different-fact-table-in-power-bi/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">38611</post-id>	</item>
		<item>
		<title>Analysing Power BI Data Using Copilot In Excel</title>
		<link>https://blog.crossjoin.co.uk/2026/08/02/analysing-power-bi-data-using-copilot-in-excel/</link>
					<comments>https://blog.crossjoin.co.uk/2026/08/02/analysing-power-bi-data-using-copilot-in-excel/#comments</comments>
		
		<dc:creator><![CDATA[Chris Webb]]></dc:creator>
		<pubDate>Sun, 02 Aug 2026 17:52:45 +0000</pubDate>
				<category><![CDATA[Copilot]]></category>
		<category><![CDATA[Excel]]></category>
		<category><![CDATA[Power BI]]></category>
		<guid isPermaLink="false">https://blog.crossjoin.co.uk/?p=38543</guid>

					<description><![CDATA[This week there was another big Copilot-related announcement for Power BI &#8211; but on the Excel blog. You can now analyse data from Power BI semantic models using Copilot in Excel. Full details on how to enable this are in the docs here, but what does it look like? Using the same semantic model from &#8230; <a href="https://blog.crossjoin.co.uk/2026/08/02/analysing-power-bi-data-using-copilot-in-excel/" class="more-link">Continue reading <span class="screen-reader-text">Analysing Power BI Data Using Copilot In Excel</span> <span class="meta-nav">&#8594;</span></a>]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">This week there was another big Copilot-related announcement for Power BI &#8211; but on the <a href="https://techcommunity.microsoft.com/blog/ExcelBlog/whats-new-in-excel-july-2026/4523403">Excel blog</a>. You can now analyse data from Power BI semantic models using Copilot in Excel. Full details on how to enable this are in the docs <a href="https://support.microsoft.com/en-us/excel/copilot/copilot-in-excel-power-bi">here</a>, but what does it look like?</p>



<p class="wp-block-paragraph">Using the same semantic model from last week&#8217;s <a href="https://blog.crossjoin.co.uk/2026/07/26/power-bi-m365-copilot-and-the-importance-of-dax-udfs/">blog post</a> on doing ABC analysis in the M365 Copilot app, I opened Excel, opened the Copilot pane and entered the same prompt:</p>


<div class="wp-block-code">
	<div class="cm-editor">
		<div class="cm-scroller">
			
<pre>
<code class="language-html"><div class="cm-line">Use this semantic model <span class="tok-punctuation">&lt;</span><span class="tok-typeName">insert</span> <span class="tok-propertyName">URL</span> <span class="tok-propertyName">of</span> <span class="tok-propertyName">semantic</span> <span class="tok-propertyName">model</span> <span class="tok-propertyName">here</span><span class="tok-punctuation">&gt;</span> to do an ABC analysis. </div><div class="cm-line">The upper boundary for the first group is £290000 and the upper boundary for the second group is £790000. </div><div class="cm-line">Filter the transactions to just 20th January 2025.</div></code></pre>
		</div>
	</div>
</div>


<p class="wp-block-paragraph">&#8230;and fairly soon after saw two worksheets created. One had a few thousand rows from the fact table in my semantic model:</p>



<figure class="wp-block-image size-large"><a href="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" width="1024" height="335" data-attachment-id="38552" data-permalink="https://blog.crossjoin.co.uk/2026/08/02/analysing-power-bi-data-using-copilot-in-excel/image-642/" data-orig-file="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image.png?fit=1144%2C374&amp;ssl=1" data-orig-size="1144,374" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;,&quot;alt&quot;:&quot;&quot;}" data-image-title="image" data-image-description="" data-image-caption="" data-large-file="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image.png?fit=1024%2C335&amp;ssl=1" src="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image.png?resize=1024%2C335&#038;ssl=1" alt="" class="wp-image-38552" srcset="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image.png?resize=1024%2C335&amp;ssl=1 1024w, https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image.png?resize=300%2C98&amp;ssl=1 300w, https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image.png?resize=768%2C251&amp;ssl=1 768w, https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image.png?resize=1100%2C360&amp;ssl=1 1100w, https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image.png?w=1144&amp;ssl=1 1144w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></figure>



<p class="wp-block-paragraph">&#8230;and the other had the ABC Analysis I asked for:</p>



<figure class="wp-block-image size-full"><a href="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-1.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" width="921" height="712" data-attachment-id="38554" data-permalink="https://blog.crossjoin.co.uk/2026/08/02/analysing-power-bi-data-using-copilot-in-excel/image-643/" data-orig-file="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-1.png?fit=921%2C712&amp;ssl=1" data-orig-size="921,712" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;,&quot;alt&quot;:&quot;&quot;}" data-image-title="image" data-image-description="" data-image-caption="" data-large-file="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-1.png?fit=921%2C712&amp;ssl=1" src="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-1.png?resize=921%2C712&#038;ssl=1" alt="" class="wp-image-38554" srcset="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-1.png?w=921&amp;ssl=1 921w, https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-1.png?resize=300%2C232&amp;ssl=1 300w, https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-1.png?resize=768%2C594&amp;ssl=1 768w" sizes="auto, (max-width: 921px) 100vw, 921px" /></a></figure>



<p class="wp-block-paragraph">Interestingly, unlike in my blog post last week, Copilot did not use the DAX UDF in the semantic model to do the ABC analysis. Instead it did what most Excel users would prefer and grabbed the raw data, did some of the analysis in the DAX query that got that raw data, then did most of the analysis using Excel formulas. It got the answer I was expecting though and the logic was consistent with the logic in my DAX UDF. </p>



<p class="wp-block-paragraph">The data on the transactions worksheet was a static copy and I would love it if, in future, Copilot created Excel tables linked to a DAX query and a connection back to the semantic model so that when the data in the model changed then the workbook would update automatically. </p>



<p class="wp-block-paragraph">Next, just to see if it worked, I used the <a href="https://support.microsoft.com/en-us/excel/copilot/copilot-in-excel-microsoft-skills">brandkit skill</a> (also <a href="https://techcommunity.microsoft.com/blog/ExcelBlog/whats-new-in-excel-july-2026/4523403">announced</a> this week) to make it look more corporate with the following prompt:</p>



<pre class="wp-block-code"><code> @brandkit make this look like a Microsoft branded report</code></pre>



<p class="wp-block-paragraph">Luckily there was already a Microsoft brand kit available to me; the result was a report which (I guess) was a bit more Microsoft-blue and which had a Microsoft logo in the top right-hand corner:</p>



<figure class="wp-block-image size-large"><a href="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-2.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" width="1024" height="350" data-attachment-id="38558" data-permalink="https://blog.crossjoin.co.uk/2026/08/02/analysing-power-bi-data-using-copilot-in-excel/image-644/" data-orig-file="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-2.png?fit=1241%2C424&amp;ssl=1" data-orig-size="1241,424" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;,&quot;alt&quot;:&quot;&quot;}" data-image-title="image" data-image-description="" data-image-caption="" data-large-file="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-2.png?fit=1024%2C350&amp;ssl=1" src="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-2.png?resize=1024%2C350&#038;ssl=1" alt="" class="wp-image-38558" srcset="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-2.png?resize=1024%2C350&amp;ssl=1 1024w, https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-2.png?resize=300%2C102&amp;ssl=1 300w, https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-2.png?resize=768%2C262&amp;ssl=1 768w, https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-2.png?resize=1200%2C410&amp;ssl=1 1200w, https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-2.png?resize=1100%2C376&amp;ssl=1 1100w, https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/08/image-2.png?w=1241&amp;ssl=1 1241w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></figure>



<p class="wp-block-paragraph">Job done, report created.</p>



<p class="wp-block-paragraph">So what? The functionality exists and it works well, which is good to know. But there&#8217;s a more interesting question to consider here: who cares? Is anyone going to use this? After all, &#8220;AI helps you analyse data&#8221; is not exactly headline news anymore. But because Excel Copilot:</p>



<ul class="wp-block-list">
<li>Works well enough &#8211; which this seems to do</li>



<li>Works well enough before other competing tools which also work well enough become commonplace on corporate desktops</li>



<li>Produces analysis in a way &#8211; Excel formulas &#8211; that is more accessible and understandable to more people than, say, Python code</li>



<li>Does this analysis directly inside the tool that most people already know and love, Excel, without needing anything extra installed and not in some other tool &#8211; even if that tool can generate Excel workbooks</li>
</ul>



<p class="wp-block-paragraph">&#8230;then I think there&#8217;s a very good chance that this <em>will</em> be popular. Probably more popular as a way of analysing data from Power BI semantic models than the M365 Copilot app, and maybe even more popular than Power BI reports as a way of analysing data from Power BI semantic models.It&#8217;s Export to Excel for the age of AI!</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.crossjoin.co.uk/2026/08/02/analysing-power-bi-data-using-copilot-in-excel/feed/</wfw:commentRss>
			<slash:comments>7</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">38543</post-id>	</item>
		<item>
		<title>Power BI, M365 Copilot And The Importance Of DAX UDFs</title>
		<link>https://blog.crossjoin.co.uk/2026/07/26/power-bi-m365-copilot-and-the-importance-of-dax-udfs/</link>
					<comments>https://blog.crossjoin.co.uk/2026/07/26/power-bi-m365-copilot-and-the-importance-of-dax-udfs/#comments</comments>
		
		<dc:creator><![CDATA[Chris Webb]]></dc:creator>
		<pubDate>Sun, 26 Jul 2026 21:13:48 +0000</pubDate>
				<category><![CDATA[Copilot]]></category>
		<category><![CDATA[DAX]]></category>
		<category><![CDATA[DAX UDFs]]></category>
		<category><![CDATA[Power BI]]></category>
		<guid isPermaLink="false">https://blog.crossjoin.co.uk/?p=38490</guid>

					<description><![CDATA[This was a big week for Power BI Copilot with the announcement of a new direction for the feature. If you haven&#8217;t done so already, read the two announcement blog posts here and here and check out this demo video. There are some pros and cons to this change (yes, you&#8217;re going to need an &#8230; <a href="https://blog.crossjoin.co.uk/2026/07/26/power-bi-m365-copilot-and-the-importance-of-dax-udfs/" class="more-link">Continue reading <span class="screen-reader-text">Power BI, M365 Copilot And The Importance Of DAX UDFs</span> <span class="meta-nav">&#8594;</span></a>]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">This was a big week for Power BI Copilot with the announcement of a new direction for the feature. If you haven&#8217;t done so already, read the two announcement blog posts <a href="https://community.fabric.microsoft.com/t5/Fabric-Updates-Blog/The-future-of-conversational-analytics-in-Fabric/ba-p/5302562">here</a> and <a href="https://community.fabric.microsoft.com/t5/Power-BI-Updates-Blog/Bringing-Power-BI-Insights-to-Every-Copilot-User/ba-p/5309360">here</a> and check out this <a href="https://www.youtube.com/watch?v=R1JIRc4KT7I">demo video</a>. There are some pros and cons to this change (yes, you&#8217;re going to need an M365 Copilot licence to use it but no Fabric capacity is needed any more &#8211; this works with models in Pro workspaces too) and there are more features still to come and problems to be solved, but the bottom line is that all of the work you&#8217;ve done preparing your semantic models for Copilot is not wasted and while the existing Power BI Copilot worked pretty well, the combination of M365 Copilot and Power BI semantic models works much, much better.</p>



<p class="wp-block-paragraph">Probably the biggest change is that whereas the existing Power BI Copilot can answer questions in a number of different ways, for example by constructing a Power BI visual, M365 Copilot usually just generates and runs DAX queries against the underlying semantic model. It&#8217;s very good at generating syntactically correct DAX queries and of course your model&#8217;s AI Instructions are respected, but two risks remain:</p>



<ol class="wp-block-list">
<li>M365 Copilot generates a DAX query that returns the correct result but not necessarily one that is optimal in terms of performance or CU cost </li>



<li>Multiple end users want to do the same kind of analysis but don&#8217;t know precisely how it should be performed, give vague instructions or are inconsistent, so they might each get slightly different results</li>
</ol>



<p class="wp-block-paragraph">Both of these problems can be solved in different ways but as a semantic model developer I find that adding <a href="https://learn.microsoft.com/en-us/dax/best-practices/dax-user-defined-functions">DAX User-Defined Functions</a> (UDFs) to your model is the easiest way to do so. This is something <a href="https://blog.crossjoin.co.uk/2025/11/09/calling-dax-udfs-from-power-bi-copilot/">I wrote about last year</a> but I thought I would revisit the topic because of its importance in the new world of M365 Copilot. If you&#8217;re going to centralise all your business logic in a semantic model then that should include the definition of complex analytical operations, something that a DAX UDF that returns a table can handle better than a <a href="https://blog.crossjoin.co.uk/2025/08/17/power-bi-copilot-ai-instructions-and-dax-query-templates/">DAX fragment embedded in your AI Instructions</a> or a text description of how your analysis should be performed.</p>



<p class="wp-block-paragraph">Using the same semantic model containing <a href="https://www.gov.uk/government/collections/price-paid-data">UK Land Registry Price Paid data</a> and the same ABC analysis UDF from that <a href="https://blog.crossjoin.co.uk/2025/11/09/calling-dax-udfs-from-power-bi-copilot/">previous post</a>, I ran a similar test to the one in that post in M365 Copilot. I only made one change to the AI Instructions for the semantic model, adding two new paragraphs highlighted below:</p>



<pre class="wp-block-preformatted">This semantic model contains a DAX user-defined function called ABC that does an ABC analysis on the data in the Transactions table. It takes three parameters defined as follows:<br />AUpperBoundary - an integer value which is the upper boundary of transactions in the A group<br />BUpperBoundary - an integer value which is the upper boundary of transactions in the B group<br />AnalysisDate: a datetime value which is the date to filter transactions on<br />The function returns a table which can be used in an EVALUATE statement in a DAX query.<br /><br /><strong>If a user asks for an ABC analysis then you must **always** use this function. Do not add any other columns or totals or try to do any other calculations on what this function returns, just return the table that the function returns and nothing else.<br /><br />If the user does not specify the values needed for the function parameters please ask the user for them - do not make any assumptions. Never try to generate the DAX for an ABC analysis yourself because it may result in incorrect or inconsistent results.</strong><br /><br />For example if I wanted to see the number of transactions which took place on 1st January 2025 divided into three groups:<br />A - transactions between £0 up to and including £250000<br />B - transactions above £250000 up to and including £700000<br />C - transactions above £700000<br />I could call the function as follows:<br />ABC(250000, 700000, DATE(2025,1,1))</pre>



<p class="wp-block-paragraph">I added the first new paragraph because I found M365 Copilot was trying to be too clever and adding extra columns and subtotals that I didn&#8217;t think were necessary, and running extra DAX queries in order to do so. I added the second one when I found that if I asked a vague question then Copilot made too many assumptions and didn&#8217;t use my UDF.</p>



<p class="wp-block-paragraph">The following prompt:</p>



<pre class="wp-block-preformatted">Use this semantic model &lt;insert URL of semantic model here&gt; to do an ABC analysis. The upper boundary for the first group is £290000 and the upper boundary for the second group is £790000. Filter the transactions to just 20th January 2025.</pre>



<p class="wp-block-paragraph">&#8230;resulted in the following output:</p>



<figure class="wp-block-image size-full"><a href="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/07/image-9.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" width="710" height="349" data-attachment-id="38498" data-permalink="https://blog.crossjoin.co.uk/2026/07/26/power-bi-m365-copilot-and-the-importance-of-dax-udfs/image-639/" data-orig-file="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/07/image-9.png?fit=710%2C349&amp;ssl=1" data-orig-size="710,349" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;,&quot;alt&quot;:&quot;&quot;}" data-image-title="image" data-image-description="" data-image-caption="" data-large-file="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/07/image-9.png?fit=710%2C349&amp;ssl=1" src="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/07/image-9.png?resize=710%2C349&#038;ssl=1" alt="" class="wp-image-38498" srcset="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/07/image-9.png?w=710&amp;ssl=1 710w, https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/07/image-9.png?resize=300%2C147&amp;ssl=1 300w" sizes="auto, (max-width: 710px) 100vw, 710px" /></a></figure>



<figure class="wp-block-image size-large"><a href="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/07/image-10.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" width="1024" height="582" data-attachment-id="38501" data-permalink="https://blog.crossjoin.co.uk/2026/07/26/power-bi-m365-copilot-and-the-importance-of-dax-udfs/image-640/" data-orig-file="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/07/image-10.png?fit=1296%2C736&amp;ssl=1" data-orig-size="1296,736" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;,&quot;alt&quot;:&quot;&quot;}" data-image-title="image" data-image-description="" data-image-caption="" data-large-file="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/07/image-10.png?fit=1024%2C582&amp;ssl=1" src="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/07/image-10.png?resize=1024%2C582&#038;ssl=1" alt="" class="wp-image-38501" srcset="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/07/image-10.png?resize=1024%2C582&amp;ssl=1 1024w, https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/07/image-10.png?resize=300%2C170&amp;ssl=1 300w, https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/07/image-10.png?resize=768%2C436&amp;ssl=1 768w, https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/07/image-10.png?resize=1200%2C681&amp;ssl=1 1200w, https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/07/image-10.png?resize=1100%2C625&amp;ssl=1 1100w, https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/07/image-10.png?w=1296&amp;ssl=1 1296w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></figure>



<p class="wp-block-paragraph">&#8230;which is exactly what I wanted. What&#8217;s more it worked consistently across all my tests and I could see that the only DAX queries run looked like this:</p>


<div class="wp-block-code">
	<div class="cm-editor">
		<div class="cm-scroller">
			
<pre>
<code><div class="cm-line">EVALUATE</div><div class="cm-line">ABC(290000, 790000, DATE(2025,1,20))</div><div class="cm-line">ORDER BY [ABC Group]</div></code></pre>
		</div>
	</div>
</div>


<p class="wp-block-paragraph">When I tried a vaguer prompt, like:</p>



<pre class="wp-block-preformatted">Use this semantic model &lt;insert URL of semantic model here&gt; to do an ABC analysis.</pre>



<p class="wp-block-paragraph">M365 Copilot asked me for the extra information it needed to do the ABC analysis:</p>



<figure class="wp-block-image size-full"><a href="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/07/image-11.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" width="708" height="528" data-attachment-id="38513" data-permalink="https://blog.crossjoin.co.uk/2026/07/26/power-bi-m365-copilot-and-the-importance-of-dax-udfs/image-641/" data-orig-file="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/07/image-11.png?fit=708%2C528&amp;ssl=1" data-orig-size="708,528" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;,&quot;alt&quot;:&quot;&quot;}" data-image-title="image" data-image-description="" data-image-caption="" data-large-file="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/07/image-11.png?fit=708%2C528&amp;ssl=1" src="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/07/image-11.png?resize=708%2C528&#038;ssl=1" alt="" class="wp-image-38513" srcset="https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/07/image-11.png?w=708&amp;ssl=1 708w, https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/07/image-11.png?resize=300%2C224&amp;ssl=1 300w, https://i0.wp.com/blog.crossjoin.co.uk/wp-content/uploads/2026/07/image-11.png?resize=200%2C150&amp;ssl=1 200w" sizes="auto, (max-width: 708px) 100vw, 708px" /></a></figure>



<p class="wp-block-paragraph">Interestingly when I deleted the AI Instructions above and pasted more or less the same text into the Description property of the UDF, I found that M365 Copilot did not use the UDF and instead it generated its own DAX query &#8211; which still gave the correct result but which included a number of additional measures from the semantic model that I didn&#8217;t think were relevant. So explaining in your AI Instructions what UDFs are present and what they should be used for is necessary.</p>



<p class="wp-block-paragraph">Anyway, to reiterate my point, I think DAX UDFs are going to be more and more important in the future. Up to now they&#8217;ve been useful as a way of encapsulating and reusing logic across calculations inside a semantic model; Power BI, alas, doesn&#8217;t provide a way for a report to show the output of a table-valued UDF. As more users consume data from Power BI semantic models outside Power BI reports, in tools like M365 Copilot that can answer questions by generating any DAX query they want, then DAX UDFs provide a way for semantic model developers to specify how certain types of analysis should be performed to ensure consistency and performance.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.crossjoin.co.uk/2026/07/26/power-bi-m365-copilot-and-the-importance-of-dax-udfs/feed/</wfw:commentRss>
			<slash:comments>7</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">38490</post-id>	</item>
	</channel>
</rss>