<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>M on Hat Full of Data</title><link>https://hatfullofdata.blog/categories/m/</link><description>Recent content in M on Hat Full of Data</description><generator>Hugo -- gohugo.io</generator><language>en-gb</language><lastBuildDate>Mon, 12 May 2025 16:01:10 +0000</lastBuildDate><atom:link href="https://hatfullofdata.blog/categories/m/index.xml" rel="self" type="application/rss+xml"/><item><title>First refresh it broke!</title><link>https://hatfullofdata.blog/first-refresh-it-broke-laurabrokeit/</link><pubDate>Mon, 12 May 2025 15:57:47 +0000</pubDate><guid>https://hatfullofdata.blog/first-refresh-it-broke-laurabrokeit/</guid><description>&lt;img src="https://hatfullofdata.blog/first-refresh-it-broke-laurabrokeit/cover.png" alt="Featured image of post First refresh it broke!" /&gt;&lt;p&gt;I set up my dataflow and it was working great. Then it broke on the refresh. Here is how I fixed it.&lt;/p&gt;
&lt;h2 id="sharepoint-and-microsoft-fabric"&gt;SharePoint and Microsoft Fabric
&lt;/h2&gt;&lt;p&gt;SharePoint is no database but we keep putting data there so here are my findings and notes from working with SharePoint libraries and lists in Microsoft Fabric.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://hatfullofdata.blog/sharepoint-folder-into-microsoft-fabric/" target="_blank" rel="noopener"
 &gt;Ingest a SharePoint folder of Excel Files&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://hatfullofdata.blog/first-refresh-it-broke-laurabrokeit/" target="_blank" rel="noopener"
 &gt;Fixing the broken query&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="previously"&gt;Previously
&lt;/h2&gt;&lt;p&gt;In the previous post we ingested a SharePoint folder into a table in a Lakehouse. That is a well known process and nothing new except for one thing. I split the process into two stages, firstly the FullFileList which contained the list of files and the binary content of the files and then a separate query to combine data from those files. Power Query created Helper queries to perform the combining. Then it broke.&lt;/p&gt;
&lt;p&gt;&lt;img class="gallery-image" data-flex-basis="1371px" data-flex-grow="571" height="119" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://hatfullofdata.blog/first-refresh-it-broke-laurabrokeit/image-14.png" width="680"&gt;&lt;/p&gt;
&lt;h2 id="it-broke"&gt;It Broke
&lt;/h2&gt;&lt;p&gt;It all appears to work fine. Then I try a refresh and it fails. On going back to look at the dataflow I see that there are 2 extra steps in FullFileList that have been added by Microsoft Fabric.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Query steps from the FullFileList Query showing the steps the made it broke" class="gallery-image" data-flex-basis="499px" data-flex-grow="207" height="327" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://hatfullofdata.blog/first-refresh-it-broke-laurabrokeit/image-15.png" width="680"&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-xml" data-lang="xml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;let
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Source = SharePoint.Files(&amp;#34;https://lgb123.sharepoint.com/sites/FabricDemo/&amp;#34;, [ApiVersion = 15]),
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; #&amp;#34;Filtered rows&amp;#34; = Table.SelectRows(Source, each [Folder Path] = &amp;#34;https://lgb123.sharepoint.com/sites/FabricDemo/Budgets/&amp;#34;),
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; #&amp;#34;From Value&amp;#34; = Table.FromValue(#&amp;#34;Filtered rows&amp;#34;),
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; #&amp;#34;Remove Columns&amp;#34; = Table.RemoveColumns(#&amp;#34;From Value&amp;#34;, Table.ColumnsOfType(#&amp;#34;From Value&amp;#34;, {type table, type record, type list, type nullable binary, type binary, type function}))
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;in
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; #&amp;#34;Remove Columns&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;The last step Remove Columns, removes all columns of type table, record, list, binary or function. So this removes the Content column that is binary and therefore the queries doing the combine of the Content column all fail. Hence it broke.&lt;/p&gt;
&lt;h2 id="it-broke-in-the-staging"&gt;It Broke in the Staging
&lt;/h2&gt;&lt;p&gt;To improve performance and reliability, Dataflow Gen2 uses staging items to store intermediate data during data transformation&lt;/p&gt;
&lt;p&gt;The above quote is from &lt;a class="link" href="https://learn.microsoft.com/en-us/fabric/data-factory/data-in-staging-artifacts?wt.mc_id=DX-MVP-5003563" target="_blank" rel="noopener"
 &gt;https://learn.microsoft.com/en-us/fabric/data-factory/data-in-staging-artifacts&lt;/a&gt; It stores the intermediate queries, so FullFileList would have been stored as a table in the staginglakehouse or stagingwarehouse. So Fabric is adding the step to remove the binary column so staging can work.&lt;/p&gt;
&lt;h2 id="turn-off-staging"&gt;Turn Off Staging
&lt;/h2&gt;&lt;p&gt;When I right click on the FullFileList query in the query list the menu includes Enable Staging, by default it is turned on, indicated with a tick. So I click on Enable staging to remove the tick and turn it off. I publish the dataflow and wait. Yes! the refresh works, I test it multiple times.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Turning off enable staging" class="gallery-image" data-flex-basis="232px" data-flex-grow="96" height="623" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://hatfullofdata.blog/first-refresh-it-broke-laurabrokeit/image-16.png" width="603"&gt;&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion
&lt;/h2&gt;&lt;p&gt;I am curious as to how turning off staging will impact the dataflow. So I will be keeping an eye on this one. But this appears to be the fix we need to get it working again for now. I will do my enquiries and retests to see if this is still needed.&lt;/p&gt;</description></item><item><title>SharePoint Folder into Microsoft Fabric</title><link>https://hatfullofdata.blog/sharepoint-folder-into-microsoft-fabric/</link><pubDate>Fri, 09 May 2025 17:08:15 +0000</pubDate><guid>https://hatfullofdata.blog/sharepoint-folder-into-microsoft-fabric/</guid><description>&lt;img src="https://hatfullofdata.blog/sharepoint-folder-into-microsoft-fabric/cover.png" alt="Featured image of post SharePoint Folder into Microsoft Fabric" /&gt;&lt;p&gt;SharePoint folder has been a connector into Power Query for Excel, Power BI Desktop and dataflows for quite a while. This post is to cover the basics before I write another post to explain a more complex scenario. This post will use GEN2 Dataflows in Microsoft Fabric. Power Query can take files on a SharePoint site and from a selected sheet, table or named range append the contents to one big table. This post explains what you should be aware of when doing this.&lt;/p&gt;
&lt;h2 id="sharepoint-and-microsoft-fabric"&gt;SharePoint and Microsoft Fabric
&lt;/h2&gt;&lt;p&gt;SharePoint is no database but we keep putting data there so here are my findings and notes from working with SharePoint libraries and lists in Microsoft Fabric.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://hatfullofdata.blog/sharepoint-folder-into-microsoft-fabric/" target="_blank" rel="noopener"
 &gt;Ingest a SharePoint folder of Excel Files&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://hatfullofdata.blog/first-refresh-it-broke-laurabrokeit/" target="_blank" rel="noopener"
 &gt;Fixing the broken query&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="sharepoint-library"&gt;SharePoint Library
&lt;/h2&gt;&lt;p&gt;I have a SharePoint library on a site called Budgets. It contains 3 files which are all the same format, 2 tabs, 1 table and 2 named regions.&lt;/p&gt;
&lt;p&gt;&lt;img alt="SharePoint library containing 3 files." class="gallery-image" data-flex-basis="688px" data-flex-grow="286" height="237" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://hatfullofdata.blog/sharepoint-folder-into-microsoft-fabric/image.png" width="680"&gt;&lt;/p&gt;
&lt;p&gt;The URL to the library is &lt;a class="link" href="https://lgb123.sharepoint.com/sites/FabricDemo/Budgets/Forms/AllItems.aspx" target="_blank" rel="noopener"
 &gt;https://lgb123.sharepoint.com/sites/FabricDemo/Budgets/Forms/AllItems.aspx&lt;/a&gt; . From this I can work out the URL to the SharePoint site is &lt;a class="link" href="https://lgb123.sharepoint.com/sites/FabricDemo/Budgets/" target="_blank" rel="noopener"
 &gt;https://lgb123.sharepoint.com/sites/FabricDemo/Budgets/&lt;/a&gt; You can always test it by making sure the site url takes you to the front page.&lt;/p&gt;
&lt;h2 id="connecting-to-sharepoint-folder"&gt;Connecting to SharePoint Folder
&lt;/h2&gt;&lt;p&gt;In a GEN2 Dataflow, from the Home ribbon select Get Data and then more. If SharePoint folder isn’t showing in the dialog that appears, search for SharePoint. Then select SharePoint folder. Then enter in your site URL. Please note the full library url will not work.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Setting up the SharePoint Folder connector" class="gallery-image" data-flex-basis="494px" data-flex-grow="206" height="330" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://hatfullofdata.blog/sharepoint-folder-into-microsoft-fabric/image-6.png" width="680"&gt;&lt;/p&gt;
&lt;p&gt;If this is the first time you’ve connected to this SharePoint site you will need to set up the connection. All you need to do is change the Authentication kind to Organizational account and make sure you are signed in. Click Next to move onto the Preview folder data. If you have more than one library or folders it will show too many files, don’t worry we will fix this.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Preview folder data dialog showing files from multiple folders" class="gallery-image" data-flex-basis="600px" data-flex-grow="250" height="272" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://hatfullofdata.blog/sharepoint-folder-into-microsoft-fabric/image-7.png" width="680"&gt;&lt;/p&gt;
&lt;p&gt;Click Create, rather than Combine so we can control which files get combined.&lt;/p&gt;
&lt;h2 id="filtering-to-the-right-sharepoint-folder"&gt;Filtering to the right SharePoint Folder
&lt;/h2&gt;&lt;p&gt;In my example I have multiple SharePoint libraries in the same site, so the initial list returned contains too many files. There is a column called Folder Path. I find a row that contains the value I want, right click on the value. Then select Text filters – Equals. This will add a filter a step to the query to filter to only files in that path.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Adding a text filter to the Folder Path column." class="gallery-image" data-flex-basis="322px" data-flex-grow="134" height="506" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://hatfullofdata.blog/sharepoint-folder-into-microsoft-fabric/image-8.png" width="680"&gt;&lt;/p&gt;
&lt;p&gt;Even if your current site only has one document library so currently this step is not required, I would add it anyway. Then when anyone adds files a new library it will not break your query.&lt;/p&gt;
&lt;h2 id="combining-the-files"&gt;Combining the Files
&lt;/h2&gt;&lt;p&gt;In order to make future additions to these queries easier and to reduce repeated work happening I would rename the query so far to FullFileList or similar and the right click on the query and select Reference. Rename the new query to something suitable, in my case it was Budget. The diagram will now show the two queries connected.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Creating a " class="gallery-image" data-flex-basis="820px" data-flex-grow="341" height="199" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://hatfullofdata.blog/sharepoint-folder-into-microsoft-fabric/image-9.png" width="680"&gt;&lt;/p&gt;
&lt;p&gt;The next stage is to do the combining. Make sure the Content column has a data type of Binary. Then click the button in the top corner of the Content column to start the file combination. After a few seconds the Combine Files will appear requesting you to select which sheet, table or named range you are combining.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Showing the button in the Content for combining, the combine dialog and the resulted combined data" class="gallery-image" data-flex-basis="584px" data-flex-grow="243" height="279" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://hatfullofdata.blog/sharepoint-folder-into-microsoft-fabric/image-11.png" width="680"&gt;&lt;/p&gt;
&lt;p&gt;Once you click Combine it will create the Helper queries and related queries and will combine the files. You then will have a query with the first column Source.Name and the rest the data from the selected item.&lt;/p&gt;
&lt;h2 id="adding-a-destination"&gt;Adding a Destination
&lt;/h2&gt;&lt;p&gt;There might be other transformation steps you need to add before your data is ready. I’ve added an unpivot to my data, but that would a complete post on its own. Finally we get to add a destination to save the data to. If you are going to a Lakehouse, Warehouse or Database you should be aware of option available to you.&lt;/p&gt;
&lt;p&gt;The first option is if you are saving to an existing table or creating a new table.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Choosing a destination target to either a New or Existing table" class="gallery-image" data-flex-basis="390px" data-flex-grow="162" height="418" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://hatfullofdata.blog/sharepoint-folder-into-microsoft-fabric/image-12.png" width="680"&gt;&lt;/p&gt;
&lt;p&gt;When you click next the second option is available. Turning off Use automatic settings will give you the options. Is the update an append or a replace? Is the schema dynamic or fixed, ie if your query adds a new column what happens? I’ve picked replace, the default option but as the SharePoint folder grows I might look to more clever file filters so that only new data is selected and therefore can be appended.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Showing options for append or replace" class="gallery-image" data-flex-basis="558px" data-flex-grow="232" height="292" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://hatfullofdata.blog/sharepoint-folder-into-microsoft-fabric/image-13.png" width="680"&gt;&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion
&lt;/h2&gt;&lt;p&gt;Uploading multiple Excel files will always be a requirement. So its worth knowing what Power Query can do for us in a dataflow to do that. There are probably more capacity efficient methods which need exploring.&lt;/p&gt;</description></item><item><title>Power Query – Fixing Missing Columns Dynamically</title><link>https://hatfullofdata.blog/power-query-fixing-missing-columns-dynamically/</link><pubDate>Wed, 08 Jan 2025 11:49:26 +0000</pubDate><guid>https://hatfullofdata.blog/power-query-fixing-missing-columns-dynamically/</guid><description>&lt;img src="https://hatfullofdata.blog/power-query-fixing-missing-columns-dynamically/cover.png" alt="Featured image of post Power Query – Fixing Missing Columns Dynamically" /&gt;&lt;p&gt;One of the challenges of making sure your query works in Power Query is data sources that have a changing schema. Some APIs miss out fields if the data is null and sometimes we need one report able to handle data files that are almost the same but not quite. In this post we will look at fixing 2 scenarios, a single missing column and multiple missing columns.&lt;/p&gt;
&lt;p&gt;You know you have this problem when you get the an error similar to this:&lt;/p&gt;
&lt;p&gt;&lt;img alt="An error stating Expression Error, the column Debit of the table wasn’t found" class="gallery-image" data-flex-basis="1255px" data-flex-grow="523" height="130" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://hatfullofdata.blog/power-query-fixing-missing-columns-dynamically/2025-01-08_10-09-49.png" width="680"&gt;&lt;/p&gt;
&lt;h2 id="single-missing-column"&gt;Single Missing Column
&lt;/h2&gt;&lt;p&gt;This scenario is fixing one column missing. In my example the query was written based on a file that had a Debit column. The query is now pointed to file that is missing that column. We need the query to work if the Debit column is in the original or not.&lt;/p&gt;
&lt;p&gt;&lt;img alt="2 screen shots of a query, first one with the last applied step selected and an missing columns error showing, second one with the previous step selected and no error showing" class="gallery-image" data-flex-basis="464px" data-flex-grow="193" height="351" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://hatfullofdata.blog/power-query-fixing-missing-columns-dynamically/2025-01-08_10-14-49.png" width="680"&gt;&lt;/p&gt;
&lt;p&gt;Start in the broken version and find the first step where there is not an error. The fix is to add the Debit column if the table does not have the column.&lt;/p&gt;
&lt;p&gt;M is not friendly to write so lets get the interface to write part of it. Click on Custom Column on the Add Column ribbon. Click Insert when prompted about inserting a step. Then enter in the name of the missing column for the column name and null for the value. When you click OK the column gets inserted and your query goes back to working.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Custom column dialog box showing the Debit column with a null value and the result table with the Debit column added." class="gallery-image" data-flex-basis="276px" data-flex-grow="115" height="590" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://hatfullofdata.blog/power-query-fixing-missing-columns-dynamically/2025-01-08_10-27-53.png" width="680"&gt;&lt;/p&gt;
&lt;p&gt;But the query will fail when the file does include the Debit column. So we need to add some logic to the new step we added. We need to test to see if the table already has the column, if it does just return the table, if not add the column. This can be done using Table.HasColumns function and an “if” statement.&lt;/p&gt;
&lt;p&gt;The line of M created by the inserting a custom column is&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-xml" data-lang="xml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;= Table.AddColumn(#&amp;#34;Promoted Headers&amp;#34;, &amp;#34;Debit&amp;#34;, each null)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;This needs to become&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-xml" data-lang="xml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;= if Table.HasColumns(#&amp;#34;Promoted Headers&amp;#34;,&amp;#34;Debit&amp;#34;) 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; then #&amp;#34;Promoted Headers&amp;#34; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; else Table.AddColumn(#&amp;#34;Promoted Headers&amp;#34;, &amp;#34;Debit&amp;#34;, each null)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Please note the #”Promoted Headers” comes from the name of the previous step.&lt;/p&gt;
&lt;p&gt;Reference for HasColumns can be found at &lt;a class="link" href="https://learn.microsoft.com/en-us/powerquery-m/table-hascolumns?wt.mc_id=DX-MVP-5003563" target="_blank" rel="noopener"
 &gt;https://learn.microsoft.com/en-us/powerquery-m/table-hascolumns&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="multiple-missing-columns"&gt;Multiple Missing Columns
&lt;/h2&gt;&lt;p&gt;The previous method works great for a single column and maybe even 2 but if you have more columns than that you really need another method. In this example we have a set of data with columns for months Jan – Dec. At the start of the year there is only a Jan column but we need the query to return all the columns.&lt;/p&gt;
&lt;p&gt;&lt;img alt="error complaining about missing columns" class="gallery-image" data-flex-basis="1133px" data-flex-grow="472" height="144" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://hatfullofdata.blog/power-query-fixing-missing-columns-dynamically/2025-01-08_10-54-24.png" width="680"&gt;&lt;/p&gt;
&lt;p&gt;The error will only complain about the first column it finds missing but if we fixed Feb it would then complain that Mar was missing etc. When you append 2 tables it creates a table with all the columns of both tables even if one table does not contain any data. So if we can create an empty table with all the columns we want and then append the tables we will get all the columns added.&lt;/p&gt;
&lt;p&gt;Create a new blank query and enter in the formula to create a list of all the column names you want to make sure exist. Use {} brackets containing the column name strings separated by commas. This will display the list of values. Rename the query to something meaningful, for example Months.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-xml" data-lang="xml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;= {&amp;#34;Jan&amp;#34;,&amp;#34;Feb&amp;#34;,&amp;#34;Mar&amp;#34;,&amp;#34;Apr&amp;#34;,&amp;#34;May&amp;#34;,&amp;#34;Jun&amp;#34;,&amp;#34;Jul&amp;#34;,&amp;#34;Aug&amp;#34;,&amp;#34;Sep&amp;#34;,&amp;#34;Oct&amp;#34;,&amp;#34;Nov&amp;#34;,&amp;#34;Dec&amp;#34;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;img alt="Screen shot from Power Query showing the query with formula shown as the Source step." class="gallery-image" data-flex-basis="932px" data-flex-grow="388" height="175" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://hatfullofdata.blog/power-query-fixing-missing-columns-dynamically/2025-01-08_11-01-40.png" width="680"&gt;&lt;/p&gt;
&lt;p&gt;Now we need to add a step that converts this into a table. Right click on the Source step and select Insert Step After. Next we use #table function that takes 2 parameters, list of columns and values. We want an empty table so will use {} for the values. Change the formula to the following&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-xml" data-lang="xml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;= #table( Source , {} )
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;img class="gallery-image" data-flex-basis="1554px" data-flex-grow="647" height="105" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://hatfullofdata.blog/power-query-fixing-missing-columns-dynamically/2025-01-08_11-07-21.png" width="680"&gt;&lt;/p&gt;
&lt;p&gt;Reference for #table can be found at &lt;a class="link" href="https://learn.microsoft.com/en-us/powerquery-m/sharptable?wt.mc_id=DX-MVP-5003563" target="_blank" rel="noopener"
 &gt;https://learn.microsoft.com/en-us/powerquery-m/sharptable&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Return to the broken query and find the last step that the query works. On the Home ribbon select Append Queries and select Insert when prompted about inserting a step. In the Append dialog select the query that has the empty table just created. Then click OK. Your query now has all the columns required and should work if the columns are missing columns or not&lt;/p&gt;
&lt;p&gt;&lt;img alt="Append dialog showing appending the Months table and the final table with the missing columns added" class="gallery-image" data-flex-basis="381px" data-flex-grow="158" height="428" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://hatfullofdata.blog/power-query-fixing-missing-columns-dynamically/2025-01-08_11-08-49.png" width="680"&gt;&lt;/p&gt;
&lt;h2 id="advanced-notes-on-missing-columns"&gt;Advanced Notes on Missing Columns
&lt;/h2&gt;&lt;p&gt;When appending 2 tables the first table columns will come first and in the order of the first table. So if you wish to order the columns of the query as well make sure your blank table query contains all the columns and the swap the order of the tables named in the Table.Combine step.&lt;/p&gt;
&lt;p&gt;The list of column names and creating the blank table could be put as steps within the original query. That requires being comfortable with the Advanced editor and writing M. For those interested here is an example query.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-xml" data-lang="xml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;let
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Source = Excel.Workbook(Web.Contents(ExcelPath), null, true),
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Sheet2_Sheet = Source{[Item=&amp;#34;Sheet2&amp;#34;,Kind=&amp;#34;Sheet&amp;#34;]}[Data],
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; #&amp;#34;Promoted Headers&amp;#34; = Table.PromoteHeaders(Sheet2_Sheet, [PromoteAllScalars=true]),
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; AllColumns = {&amp;#34;Project&amp;#34;,&amp;#34;Jan&amp;#34;,&amp;#34;Feb&amp;#34;,&amp;#34;Mar&amp;#34;,&amp;#34;Apr&amp;#34;,&amp;#34;May&amp;#34;,&amp;#34;Jun&amp;#34;,&amp;#34;Jul&amp;#34;,&amp;#34;Aug&amp;#34;,&amp;#34;Sep&amp;#34;,&amp;#34;Oct&amp;#34;,&amp;#34;Nov&amp;#34;,&amp;#34;Dec&amp;#34;},
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; BlankTable = #table( AllColumns , {} ),
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; #&amp;#34;Appended Query&amp;#34; = Table.Combine({BlankTable, #&amp;#34;Promoted Headers&amp;#34;}),
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; #&amp;#34;Changed Type&amp;#34; = Table.TransformColumnTypes(#&amp;#34;Appended Query&amp;#34;,{{&amp;#34;Project&amp;#34;, type text}, {&amp;#34;Jan&amp;#34;, Int64.Type}, {&amp;#34;Feb&amp;#34;, Int64.Type}, {&amp;#34;Mar&amp;#34;, Int64.Type}, {&amp;#34;Apr&amp;#34;, Int64.Type}, {&amp;#34;May&amp;#34;, Int64.Type}, {&amp;#34;Jun&amp;#34;, Int64.Type}, {&amp;#34;Jul&amp;#34;, Int64.Type}, {&amp;#34;Aug&amp;#34;, Int64.Type}, {&amp;#34;Sep&amp;#34;, Int64.Type}, {&amp;#34;Oct&amp;#34;, Int64.Type}, {&amp;#34;Nov&amp;#34;, Int64.Type}, {&amp;#34;Dec&amp;#34;, Int64.Type}})
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;in
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; #&amp;#34;Changed Type&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id="conclusion"&gt;Conclusion
&lt;/h2&gt;&lt;p&gt;Queries should be dynamic when required and missing columns is a common issue. Writing M is not friendly, writing dynamic M takes practice but it is worth it. Power Query that copes with your unclean data is the reality of handling data. Bast of luck I hope this helped.&lt;/p&gt;
&lt;h2 id="more-power-query-posts"&gt;More Power Query Posts
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://hatfullofdata.blog/power-query-handwritten-function/" target="_blank" rel="noopener"
 &gt;Custom Handwritten Function&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://hatfullofdata.blog/power-query-multi-step-function/" target="_blank" rel="noopener"
 &gt;Multi-step Function&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://hatfullofdata.blog/power-query-replace-values-for-whole-table/" target="_blank" rel="noopener"
 &gt;Replace Values for Whole Table&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://hatfullofdata.blog/power-query-ai-insights-error/" target="_blank" rel="noopener"
 &gt;AI Insights Error&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://hatfullofdata.blog/excel-power-query-vba-to-edit-a-parameter-value/" target="_blank" rel="noopener"
 &gt;VBA to Edit a Parameter Value&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://hatfullofdata.blog/power-query-dynamic-data-source-and-web-content/" target="_blank" rel="noopener"
 &gt;Dynamic Data Source and Web.Contents()&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://hatfullofdata.blog/power-query-get-previous-row-data/" target="_blank" rel="noopener"
 &gt;Get Previous Row Data&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://hatfullofdata.blog/power-query-creating-new-parameters/" target="_blank" rel="noopener"
 &gt;Creating New Parameters&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://hatfullofdata.blog/power-query-fixing-missing-columns-dynamically/" target="_blank" rel="noopener"
 &gt;Fixing Missing Columns Dynamically&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://hatfullofdata.blog/power-query-handling-null-values/" target="_blank" rel="noopener"
 &gt;Handling Null Values Properly&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Power Query – Get Previous Row Data</title><link>https://hatfullofdata.blog/power-query-get-previous-row-data/</link><pubDate>Tue, 08 Jun 2021 08:55:16 +0000</pubDate><guid>https://hatfullofdata.blog/power-query-get-previous-row-data/</guid><description>&lt;img src="https://hatfullofdata.blog/power-query-get-previous-row-data/cover.png" alt="Featured image of post Power Query – Get Previous Row Data" /&gt;&lt;p&gt;Occasionally I get asked a question via Twitter or LinkedIn that prompts me to write a post. The question asked was how to get previous row data. In this post I will describe how to get a value from the previous row that matches a criteria. The example data is peoples scores on different dates. I want to know if they are improving. For this I need their previous score.&lt;/p&gt;
&lt;h3 id="starting-data"&gt;Starting Data
&lt;/h3&gt;&lt;p&gt;&lt;img alt="Table of data with columns name, date and score" class="gallery-image" data-flex-basis="545px" data-flex-grow="227" height="299" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://hatfullofdata.blog/power-query-get-previous-row-data/PreviousScore_001.png" width="680"&gt;&lt;/p&gt;
&lt;h3 id="getting-previous-row-data"&gt;Getting Previous Row Data
&lt;/h3&gt;&lt;p&gt;The first step is to sort the data. You need the previous score to be in the previous row, so we sort by name and then date.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Data now sorted by Name and Date." class="gallery-image" data-flex-basis="544px" data-flex-grow="226" height="300" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://hatfullofdata.blog/power-query-get-previous-row-data/PreviousScore_002.png" width="680"&gt;&lt;/p&gt;
&lt;p&gt;Then from the Add Column ribbon we add an Index column. And then a custom column, “Prev Index” which is Index-1&lt;/p&gt;
&lt;p&gt;&lt;img alt="Custom Column dialog showing the calculation for Prev Index of Index -1" class="gallery-image" data-flex-basis="374px" data-flex-grow="155" height="436" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://hatfullofdata.blog/power-query-get-previous-row-data/PreviousScore_003.png" width="680"&gt;&lt;/p&gt;
&lt;p&gt;Now we can merge a table to itself (yes a touch head screwy but its fine it works) by linking Prev Index to Index. This though will give Bob Alice’s last score as his previous score so we add the Name column to the merge as well. Holding down the Ctrl key will allow you to select multiple columns and make sure at the bottom of the dialog you have some matching rows..&lt;/p&gt;
&lt;p&gt;&lt;img alt="Merge dialog with columns selected for the merge" class="gallery-image" data-flex-basis="267px" data-flex-grow="111" height="611" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://hatfullofdata.blog/power-query-get-previous-row-data/PreviousScore_004.png" width="680"&gt;&lt;/p&gt;
&lt;p&gt;This creates a column that contains tables. Press the expand button and only select the Score column. Click OK to give a column of the previous scores ready to rename.&lt;/p&gt;
&lt;p&gt;&lt;img class="gallery-image" data-flex-basis="558px" data-flex-grow="232" height="292" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://hatfullofdata.blog/power-query-get-previous-row-data/PreviousScore_005.png" width="680"&gt;&lt;/p&gt;
&lt;p&gt;I then rename Score.1 to Previous Score and use Choose Columns to remove Index and Previous Index to end up with a table of name, date, score and previous score.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Final table including previous row data" class="gallery-image" data-flex-basis="709px" data-flex-grow="295" height="230" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://hatfullofdata.blog/power-query-get-previous-row-data/PreviousScore_006.png" width="680"&gt;&lt;/p&gt;
&lt;h2 id="more-power-query-posts"&gt;More Power Query Posts
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://hatfullofdata.blog/power-query-handwritten-function/" target="_blank" rel="noopener"
 &gt;Custom Handwritten Function&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://hatfullofdata.blog/power-query-multi-step-function/" target="_blank" rel="noopener"
 &gt;Multi-step Function&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://hatfullofdata.blog/power-query-replace-values-for-whole-table/" target="_blank" rel="noopener"
 &gt;Replace Values for Whole Table&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://hatfullofdata.blog/power-query-ai-insights-error/" target="_blank" rel="noopener"
 &gt;AI Insights Error&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://hatfullofdata.blog/excel-power-query-vba-to-edit-a-parameter-value/" target="_blank" rel="noopener"
 &gt;VBA to Edit a Parameter Value&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://hatfullofdata.blog/power-query-dynamic-data-source-and-web-content/" target="_blank" rel="noopener"
 &gt;Dynamic Data Source and Web.Contents()&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://hatfullofdata.blog/power-query-get-previous-row-data/" target="_blank" rel="noopener"
 &gt;Get Previous Row Data&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://hatfullofdata.blog/power-query-creating-new-parameters/" target="_blank" rel="noopener"
 &gt;Creating New Parameters&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://hatfullofdata.blog/power-query-fixing-missing-columns-dynamically/" target="_blank" rel="noopener"
 &gt;Fixing Missing Columns Dynamically&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://hatfullofdata.blog/power-query-handling-null-values/" target="_blank" rel="noopener"
 &gt;Handling Null Values Properly&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Power Query – Dynamic Data Source and Web.Contents()</title><link>https://hatfullofdata.blog/power-query-dynamic-data-source-and-web-content/</link><pubDate>Tue, 04 May 2021 13:01:31 +0000</pubDate><guid>https://hatfullofdata.blog/power-query-dynamic-data-source-and-web-content/</guid><description>&lt;img src="https://hatfullofdata.blog/power-query-dynamic-data-source-and-web-content/cover.png" alt="Featured image of post Power Query – Dynamic Data Source and Web.Contents()" /&gt;&lt;p&gt;This is the first post in a series to create a Star Wars report. This post handles the issue of using a parameter as the url in a web Power Query. This type of data source is referred to as a Dynamic Data Source. It will not refresh in the Power BI service unless you do some tricks.&lt;/p&gt;
&lt;h3 id="star-wars-series"&gt;Star Wars Series
&lt;/h3&gt;&lt;p&gt;Starting on May 4th a series using Star Wars data had to be done. Its based off an api that has some great data that is paged in 10 row blocks. I’m looking to create complete report from queries to modelling to visuals and theme etc.&lt;/p&gt;
&lt;p&gt;The data comes from &lt;a class="link" href="https://swapi.dev/api/" target="_blank" rel="noopener"
 &gt;https://swapi.dev/api/&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://hatfullofdata.blog/power-query-dynamic-data-source-and-web-contents/" target="_blank" rel="noopener"
 &gt;Handling Dynamic Data sources&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Fetching number of pages&lt;/li&gt;
&lt;li&gt;Using next page url&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="fetching-data"&gt;Fetching Data
&lt;/h3&gt;&lt;p&gt;I started by looking at the people table. In a new Power BI report I select Web from Get Data and use the url &lt;a class="link" href="https://swapi.dev/api/people/" target="_blank" rel="noopener"
 &gt;https://swapi.dev/api/people/&lt;/a&gt; and click OK. This throws you straight into Power Query where is has created a few steps to get you a table of data.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Table of 10 rows of data plus 5 query steps in Power Query" class="gallery-image" data-flex-basis="796px" data-flex-grow="331" height="205" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://hatfullofdata.blog/power-query-dynamic-data-source-and-web-content/API-Paged-001.png" width="680"&gt;&lt;/p&gt;
&lt;p&gt;It only gives 10 rows of data, which does include the url to the next 10 rows and also how many rows there are in total. So I use a technique I’ve blogged about before and create a URL parameter, change the source step to use the URL and then convert the query into a function.&lt;/p&gt;
&lt;p&gt;Look here for more details &lt;a class="link" href="https://hatfullofdata.blog/power-query-fetch-web-data/" target="_blank" rel="noopener"
 &gt;https://hatfullofdata.blog/power-query-fetch-web-data/&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="test-refresh"&gt;Test Refresh
&lt;/h3&gt;&lt;p&gt;Then as a test I invoke the function to fetch the first 10 rows into a table, close and apply Power Query and then publish my report to the Power BI service.&lt;/p&gt;
&lt;p&gt;&lt;img alt="snapshot of the power bi workspace showing the report and dataset listed" class="gallery-image" data-flex-basis="466px" data-flex-grow="194" height="350" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://hatfullofdata.blog/power-query-dynamic-data-source-and-web-content/API-Paged-002.png" width="680"&gt;&lt;/p&gt;
&lt;p&gt;Then I do the important test, does it refresh? When I click on refresh it fails, and when I click on the small red triangle it gives an error stating the dataset uses a dynamic data source and these can’t be refreshed.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Screen grab of the Dynamic Data Source refresh error." class="gallery-image" data-flex-basis="570px" data-flex-grow="237" height="286" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://hatfullofdata.blog/power-query-dynamic-data-source-and-web-content/API-Paged-003.png" width="680"&gt;&lt;/p&gt;
&lt;p&gt;Part of the error includes a URL &lt;a class="link" href="https://aka.ms/dynamic-data-sources" target="_blank" rel="noopener"
 &gt;https://aka.ms/dynamic-data-sources&lt;/a&gt; , so I go and look at the web page. And it explains how you can identify if you have a dynamic data source that won’t refresh by looking in the Data source settings in Power Query. Sure enough, when I look, it gives a message which I now know means a dynamic data source so refresh won’t work. I assume hand-authored queries means dynamic data sources.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Data source settings dialog with message regarding hand-crafted queries which is how you identify Dynamic Data Sources exist apparently" class="gallery-image" data-flex-basis="418px" data-flex-grow="174" height="390" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://hatfullofdata.blog/power-query-dynamic-data-source-and-web-content/API-Paged-004.png" width="680"&gt;&lt;/p&gt;
&lt;p&gt;This doesn’t tell me how to to fix it though. So off onto the internet I go and search around my favourite Power Query bloggers and sure enough Chris Webb comes up trumps with a few posts.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://blog.crossjoin.co.uk/2016/08/23/web-contents-m-functions-and-dataset-refresh-errors-in-power-bi/" target="_blank" rel="noopener"
 &gt;Chris Webb’s BI Blog: Web.Contents(), M Functions And Dataset Refresh Errors In Power BI Chris Webb’s BI Blog (crossjoin.co.uk)&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://blog.crossjoin.co.uk/2016/08/16/using-the-relativepath-and-query-options-with-web-contents-in-power-query-and-power-bi-m-code/" target="_blank" rel="noopener"
 &gt;Chris Webb’s BI Blog: Using The RelativePath And Query Options With Web.Contents() In Power Query And Power BI M Code Chris Webb’s BI Blog (crossjoin.co.uk)&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The second post was the one I used the most in modifying my query. It also includes searching for cow data, which I think is superb!&lt;/p&gt;
&lt;h3 id="removing-the-dynamic-data-source"&gt;Removing the Dynamic Data Source
&lt;/h3&gt;&lt;p&gt;So the Web.Contents used in the source of my function needs the base url to stay the same and then any dynamic parts put into the options. The base url must be a valid web address you can authenticate to as anonymous and the shorter the better as it makes the function more flexible. I delete the invoked function query and the function from my report.&lt;/p&gt;
&lt;p&gt;So for the Star Wars data the base url is – &lt;a class="link" href="https://swapi.dev/api" target="_blank" rel="noopener"
 &gt;https://swapi.dev/api&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The people part and the page=1 can be added in as part of the options. So the new solution has 2 parameters, TableName and PageNum and they are both text. Then we have to edit the source step by hand to write the second parameter of Web.Con (the whole hand-crafted fix to get rid of hand-crafted error is just amusing). The options are a record so put inside square brackets [ .. ]. The query is another record so is a nested [ .. ].&lt;/p&gt;
&lt;p&gt;Web.Contents options allow for two things to be set, a relative path, eg People and query parameters eg Page=1. APIs are fussy so make sure you get the case right in the query part. This is my final code for the Source step. (This is the reason I blog, so in 6 months time I know I have a working example piece of code.)&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-xml" data-lang="xml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Source = Json.Document(Web.Contents(&amp;#34;https://swapi.dev/api/&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; [
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; RelativePath=TableName,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Query=[page=PageNum]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; )),
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Then I right click on the query and create a function. Invoking this function creates a table ready now to close and apply back into Power BI desktop. I publish and try a refresh and YES! it works. I now have a function that will take a table name and page number and give 10 rows of data.&lt;/p&gt;
&lt;p&gt;In the next post we will use this function to get all the data for a table.&lt;/p&gt;
&lt;h2 id="more-power-query-posts"&gt;More Power Query Posts
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://hatfullofdata.blog/power-query-handwritten-function/" target="_blank" rel="noopener"
 &gt;Custom Handwritten Function&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://hatfullofdata.blog/power-query-multi-step-function/" target="_blank" rel="noopener"
 &gt;Multi-step Function&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://hatfullofdata.blog/power-query-replace-values-for-whole-table/" target="_blank" rel="noopener"
 &gt;Replace Values for Whole Table&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://hatfullofdata.blog/power-query-ai-insights-error/" target="_blank" rel="noopener"
 &gt;AI Insights Error&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://hatfullofdata.blog/excel-power-query-vba-to-edit-a-parameter-value/" target="_blank" rel="noopener"
 &gt;VBA to Edit a Parameter Value&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://hatfullofdata.blog/power-query-dynamic-data-source-and-web-content/" target="_blank" rel="noopener"
 &gt;Dynamic Data Source and Web.Contents()&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://hatfullofdata.blog/power-query-get-previous-row-data/" target="_blank" rel="noopener"
 &gt;Get Previous Row Data&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://hatfullofdata.blog/power-query-creating-new-parameters/" target="_blank" rel="noopener"
 &gt;Creating New Parameters&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://hatfullofdata.blog/power-query-fixing-missing-columns-dynamically/" target="_blank" rel="noopener"
 &gt;Fixing Missing Columns Dynamically&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://hatfullofdata.blog/power-query-handling-null-values/" target="_blank" rel="noopener"
 &gt;Handling Null Values Properly&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Power Query – Replace Values for Whole Table</title><link>https://hatfullofdata.blog/power-query-replace-values-for-whole-table/</link><pubDate>Wed, 15 Apr 2020 15:40:57 +0000</pubDate><guid>https://hatfullofdata.blog/power-query-replace-values-for-whole-table/</guid><description>&lt;img src="https://hatfullofdata.blog/power-query-replace-values-for-whole-table/cover.png" alt="Featured image of post Power Query – Replace Values for Whole Table" /&gt;&lt;p&gt;Today’s challenge was to replace the values on all the columns in the query when I know the columns will change so I don’t want to name them.&lt;/p&gt;
&lt;h3 id="quick-answer"&gt;Quick Answer
&lt;/h3&gt;&lt;p&gt;For those who don’t want the long explanation. Do replace values on at least one column to get the replace step. In the example below the previous step is #’Changed Type’ and the columns are Jan 20 and Feb 20.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-xml" data-lang="xml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;= Table.ReplaceValue(#&amp;#34;Changed Type&amp;#34;,null,0,Replacer.ReplaceValue,{&amp;#34;Jan 20&amp;#34;, &amp;#34;Feb 20&amp;#34;})
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Remove the {…} section and replace it with Table.ColumnNames(Previous Step)&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-xml" data-lang="xml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;= Table.ReplaceValue(#&amp;#34;Changed Type&amp;#34;,null,0,Replacer.ReplaceValue,Table.ColumnNames(#&amp;#34;Changed Type&amp;#34;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;img alt="Replace values with named columns" class="gallery-image" data-flex-basis="1052px" data-flex-grow="438" height="155" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://hatfullofdata.blog/power-query-replace-values-for-whole-table/ReplaceAll_001.png" width="680"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="Replace values on all columns" class="gallery-image" data-flex-basis="1110px" data-flex-grow="462" height="147" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://hatfullofdata.blog/power-query-replace-values-for-whole-table/ReplaceAll_002.png" width="680"&gt;&lt;/p&gt;
&lt;h3 id="longer-answer"&gt;Longer Answer
&lt;/h3&gt;&lt;p&gt;Replace values is a powerful tool for coping with null values and errors. When you select multiple columns and select Replaces values a step is written in that includes a list of column names, eg {“column1″,”column2″,”column3”}. If your data structure changes that step will either break because a column is missing or will not include a new column.&lt;/p&gt;
&lt;p&gt;The function Table.ColumnNames(StepName) returns a list of column names from the named step. To see this result and filter the list right click on a step and select Insert Step After. Edit the new step to be Table.ColumnNames(StepName)&lt;/p&gt;
&lt;p&gt;&lt;img alt="Column name list" class="gallery-image" data-flex-basis="1046px" data-flex-grow="435" height="156" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://hatfullofdata.blog/power-query-replace-values-for-whole-table/ReplaceAll_003.png" width="680"&gt;&lt;/p&gt;
&lt;p&gt;The list of column names can be filtered, even though there is no drop down arrow. Right click on the value to remove and select Remove Item.&lt;/p&gt;
&lt;p&gt;&lt;img alt="column name list" class="gallery-image" data-flex-basis="680px" data-flex-grow="283" height="240" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://hatfullofdata.blog/power-query-replace-values-for-whole-table/ReplaceAll_004.png" width="680"&gt;&lt;/p&gt;
&lt;p&gt;If I then rename this step to ColumnNames I can then use that step name in a replace step.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Replace Values using named step" class="gallery-image" data-flex-basis="943px" data-flex-grow="393" height="173" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://hatfullofdata.blog/power-query-replace-values-for-whole-table/ReplaceAll_005.png" width="680"&gt;&lt;/p&gt;
&lt;h3 id="note"&gt;Note
&lt;/h3&gt;&lt;p&gt;Yes the Replaced Value step is refering to a calculation that comes after it (yup its wacky). If you reorder the steps by dragging them Power Query will decide to change the code so steps refer to the new previous step.&lt;/p&gt;
&lt;h3 id="references"&gt;References
&lt;/h3&gt;&lt;p&gt;&lt;a class="link" href="https://docs.microsoft.com/en-us/powerquery-m/table-columnnames" target="_blank" rel="noopener"
 &gt;Microsoft Docs Table.ColumnNames&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="more-power-query-posts"&gt;More Power Query Posts
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://hatfullofdata.blog/power-query-handwritten-function/" target="_blank" rel="noopener"
 &gt;Custom Handwritten Function&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://hatfullofdata.blog/power-query-multi-step-function/" target="_blank" rel="noopener"
 &gt;Multi-step Function&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://hatfullofdata.blog/power-query-replace-values-for-whole-table/" target="_blank" rel="noopener"
 &gt;Replace Values for Whole Table&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://hatfullofdata.blog/power-query-ai-insights-error/" target="_blank" rel="noopener"
 &gt;AI Insights Error&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://hatfullofdata.blog/excel-power-query-vba-to-edit-a-parameter-value/" target="_blank" rel="noopener"
 &gt;VBA to Edit a Parameter Value&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://hatfullofdata.blog/power-query-dynamic-data-source-and-web-content/" target="_blank" rel="noopener"
 &gt;Dynamic Data Source and Web.Contents()&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://hatfullofdata.blog/power-query-get-previous-row-data/" target="_blank" rel="noopener"
 &gt;Get Previous Row Data&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://hatfullofdata.blog/power-query-creating-new-parameters/" target="_blank" rel="noopener"
 &gt;Creating New Parameters&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://hatfullofdata.blog/power-query-fixing-missing-columns-dynamically/" target="_blank" rel="noopener"
 &gt;Fixing Missing Columns Dynamically&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://hatfullofdata.blog/power-query-handling-null-values/" target="_blank" rel="noopener"
 &gt;Handling Null Values Properly&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Power Query Functions – SQL Procedures</title><link>https://hatfullofdata.blog/power-query-execute-sql-procedure/</link><pubDate>Sun, 06 Oct 2019 17:25:02 +0000</pubDate><guid>https://hatfullofdata.blog/power-query-execute-sql-procedure/</guid><description>&lt;p&gt;This is the fourth post in my series regarding writing custom functions in Power Query. This post describes how to create a function that will execute an SQL procedure, passing in a parameter.&lt;/p&gt;
&lt;p&gt;This series is to support my sessions at Data Relay 2019 and will cover the topics in the session.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://hatfullofdata.blog/power-query-handwritten-function/" target="_blank" rel="noopener"
 &gt;Handwritten Functions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://hatfullofdata.blog/power-query-multi-step-function/" target="_blank" rel="noopener"
 &gt;Multi-step Functions and Parameters&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://hatfullofdata.blog/power-query-fetch-web-data/" target="_blank" rel="noopener"
 &gt;Using functions to fetch web data&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://hatfullofdata.blog/power-query-function-to-execute-a-procedure/" target="_blank" rel="noopener"
 &gt;Executing SQL procedures from functions&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="stored-procedure"&gt;Stored Procedure
&lt;/h3&gt;&lt;p&gt;My database contains a very simple procedure that given a cost center returns all the expense records.&lt;/p&gt;
&lt;p&gt;&lt;img alt="stored procedure" class="gallery-image" data-flex-basis="886px" data-flex-grow="369" height="184" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://hatfullofdata.blog/power-query-execute-sql-procedure/customfunc_401.png" width="680"&gt;&lt;/p&gt;
&lt;p&gt;It can be run with the following SQL&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-xml" data-lang="xml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;EXECUTE dbo.GetExpenses @CostCenter=&amp;#34;B01&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="create-initial-query"&gt;Create Initial Query
&lt;/h3&gt;&lt;p&gt;The initial query will excute a procedure with a fixed parameter being passed to the procedure using the SQL in the previous section.&lt;/p&gt;
&lt;p&gt;Add a new source of SQL Server. Fill in the Server and Database and then click on Advanced options to reveal the SQL statement box where you enter the SQL statement to execute the procedure.&lt;/p&gt;
&lt;p&gt;&lt;img alt="entering in SQL procedure statement" class="gallery-image" data-flex-basis="232px" data-flex-grow="96" height="703" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://hatfullofdata.blog/power-query-execute-sql-procedure/customfunc_402.png" width="680"&gt;&lt;/p&gt;
&lt;p&gt;Click OK to and then Transform Data to edit the query. When the query opens it has only one step called Source.&lt;/p&gt;
&lt;h3 id="create-parameter-and-function"&gt;Create Parameter and Function
&lt;/h3&gt;&lt;p&gt;After creating the query, we need to create a parameter to store the value to pass into the procedure. So from the Home ribbon tab select Manage Parameters – New Parameter. You need to give the parameter a name and the type Text and lastly a value.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Creating parameter" class="gallery-image" data-flex-basis="291px" data-flex-grow="121" height="559" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://hatfullofdata.blog/power-query-execute-sql-procedure/customfunc_403.png" width="680"&gt;&lt;/p&gt;
&lt;p&gt;Then we need to edit the Source step of the query to use the above parameter. Remember to get the number of ” correct, you need 2 ” if the ” is inside a string.&lt;/p&gt;
&lt;p&gt;&lt;img alt="inserting parameter" class="gallery-image" data-flex-basis="761px" data-flex-grow="317" height="214" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://hatfullofdata.blog/power-query-execute-sql-procedure/customfunc_404-1.png" width="679"&gt;&lt;/p&gt;
&lt;p&gt;When you alter the query you might get a prompt asking for permission to run the query. For now let it run the query, further on in this post I will discuss this further.&lt;/p&gt;
&lt;p&gt;After we have included the parameter into the query it is ready to be converted into a function, just as we have done in previous posts. Right click on the query and select Create Function, then enter in a name for the function. As before the query and parameter get moved into a group with the new function.&lt;/p&gt;
&lt;p&gt;&lt;img alt="function group" class="gallery-image" data-flex-basis="309px" data-flex-grow="128" height="392" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://hatfullofdata.blog/power-query-execute-sql-procedure/customfunc_405.png" width="505"&gt;&lt;/p&gt;
&lt;p&gt;This function can now be invoked on a table of cost centers to give all the related expenses.&lt;/p&gt;
&lt;p&gt;&lt;img alt="cost center table" class="gallery-image" data-flex-basis="391px" data-flex-grow="163" height="273" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://hatfullofdata.blog/power-query-execute-sql-procedure/customfunc_409.png" width="445"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="expanded to expenses" class="gallery-image" data-flex-basis="872px" data-flex-grow="363" height="187" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://hatfullofdata.blog/power-query-execute-sql-procedure/customfunc_410.png" width="680"&gt;&lt;/p&gt;
&lt;h3 id="changing-security"&gt;Changing Security
&lt;/h3&gt;&lt;p&gt;When you invoke the query you will get a prompt asking for permission to run a native database query. This is a caution to warn you that some SQL is being run which could makes changes to the database.&lt;/p&gt;
&lt;p&gt;&lt;img alt="permission is required" class="gallery-image" data-flex-basis="1457px" data-flex-grow="607" height="112" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://hatfullofdata.blog/power-query-execute-sql-procedure/customfunc_406.png" width="680"&gt;&lt;/p&gt;
&lt;p&gt;When you click on Edit Permission you will be shown the SQL that is going to be executed, so you can check it carefully.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Native Database Query" class="gallery-image" data-flex-basis="329px" data-flex-grow="137" height="495" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://hatfullofdata.blog/power-query-execute-sql-procedure/customfunc_408.png" width="680"&gt;&lt;/p&gt;
&lt;p&gt;This request for permission can be turned off. Click on File and then Options, and then Security. The first option in the dialog is regarding Native Database Queries, by default the require approval is ticked. Be aware this changes it for all queries.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Turn off requiring approval" class="gallery-image" data-flex-basis="236px" data-flex-grow="98" height="691" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://hatfullofdata.blog/power-query-execute-sql-procedure/customfunc_407.png" width="680"&gt;&lt;/p&gt;
&lt;h3 id="conclusion"&gt;Conclusion
&lt;/h3&gt;&lt;p&gt;SQL procedures are a great way to make use of the dba to build the queries you need to fetch the data using your parameters. Obviously this will require many biscuits for the dba. I think there is plenty of scope for functions that execute an SQL procedure.&lt;/p&gt;
&lt;h3 id="resources"&gt;Resources
&lt;/h3&gt;&lt;p&gt;I am not the first, and hopefully not the last to write blog posts on writing functions in M for Power Query. Here are a list of the resources I found useful. (If you know of any good ones I’ve missed please let me know!)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://blog.crossjoin.co.uk/2016/05/15/creating-m-functions-from-parameterised-queries-in-power-bi/" target="_blank" rel="noopener"
 &gt;Chris Webb’s Creating M Functions From Parameterised Queries In Power BI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://skillsmatter.com/skillscasts/10210-working-with-parameters-and-functions-in-power-query-excel-and-power-bi" target="_blank" rel="noopener"
 &gt;Chris Webb presenting at Skills Matter on Working with Parameters and Functions in Power Query/Excel and Power BI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://ssbi-blog.de/writing-documentation-for-custom-m-functions/" target="_blank" rel="noopener"
 &gt;Lars Schreiber’s Writing documentation for custom M-functions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://bengribaudo.com/blog/2017/11/17/4107/power-query-m-primer-part1-introduction-simple-expressions-let" target="_blank" rel="noopener"
 &gt;Ben Gribaudo’s Power Query M Primer&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Power Query Functions – Fetch web data</title><link>https://hatfullofdata.blog/power-query-fetch-web-data/</link><pubDate>Sat, 05 Oct 2019 17:33:54 +0000</pubDate><guid>https://hatfullofdata.blog/power-query-fetch-web-data/</guid><description>&lt;p&gt;This is the third post in my Custom functions in Power Query series. Often web based data is split across multiple pages using the url to select the data. This post describes how to build a function that populates the parts of the url so multiple pages can be used to fetch web data can be combined.&lt;/p&gt;
&lt;p&gt;This series is to support my sessions at Data Relay 2019 and will cover the topics in the session.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://hatfullofdata.blog/power-query-handwritten-function/" target="_blank" rel="noopener"
 &gt;Handwritten Functions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://hatfullofdata.blog/power-query-multi-step-function/" target="_blank" rel="noopener"
 &gt;Multi-step Functions and Parameters&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://hatfullofdata.blog/power-query-fetch-web-data/" target="_blank" rel="noopener"
 &gt;Using functions to fetch web data&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://hatfullofdata.blog/power-query-function-to-execute-a-procedure/" target="_blank" rel="noopener"
 &gt;Executing SQL procedures from functions&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="initial-query-to-fetch-web-data"&gt;Initial Query to Fetch Web Data
&lt;/h3&gt;&lt;p&gt;We start the whole process by fetching data from one page of the web site. for my example in this post I am going to use data from Formula 1 racing. The page I am using as my initial page if for the first race in 2019 in Australia. The url is&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-xml" data-lang="xml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;https://www.formula1.com/en/results.html/2019/races/1000/australia/race-result.html
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;img alt="Web page" class="gallery-image" data-flex-basis="413px" data-flex-grow="172" height="395" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://hatfullofdata.blog/power-query-fetch-web-data/customfunc_301.png" width="680"&gt;&lt;/p&gt;
&lt;p&gt;I’ve used table by example to extract the data I need. (There is a blog post coming cover table by example.) So I end up with three step query.&lt;/p&gt;
&lt;p&gt;&lt;img alt="3 step query to fetch web data" class="gallery-image" data-flex-basis="766px" data-flex-grow="319" height="213" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://hatfullofdata.blog/power-query-fetch-web-data/customfunc_302.png" width="680"&gt;&lt;/p&gt;
&lt;h3 id="adding-first-parameter-to-web-query"&gt;Adding First Parameter to Web Query
&lt;/h3&gt;&lt;p&gt;The next step is to replace parts of the url with parameters in the Source step. If we look at the url it has three parts that could be made into parameters. The Race Year, Race Number and Race Name. For the the first race in 2019 the values would be :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;RaceYear – 2019&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;RaceNumber – 1000&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;RaceName – Australia&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The first parameter needs to be created before you change the Source step. From the Home ribbon tab, select Manage Parameters, New Parameter. Then you need to enter in a name for the parameter, a type of text and the current value. The type has to be text for the parameter to get included in the next step. Finally click OK to create the parameter.&lt;/p&gt;
&lt;p&gt;&lt;img alt="creating first parameter" class="gallery-image" data-flex-basis="299px" data-flex-grow="124" height="545" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://hatfullofdata.blog/power-query-fetch-web-data/customfunc_303-1.png" width="680"&gt;&lt;/p&gt;
&lt;p&gt;Now we can start to change the source step in the query. Start by clicking on the cog wheel of the Source step which will open a dialog. Then click on Advanced to give the option to break the URL into parts. You can click on Add Part to add extra rows. The first drop down allows offers Text or Parameter. If you don’t get the drop down on the left it means you don’t have any text parameters.&lt;/p&gt;
&lt;p&gt;&lt;img alt="adding first parameter to source" class="gallery-image" data-flex-basis="380px" data-flex-grow="158" height="429" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://hatfullofdata.blog/power-query-fetch-web-data/customfunc_304.png" width="680"&gt;&lt;/p&gt;
&lt;h3 id="adding-extra-parameters"&gt;Adding Extra Parameters
&lt;/h3&gt;&lt;p&gt;Earlier I stated that the url had three parts that could be put into parameters. We can create and add the new parameters inside the From Web dialog. Click Add Part to add a new row. From the new drop down select New Parameter and enter in the details of your new parameter, remember they need to be text.&lt;/p&gt;
&lt;p&gt;&lt;img alt="adding more parameters" class="gallery-image" data-flex-basis="318px" data-flex-grow="132" height="513" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://hatfullofdata.blog/power-query-fetch-web-data/customfunc_305.png" width="680"&gt;&lt;/p&gt;
&lt;p&gt;When you have finished adding new parameter and breaking the url up, click OK to save your changes. Check you still get the correct data from your query.&lt;/p&gt;
&lt;h3 id="creating-function-from-query"&gt;Creating Function from Query
&lt;/h3&gt;&lt;p&gt;We now have a query that can fetch web data which we now need to use to build a function from it..&lt;/p&gt;
&lt;p&gt;Right click on your query and select Create Function. Type in a name for the query.&lt;/p&gt;
&lt;p&gt;&lt;img class="gallery-image" data-flex-basis="608px" data-flex-grow="253" height="268" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://hatfullofdata.blog/power-query-fetch-web-data/customfunc_306.png" width="680"&gt;&lt;/p&gt;
&lt;p&gt;The query and the parameters are all moved into a group and a function is created. If any changes are required in the function, the changes need to be made to the query. If changes are made to the function it will break the link with the query.&lt;/p&gt;
&lt;p&gt;&lt;img alt="newly created function" class="gallery-image" data-flex-basis="652px" data-flex-grow="272" height="250" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://hatfullofdata.blog/power-query-fetch-web-data/customfunc_307.png" width="680"&gt;&lt;/p&gt;
&lt;h3 id="fetch-web-data-from-multiple-pages"&gt;Fetch web data from Multiple pages
&lt;/h3&gt;&lt;p&gt;I have a list of races with year, number and name in an Excel file which I load into a new query. In order for the function to work the RaceYear and RaceNumber columns need to be text.&lt;/p&gt;
&lt;p&gt;&lt;img alt="race data" class="gallery-image" data-flex-basis="336px" data-flex-grow="140" height="485" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://hatfullofdata.blog/power-query-fetch-web-data/customfunc_308.png" width="680"&gt;&lt;/p&gt;
&lt;p&gt;From the Add Column click Invoke Function. Type in a New column name and select the function in the drop. Then the parameters for the function will appear. Change the first drop down for each parameter to Column Name and select the column.&lt;/p&gt;
&lt;p&gt;&lt;img alt="invoke function" class="gallery-image" data-flex-basis="420px" data-flex-grow="175" height="388" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://hatfullofdata.blog/power-query-fetch-web-data/customfunc_309.png" width="680"&gt;&lt;/p&gt;
&lt;p&gt;When you click the OK button the function will run for every row of the table. This will create a column that contains tables. Click on the icon in the top right of the new column. In the dialog box that appears it will show the columns in the table. I un-ticked the Use original column name as prefix to keep the column names short,&lt;/p&gt;
&lt;p&gt;&lt;img alt="expand table column" class="gallery-image" data-flex-basis="580px" data-flex-grow="241" height="281" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://hatfullofdata.blog/power-query-fetch-web-data/customfunc_311.png" width="680"&gt;&lt;/p&gt;
&lt;p&gt;After OK is clicked the column of tables is replaced by the three columns from the table.&lt;/p&gt;
&lt;p&gt;&lt;img class="gallery-image" data-flex-basis="1157px" data-flex-grow="482" height="141" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://hatfullofdata.blog/power-query-fetch-web-data/customfunc_310.png" width="680"&gt;&lt;/p&gt;
&lt;h3 id="conclusion"&gt;Conclusion
&lt;/h3&gt;&lt;p&gt;If your data is web based this provides an efficient method of fetching web data into one table only using a few queries and a function.&lt;/p&gt;
&lt;h3 id="resources"&gt;Resources
&lt;/h3&gt;&lt;p&gt;I am not the first, and hopefully not the last to write blog posts on writing functions in M for Power Query. Here are a list of the resources I found useful. (If you know of any good ones I’ve missed please let me know!)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://blog.crossjoin.co.uk/2016/05/15/creating-m-functions-from-parameterised-queries-in-power-bi/" target="_blank" rel="noopener"
 &gt;Chris Webb’s Creating M Functions From Parameterised Queries In Power BI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://skillsmatter.com/skillscasts/10210-working-with-parameters-and-functions-in-power-query-excel-and-power-bi" target="_blank" rel="noopener"
 &gt;Chris Webb presenting at Skills Matter on Working with Parameters and Functions in Power Query/Excel and Power BI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://ssbi-blog.de/writing-documentation-for-custom-m-functions/" target="_blank" rel="noopener"
 &gt;Lars Schreiber’s Writing documentation for custom M-functions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://bengribaudo.com/blog/2017/11/17/4107/power-query-m-primer-part1-introduction-simple-expressions-let" target="_blank" rel="noopener"
 &gt;Ben Gribaudo’s Power Query M Primer&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Power Query – Multi-step Function</title><link>https://hatfullofdata.blog/power-query-multi-step-function/</link><pubDate>Sun, 29 Sep 2019 17:28:40 +0000</pubDate><guid>https://hatfullofdata.blog/power-query-multi-step-function/</guid><description>&lt;p&gt;This is the second post in my Writing Functions in M series. This post describes how to build a multi-step function in M to allow for a more complex function. We will create a parameter to base the calculations on and then build a function.&lt;/p&gt;
&lt;p&gt;This series is to support my sessions at Data Relay 2019 and will cover the topics in the session.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://hatfullofdata.blog/power-query-handwritten-function/" target="_blank" rel="noopener"
 &gt;Handwritten Functions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://hatfullofdata.blog/power-query-multi-step-function/" target="_blank" rel="noopener"
 &gt;Multi-step Functions and Parameters&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://hatfullofdata.blog/power-query-fetch-web-data/" target="_blank" rel="noopener"
 &gt;Using functions to fetch web data&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://hatfullofdata.blog/power-query-function-to-execute-a-procedure/" target="_blank" rel="noopener"
 &gt;Executing SQL procedures from functions&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="introduction"&gt;Introduction
&lt;/h3&gt;&lt;p&gt;In the first post of this series we built a different functions and all of them were a single step calculation. Some functions need to be made up of multiple steps. The example we will use in this example is to calculate the next working day based on Saturday and Sunday being non-working days.&lt;/p&gt;
&lt;p&gt;In simple terms the calculation is simple, if today is a Friday add 3 days, Saturday add 2 days, otherwise just add one day. I realise this could be done with a nested if, I’m using this example as a nice easy one to walk through.&lt;/p&gt;
&lt;h3 id="creating-a-parameter"&gt;Creating a Parameter
&lt;/h3&gt;&lt;p&gt;In order to make writing functions easier we create parameters to store the values passed into our multi-step function. This function will only require a single parameter to store the date which we want to calculate the next working day.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Select New Parameter" class="gallery-image" data-flex-basis="476px" data-flex-grow="198" height="342" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://hatfullofdata.blog/power-query-multi-step-function/customfunc_205.png" width="679"&gt;&lt;/p&gt;
&lt;p&gt;From the Home ribbon tab, select Manage Parameters and the New Parameter. Then enter in a name for the parameter, e.g. ThisDate and select a Type, e.g. Date. Finally add in a Current Value and press OK.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Setting up parameter" class="gallery-image" data-flex-basis="300px" data-flex-grow="125" height="544" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://hatfullofdata.blog/power-query-multi-step-function/customfunc_206.png" width="680"&gt;&lt;/p&gt;
&lt;h3 id="calculation-steps"&gt;Calculation Steps
&lt;/h3&gt;&lt;p&gt;Now we can start creating the function in with a blank query which I have renamed to NextWorkDay. This first step I am going to make equal to the parameter we created, ThisDate. (Remember the = , I have forgotten it too many times)&lt;/p&gt;
&lt;p&gt;&lt;img alt="Using parameter in the step" class="gallery-image" data-flex-basis="735px" data-flex-grow="306" height="222" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://hatfullofdata.blog/power-query-multi-step-function/customfunc_201-1.png" width="680"&gt;&lt;/p&gt;
&lt;p&gt;The first calculation step I am going to add is to calculate the day of the week of the given date. This can be done from the ribbon tab DateTime Tools. Select Date – Day – Day of Week and a new step gets added using the function Date.DayOfWeek.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Using ribbon to add new step." class="gallery-image" data-flex-basis="283px" data-flex-grow="118" height="575" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://hatfullofdata.blog/power-query-multi-step-function/customfunc_202.png" width="680"&gt;&lt;/p&gt;
&lt;p&gt;Rename the step just added to something shorter, e.g. WeekDay.&lt;/p&gt;
&lt;p&gt;The next step will be to calculate how many days to add to the date. You can add a new step by clicking on the fx next to the formula bar.&lt;/p&gt;
&lt;p&gt;We use an If statement based on the previous step. There is no quick way to add this so you will need to type in formula. The editor does now have intellisense so you should get some assistance in typing in names.&lt;/p&gt;
&lt;p&gt;&lt;img alt="intellisense in action" class="gallery-image" data-flex-basis="1174px" data-flex-grow="489" height="139" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://hatfullofdata.blog/power-query-multi-step-function/customfunc_203.png" width="680"&gt;&lt;/p&gt;
&lt;p&gt;Using the logic described in the second paragraph of the introduction the complete formula is&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-xml" data-lang="xml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;= if WeekDay=4 then 3 else 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; if WeekDay=5 then 2 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; else 1
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;And I rename the step to be DaysToAdd to make the next step easier and it should return 1,2 or 3. You can click on any step and see the result, for example clicking on Source gives you the date.&lt;/p&gt;
&lt;p&gt;So the final step is to use Source and DaysToAdd to calculate the next working day. We use the function Date.AddDays which requires 2 parameters, a date which is Source and the number of days to add which is DaysToAdd.&lt;/p&gt;
&lt;p&gt;&lt;img alt="FInal calculation step AddDays\n" class="gallery-image" data-flex-basis="562px" data-flex-grow="234" height="290" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://hatfullofdata.blog/power-query-multi-step-function/customfunc_204.png" width="680"&gt;&lt;/p&gt;
&lt;p&gt;We can change the date in the parameter ThisDate to test different dates and check the calculation logic. Now we are ready to convert this to function.&lt;/p&gt;
&lt;h3 id="creating-the-multi-step-function"&gt;Creating the Multi-step Function
&lt;/h3&gt;&lt;p&gt;Power Query includes a quick method to convert a query that uses a parameter into a function.&lt;/p&gt;
&lt;p&gt;Right click on the NextWorkDay function and from the menu select Create Function. Enter in a name for the function in the Create Function dialog and press OK.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Create function" class="gallery-image" data-flex-basis="593px" data-flex-grow="247" height="275" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://hatfullofdata.blog/power-query-multi-step-function/customfunc_207.png" width="680"&gt;&lt;/p&gt;
&lt;p&gt;This will move both NextWorkDay query and ThisDate parameter into a separate group with the new function. If you want to edit the function you need to edit NextWorkDay and it will update the function fnNextWorkDay. You can edit the function directly but it will break the connection with NextWorkDay so debugging will be harder and is not recommended.&lt;/p&gt;
&lt;h3 id="using-your-multi-step-function"&gt;Using your Multi-step Function
&lt;/h3&gt;&lt;p&gt;&lt;img alt="Final Function" class="gallery-image" data-flex-basis="832px" data-flex-grow="346" height="196" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://hatfullofdata.blog/power-query-multi-step-function/customfunc_208.png" width="680"&gt;&lt;/p&gt;
&lt;p&gt;The function can now be used in any query in your report by clicking Invoke Custom Column from the Add Column ribbon.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Invoking the multi-step function" class="gallery-image" data-flex-basis="540px" data-flex-grow="225" height="302" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://hatfullofdata.blog/power-query-multi-step-function/customfunc_209.png" width="680"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="final result" class="gallery-image" data-flex-basis="471px" data-flex-grow="196" height="346" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://hatfullofdata.blog/power-query-multi-step-function/customfunc_210.png" width="680"&gt;&lt;/p&gt;
&lt;h3 id="conclusion"&gt;Conclusion
&lt;/h3&gt;&lt;p&gt;The quick Create Function ability makes creating and editing the functions much easier. It makes building functions worth doing and not a huge development process.&lt;/p&gt;
&lt;h3 id="resources"&gt;Resources
&lt;/h3&gt;&lt;p&gt;I am not the first, and hopefully not the last to write blog posts on writing functions in M for Power Query. Here are a list of the resources I found useful. (If you know of any good ones I’ve missed please let me know!)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://blog.crossjoin.co.uk/2016/05/15/creating-m-functions-from-parameterised-queries-in-power-bi/" target="_blank" rel="noopener"
 &gt;Chris Webb’s Creating M Functions From Parameterised Queries In Power BI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://skillsmatter.com/skillscasts/10210-working-with-parameters-and-functions-in-power-query-excel-and-power-bi" target="_blank" rel="noopener"
 &gt;Chris Webb presenting at Skills Matter on Working with Parameters and Functions in Power Query/Excel and Power BI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://ssbi-blog.de/writing-documentation-for-custom-m-functions/" target="_blank" rel="noopener"
 &gt;Lars Schreiber’s Writing documentation for custom M-functions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://bengribaudo.com/blog/2017/11/17/4107/power-query-m-primer-part1-introduction-simple-expressions-let" target="_blank" rel="noopener"
 &gt;Ben Gribaudo’s Power Query M Primer&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Power Query – Custom Handwritten Function</title><link>https://hatfullofdata.blog/power-query-handwritten-function/</link><pubDate>Fri, 27 Sep 2019 17:50:43 +0000</pubDate><guid>https://hatfullofdata.blog/power-query-handwritten-function/</guid><description>&lt;h3 id="introduction"&gt;Introduction
&lt;/h3&gt;&lt;p&gt;In this post I will write a simple custom handwritten function to perform a calculation based off a parameter. We will then expand that function to include data types and optional parameters.&lt;/p&gt;
&lt;p&gt;For those who are new to programming a function is a piece of code that returns some data, which could be a single value, record or table of data. If you ever need to duplicate a calculation more that twice then it is worth considering writing a function.&lt;/p&gt;
&lt;p&gt;This series is to support my sessions at Data Relay 2019 and will cover the topics in the session.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://hatfullofdata.blog/power-query-handwritten-function/" target="_blank" rel="noopener"
 &gt;Handwritten Functions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://hatfullofdata.blog/power-query-multi-step-function/" target="_blank" rel="noopener"
 &gt;Multi-step Functions and Parameters&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://hatfullofdata.blog/power-query-fetch-web-data/" target="_blank" rel="noopener"
 &gt;Using functions to fetch web data&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://hatfullofdata.blog/power-query-function-to-execute-a-procedure/" target="_blank" rel="noopener"
 &gt;Executing SQL procedures from functions&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="the-hello-world-function"&gt;The Hello World function
&lt;/h3&gt;&lt;p&gt;Every programming 101 course includes some sort of Hello World function as the introduction. I would hate to break tradition.&lt;/p&gt;
&lt;p&gt;In Power Query we add a Blank Query and we get a blank formula bar. Enter in the following code.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-xml" data-lang="xml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;= () =&amp;gt; &amp;#34;Hello World&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;When you press return the blank query will be converted into a custom function. It gains an fx in the Queries list. It can be renamed in the Query Settings just like a query.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Hello World Function definition" class="gallery-image" data-flex-basis="872px" data-flex-grow="363" height="187" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://hatfullofdata.blog/power-query-handwritten-function/customfunc_101.png" width="680"&gt;&lt;/p&gt;
&lt;p&gt;The function can then be used to create a column in a table. From the Add Column ribbon tab, click Invoke Custom Function. Enter in a name for the new column and select the new function from the list.&lt;/p&gt;
&lt;p&gt;&lt;img alt="invoking Hello World function" class="gallery-image" data-flex-basis="587px" data-flex-grow="244" height="278" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://hatfullofdata.blog/power-query-handwritten-function/customfunc_102.png" width="680"&gt;&lt;/p&gt;
&lt;p&gt;This will add a column to your data. This example is a pretty useless example of just Hello World but tradition has been done and we are now ready to move to the next stage.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Data with Hello World column added" class="gallery-image" data-flex-basis="712px" data-flex-grow="296" height="229" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://hatfullofdata.blog/power-query-handwritten-function/customfunc_103.png" width="680"&gt;&lt;/p&gt;
&lt;h3 id="adding-a-parameter-to-our-handwritten-function"&gt;Adding a parameter to our Handwritten Function
&lt;/h3&gt;&lt;p&gt;The Hello World function just returned one value, which has a very limited use. So now we will add a parameter to our function and use that value to change our result to include that message.&lt;/p&gt;
&lt;p&gt;Parameter definitions go between the brackets in the definition. I’ve updated the function to be this code and on pressing return will now have details of the parameter required.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-xml" data-lang="xml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;= (GuestName) =&amp;gt; &amp;#34;Hello &amp;#34; &lt;span class="err"&gt;&amp;amp;&lt;/span&gt; GuestName
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;img alt="Hello function with parameter" class="gallery-image" data-flex-basis="473px" data-flex-grow="197" height="345" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://hatfullofdata.blog/power-query-handwritten-function/customfunc_104.png" width="680"&gt;&lt;/p&gt;
&lt;p&gt;If the function is being used anywhere you will need to modify the function. You can either remove and re-add the function or click the cog wheel on the relevant step. There are two possible windows you will get on clicking the cog wheel.&lt;/p&gt;
&lt;p&gt;&lt;img alt="invoke handwritten function" class="gallery-image" data-flex-basis="542px" data-flex-grow="225" height="301" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://hatfullofdata.blog/power-query-handwritten-function/customfunc_105.png" width="680"&gt;Editing a working custom function column&lt;/p&gt;
&lt;p&gt;&lt;img alt="edit function" class="gallery-image" data-flex-basis="381px" data-flex-grow="158" height="428" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://hatfullofdata.blog/power-query-handwritten-function/customfunc_106.png" width="680"&gt;Editing a custom function column that returns an error&lt;/p&gt;
&lt;p&gt;Your table will now show the result of your updated handwritten function.&lt;/p&gt;
&lt;p&gt;&lt;img alt="results" class="gallery-image" data-flex-basis="803px" data-flex-grow="334" height="203" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://hatfullofdata.blog/power-query-handwritten-function/customfunc_107.png" width="680"&gt;&lt;/p&gt;
&lt;h3 id="data-types"&gt;Data Types
&lt;/h3&gt;&lt;p&gt;I can feel my degree lectures turning in their graves as the above function has no data types specified. You can find many online references as to why adding data types into code is good practice, for this post please accept it is good practice and good practice usually leads to cleaner and faster code.&lt;/p&gt;
&lt;p&gt;The fnHelloWorld has a parameter that is text and it returns some text. So we can adjust the code with “as text” after the GuestName parameter and also after the ). It won’t change the function much but it will in the long term be a great habit to adopt.&lt;/p&gt;
&lt;p&gt;&lt;img alt="data types added" class="gallery-image" data-flex-basis="547px" data-flex-grow="228" height="298" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://hatfullofdata.blog/power-query-handwritten-function/customfunc_108.png" width="680"&gt;&lt;/p&gt;
&lt;h3 id="quick-look-at-if"&gt;Quick Look at If
&lt;/h3&gt;&lt;p&gt;One of the most used constructs in programming in any language must be the if statement. In order to help you build quick easy functions it is worth noting the syntax.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-xml" data-lang="xml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;if [TEST] then [TRUE RESULT] else [FALSE RESULT]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;So here is a very simple example of a function that calculates a delivery cost based on if the value is over 100 the delivery is free.&lt;/p&gt;
&lt;p&gt;&lt;img alt="simple if statement in an if function\n" class="gallery-image" data-flex-basis="735px" data-flex-grow="306" height="222" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://hatfullofdata.blog/power-query-handwritten-function/customfunc_109.png" width="680"&gt;&lt;/p&gt;
&lt;h3 id="optional-parameters"&gt;Optional Parameters
&lt;/h3&gt;&lt;p&gt;Last topic in this post is to make parameter optional and handling when it is not provided. Optional parameters must be the last parameters defined in your function.&lt;/p&gt;
&lt;p&gt;So in my example I’m going to add a column that calculates tax based on the value and the optional tax rate. If no tax rate is given 20% is assumed.&lt;/p&gt;
&lt;p&gt;The parameters have to be withoutTax value followed by taxRate as the taxRate is optional. We can test for no taxRate being given by testing for taxRate = null. So our function is&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-xml" data-lang="xml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;= (withoutTax as number, optional taxRate as number) as number =&amp;gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; if taxRate = null then 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; withoutTax * 0.1 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; else 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; withoutTax * taxRate
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;img alt="picture of function definition" class="gallery-image" data-flex-basis="514px" data-flex-grow="214" height="317" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://hatfullofdata.blog/power-query-handwritten-function/customfunc_110.png" width="680"&gt;&lt;/p&gt;
&lt;p&gt;Adding a tax column to example data shows how Alex’s tax rate is null so the tax is calculated at 10% and Jo’s tax is calculated at the given rate of 20%.&lt;/p&gt;
&lt;p&gt;&lt;img alt="data showing tax calculation" class="gallery-image" data-flex-basis="868px" data-flex-grow="361" height="188" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://hatfullofdata.blog/power-query-handwritten-function/customfunc_111.png" width="680"&gt;&lt;/p&gt;
&lt;h3 id="conclusion-on-handwritten-functions"&gt;Conclusion on Handwritten Functions
&lt;/h3&gt;&lt;p&gt;These are very simple examples of functions but even these can save hours of repeating calculations. When your data has the same cleanup calculations being done to your data over many queries this allows for one function to be used repeatably.&lt;/p&gt;
&lt;h3 id="resources"&gt;Resources
&lt;/h3&gt;&lt;p&gt;I am not the first, and hopefully not the last to write blog posts on writing functions in M for Power Query. Here are a list of the resources I found useful. (If you know of any good ones I’ve missed please let me know!)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://blog.crossjoin.co.uk/2016/05/15/creating-m-functions-from-parameterised-queries-in-power-bi/" target="_blank" rel="noopener"
 &gt;Chris Webb’s Creating M Functions From Parameterised Queries In Power BI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://skillsmatter.com/skillscasts/10210-working-with-parameters-and-functions-in-power-query-excel-and-power-bi" target="_blank" rel="noopener"
 &gt;Chris Webb presenting at Skills Matter on Working with Parameters and Functions in Power Query/Excel and Power BI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://ssbi-blog.de/writing-documentation-for-custom-m-functions/" target="_blank" rel="noopener"
 &gt;Lars Schreiber’s Writing documentation for custom M-functions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://bengribaudo.com/blog/2017/11/17/4107/power-query-m-primer-part1-introduction-simple-expressions-let" target="_blank" rel="noopener"
 &gt;Ben Gribaudo’s Power Query M Primer&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item></channel></rss>