The Power Query (M) Builder is a new tool for the XrmToolBox.
It is designed to automate the basic Power Queries for getting data into Power BI from Dynamics 365. This includes selecting fields, renaming fields, querying option sets etc.
Updated: July 22 2018. This page is a work in progress and will continue to be updated.
Here is an intro video on how to use the tool, and some of its features, particularly using FetchXML in your Power Query so you can easily retrieve the option set labels, lookup names, etc.
Video is for Power Query Builder version 1.2018.7.20. (Latest version)
Like the Advanced Chart Editor, the tool was developed between Mohamed Rasheed and myself.
Features included in this tool:
- Support for FetchXML in your Power Query
- Show labels for Option Sets and Status fields
- Show name for Lookup fields
- Show name and type for Owner and Customer fields
- Support for OData retrieval (standard querying method for Dynamics 365)
- Auto-include GUID for current entity
- Use Dynamics 365 display name for all columns
- Automatically set correct data type
- Auto-generate a link back to the Dynamics 365
- Handle empty tables when no records are retrieved
- Use of all-attributes in FetchXML as a setting
Check back regularly for more information about the Power Query Builder for the XrmToolBox that helps accelerate getting data from Dynamics 365 into Power BI.
Some stuff that we are still working on:
- Include fields from related (parent) entities
Ideas, how to questions, feedback etc. please put that in the comments below.
Issues, bugs etc. please put that on GitHub: https://github.com/ITLec/PowerQueryBuilder
NuGet link: https://nuget.org/packages/PowerQueryBuilder/
A big thank you to Scott Sewell, who provided a lot of great feedback during the development of this tool. We still have items on the to-do list.
Also, we want to thank Keith Mescha and the former Sonoma Partners Power BI Accelerator. This tool showed us how to do FetchXML pagination in a Power Query. Without it, all the benefits of using FetchXML would have been limited to just 5,000 records.
As always, please sign up for my newsletter or follow me on Twitter for the latest details Follow @CRMChartGuy
[…] FetchXML via the Power Query Builder is not available in Power BI, but is a tool in the XrmToolBox. It uses metadata from Dynamics 365/CDS to generate a Power Query string you can copy and paste into Power BI and do the transformations you need. The Power Query Builder has additional benefits beyond what is outlined in this post. Read more about those here. […]
Hello,
Has anyone found a solution to connecting to CRM 2016 On Premise v.9.0? I haven’t been able to pull a query due to “DataFormat.Error: We found extra characters at the end of the JSON input. Details: Value= Position=1” along with connecting to the on API???
Thanks,
Same issue with v8.2. Impossible to use the tool unless I can address the problem.
Hello,
This tool is just great and allows miracles with Powerquery or PowerBI !
Many many Thanks, You’re a Genius !
Thanks so much. We really appreciate the comments. Hope to come out with an updated version in the next month or so.
Hi there, I was trying to follow your guidelines but I get this error message “Expression.Error: The name ‘Dyn365CEBaseURL’ wasn’t recognized. Make sure it’s spelled correctly.”. Of course, the ServiceRootURL has been copied directly from the XrmToolbox. Any ideas?
Many many thanks in advance.
Figured it out! Great job Ulrik! Thanks so much!
Awesome!
Do you have a query named Dyn365CEBaseURL, similar to your ServiceRootURL? The base url content is your standard https://YOURORG.dynamics.crm.com url.
Hi Ulrik,
I’m experienced with PBI but am completely new to D365 so I’m finding your material very helpful.
Quick question. In following this article, the FetchXML is showing columns as expected as per your example. Before becoming aware of the FetchXML method, I was using the Dynamics 365 (online) PBI connector. One of the many columns this connector showed was a ‘Table’ column named xxx_patent_account. In expanding this table column I had a list of further columns I could expand. I chose accountid as this is the field that joins the patent table to the account table (I would then go on to merge the patent and account tables). However, in following the FetchXML method, and selecting ‘Use all-attributes’, I could not find the xxx_patent_account ‘Table’ column available in order to expand it so to retrieve the joining column.
Does this FetchXML method only allow the option to bring in display columns, and doesn’t bring in columns that are for joining purposes?
I hope you understanding what I am trying to explain. I am still attempting to understand how D365 structures it’s database. I’m hoping soon to export the data from D365 to Azure SQL and then use T-SQL to query the data. I hope that this way the data will be more transparent.
Thanks in advance.
Hi Dan.
First I’d urge you to check out the Common Data Service connector instead of the D365 one, as that would be the one to use moving forward, if not using FetchXML.
Also, the expand option you are referring to, is generally a very expensive option from a performance point of view, so I generally recommend never using unless you have small datasets. You can create advanced FetchXML that would query those related tables and get you the data needed. That is something that FetchXML can also do much efficiently than the standard connector, but you have to write it as a part of the FetchXML query. Check out the FetchXML Builder in the XrmToolBox, and the integration to it from the Power Query Builder if you want to look more at that.
You can see a comparison of the different query methods here. https://crmchartguy.com/2019/07/23/comparing-the-three-main-ways-to-get-dynamics-365-data-into-power-bi/
Has anyone tried to use PQB to build Power BI Dataflows?
1. My queries work in the Query Builder in PBI Desktop.
2. When I take the advanced editor text and paste it into the dataflow window I could not get the table to resolve. I ended up hard-coding the Service Root URL in the primary query to get the dataflow to visualize in the dataflow power query window.
3. Unfortunately, when the query refreshes I am getting this error “Error: Privacy settings don’t allow the combining of data from multiple sources in the same query. \n\r To refresh this dataflow you can either edit the queries or you can allow combining data from multiple sources in the Edit queries Options settings. Request ID: 8ece0d18-61fb-0080-75e9-c778ded55b77 Activity ID: 12d0eae8-b4d5-461d-aeff-955d6e880323”
ANY IDEAS would save me days of work:-)
[…] “secret sauce” in this video is the Power Query (M) Builder for the […]
[…] FetchXML via the Power Query Builder is not available in Power BI, but is a tool in the XrmToolBox. It uses metadata from Dynamics 365/CDS to generate a Power Query string you can copy and paste into Power BI and do the transformations you need. The Power Query Builder has additional benefits beyond what is outlined in this post. Read more about those here. […]
[…] If you are new to the Power Query (M) Builder and how it can accelerate Power BI report development from Dynamics 365, check out the intro page here. […]
I love the Power Query Building tool and use it for our Power BI reporting in Dynamics 365 CE. However, I am trying to bring in the ‘Notes’ entity and I do not see the objectid field in the list of available fields for ‘Notes’ in the Power Query tool. Am I doing someone wrong? Is there a way to get that?
I need to connect the notes left on entity records and bring them into Power BI … not seeing how I can do this at this time. Any advice would be helpful.
They may be listed under ‘Annotations’.
Hi Ulrik,
I’m really getting a lot out of Power Query Builder so thanks for that!
I came across one issue which I can’t resolve. I’m hoping you might have time to assist.
I created a query using your tool to pull in Email records from D365
Initially I get the error below in Power BI when I paste the query in to advanced editor
“Expression.Error: The field ‘_from_value@OData.Community.Display.V1.FormattedValue’ already exists in the record.
Details:
Name=_from_value@OData.Community.Display.V1.FormattedValue
Value=”
This seems to be based on this section in the query
“_from_value@OData.Community.Display.V1.FormattedValue”,
“_from_value”,
“_from_value@OData.Community.Display.V1.FormattedValue”,
I tried removing the Lookup value and leaving the GUID and the “hidden” values.
The query runs ok but the From fields all have Null Values
I also tried renaming the duplicate entry from “_from_value” to “_from_value_hidden” which allows the query to run but again, all the ‘From’ columns have Null values
The same is happening for ‘To’ fields.
And the issue is also occurring when I create a query for PhoneCall records.
Kind Regards,
Sean
Hi Sean, I’m having the same issue as you, did you find a solution?
Hi Cleiton,
No, I didn’t find a resolution for this. There could be a simple solution but other priorities took over so it wasn’t something I actively pursued in the end.
Hello, this tool seems a great resource based on what i’m reading and seeing! Unfortunately, i’m stuck. When running the query, I get the following message (right from the ResultsList step):
DataFormat.Error: We found extra characters at the end of JSON input.
Details:
Value=
Position=0
I see others have had the same problem. Authentication seems to be working. I’m not a JSON developer and cannot figure out what might be the “extra characters”.
Has anyone solved this problem?
Absolutely brilliant tool, thanks for your hard work on it!
I have a question about some custom option sets which I can’t seem to find when they are generated. We have one which can either be against Account or Opportunity but after I’ve generated the Option Sets I don’t see it. Does anyone have any idea why?
I managed to figure this out, a bit of trial and error using the code generated from the Account Entity. I ended up just editing the code referencing the fields in the ResultsTable and then the #”Expanded Column1″ option. I did have to reference slightly differently: fieldname@OData.Community.Display.V1.FormattedValue
Hi Ulrik,
Have you found a good way to work with multi-select fields in Power BI? It would be really awesome to add this to the Power Query Builder.
-Dan
Hi there
Could anyone guide me on how to include a linked entity in the FetchXML builder so I can pull it into PowerBI straight?
Cheers
Lars
Hi Guys,
First, many thanks for this fabulous tool. I have one suggestion for you. When I generate the query, it has step Rename before Change type. The steps should be Change type – rename. Rename should be last step. Often I want to rename the columns names and so I need to do it twice (because the change type is after rename).
[…] https://crmchartguy.com/power-query-builder/ […]
Hi,
I have used out of the Box “My Open Opportunities” view and it gives error for “Est Closed Date”. Then I tried to add any date field, still give me the following error:
DataFormat.Error: We couldn’t parse the input provided as a Date value.
The DAX Query is as follows:
let
GetResults = (z as text, x as number) =>
let
S = Json.Document(Web.Contents(ServiceRootURL, [RelativePath=”/opportunities”, Headers=[Prefer=”odata.include-annotations=*”],Query=[fetchXml=”
“]])),
P = try Xml.Document(S[#”@Microsoft.Dynamics.CRM.fetchxmlpagingcookie”]) otherwise null,
R = if P null
then List.Combine({S[value],@GetResults(Text.Replace(Text.Replace(Text.Replace(Uri.Parts(“http://a.b?d=” & Uri.Parts(“http://a.b?d=” & P{0}[Attributes]{1}[Value])[Query][d])[Query][d], “>”, “>”), “<", "<"), """", """), x + 1)})
else S[value]
in
R,
ResultsList = GetResults("", 1),
ResultsTable = if List.IsEmpty(ResultsList)
then #table(
type table[ #"Topic"= text,
#"Est. Revenue"= number,
#"Est. Close Date"= text,
#"Probability"= number,
#"Rating (opportunityratingcode)"= text,
#"Rating"= text,
#"Contact (parentcontactid)"= text,
#"Contact"= text,
#"Account (parentaccountid)"= text,
#"Account"= text,
#"Potential Customer (customerid)"= text,
#"Potential Customer (Type)"= text,
#"Potential Customer"= text,
#"opportunityid"= text,
#"Email (Potential Customer)"= text ],{})
else #"Converted to Table",
#"Converted to Table" = Table.FromList(ResultsList, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
#"Expanded Column1" = Table.ExpandRecordColumn(#"Converted to Table", "Column1",
{
"name",
"estimatedvalue",
"estimatedclosedate@OData.Community.Display.V1.FormattedValue",
"closeprobability",
"opportunityratingcode",
"opportunityratingcode@OData.Community.Display.V1.FormattedValue",
"_parentcontactid_value",
"_parentcontactid_value@OData.Community.Display.V1.FormattedValue",
"_parentaccountid_value",
"_parentaccountid_value@OData.Community.Display.V1.FormattedValue",
"_customerid_value",
"_customerid_value@Microsoft.Dynamics.CRM.lookuplogicalname",
"_customerid_value@OData.Community.Display.V1.FormattedValue",
"opportunityid",
"opportunitycustomeridcontactcontactid.emailaddress1"
},
{
"name",
"estimatedvalue",
"estimatedclosedate@OData.Community.Display.V1.FormattedValue",
"closeprobability",
"opportunityratingcode",
"opportunityratingcode@OData.Community.Display.V1.FormattedValue",
"_parentcontactid_value",
"_parentcontactid_value@OData.Community.Display.V1.FormattedValue",
"_parentaccountid_value",
"_parentaccountid_value@OData.Community.Display.V1.FormattedValue",
"_customerid_value",
"_customerid_value@Microsoft.Dynamics.CRM.lookuplogicalname",
"_customerid_value@OData.Community.Display.V1.FormattedValue",
"opportunityid",
"opportunitycustomeridcontactcontactid.emailaddress1"
}),
#"Renamed Columns" = Table.RenameColumns(#"Expanded Column1",
{
{"name", "Topic"},
{"estimatedvalue", "Est. Revenue"},
{"estimatedclosedate@OData.Community.Display.V1.FormattedValue", "Est. Close Date"},
{"closeprobability", "Probability"},
{"opportunityratingcode", "Rating (opportunityratingcode)"},
{"opportunityratingcode@OData.Community.Display.V1.FormattedValue", "Rating"},
{"_parentcontactid_value", "Contact (parentcontactid)"},
{"_parentcontactid_value@OData.Community.Display.V1.FormattedValue", "Contact"},
{"_parentaccountid_value", "Account (parentaccountid)"},
{"_parentaccountid_value@OData.Community.Display.V1.FormattedValue", "Account"},
{"_customerid_value", "Potential Customer (customerid)"},
{"_customerid_value@Microsoft.Dynamics.CRM.lookuplogicalname", "Potential Customer (Type)"},
{"_customerid_value@OData.Community.Display.V1.FormattedValue", "Potential Customer"},
{"opportunityid", "opportunityid"},
{"opportunitycustomeridcontactcontactid.emailaddress1", "Email (Potential Customer)"}
}),
#"Changed Type" = Table.TransformColumnTypes(#"Renamed Columns",
{
{"Topic", type text},
{"Est. Revenue", type number},
{"Est. Close Date", type date},
{"Probability", type number},
{"Rating (opportunityratingcode)", type text},
{"Rating", type text},
{"Contact (parentcontactid)", type text},
{"Contact", type text},
{"Account (parentaccountid)", type text},
{"Account", type text},
{"Potential Customer (customerid)", type text},
{"Potential Customer (Type)", type text},
{"Potential Customer", type text},
{"opportunityid", type text},
{"Email (Potential Customer)", type text}
})
,
#"Added Link" = Table.AddColumn(#"Changed Type", "Link", each Dyn365CEBaseURL & "/main.aspx?etn=opportunity&pagetype=entityrecord&id=%7b"& [opportunityid]&"%7d"),
#"Result" = if List.IsEmpty(ResultsList)
then ResultsTable
else #"Added Link"
in
#"Result"