<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Abdihamid Idris</title>
    <description>The latest articles on DEV Community by Abdihamid Idris (@abdihamid_idris_5b327e49e).</description>
    <link>https://dev.to/abdihamid_idris_5b327e49e</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3849413%2F3179dda4-f6a0-409a-ab4e-c0244b73bd47.png</url>
      <title>DEV Community: Abdihamid Idris</title>
      <link>https://dev.to/abdihamid_idris_5b327e49e</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/abdihamid_idris_5b327e49e"/>
    <language>en</language>
    <item>
      <title>Publishing a Power BI Report and Embedding It into a Website</title>
      <dc:creator>Abdihamid Idris</dc:creator>
      <pubDate>Sun, 05 Apr 2026 00:21:32 +0000</pubDate>
      <link>https://dev.to/abdihamid_idris_5b327e49e/publishing-a-power-bi-report-and-embedding-it-into-a-website-517h</link>
      <guid>https://dev.to/abdihamid_idris_5b327e49e/publishing-a-power-bi-report-and-embedding-it-into-a-website-517h</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;The topic that I find it easy to explain than ever since the starting of my data analytics classes at LuxDev HQ has been Power BI. It's like a front-end programming language where you see what you do in the Power Query or the desktop. Power BI provides Microsoft business intelligence tools, converting raw data into visualizations, dashboards, and reports. Power BI is one of the most used analytics tools by Data Analysts now, after launching in 2015. It is the organization's powerhouse in decision-making. The platform is composed of three components that are working together: Power BI Desktop, Power BI service, Power BI mobile. Building up a report in Power BI Desktop is only the beginning of the analytics journey. For your analysis to have actual business value, stakeholders must be able to read and deal with it — which is to say to publish the same thing in a place that anyone can read it. A professionally crafted dashboard on a single analyst’s laptop makes for no organizational value. The publishing process takes your report from your machine locally to the Power BI Service and makes it a living, shareable resource that can be accessed by peers, inserted into internal pages of internal platforms, or shared on websites and blogs. This article walks through the end-to-end publishing process: creating a workspace, publishing a report, generating embed code, and integrating the report onto a website. You'll get an idea of not only what this mechanical stage entails,  what sorts of strategic decisions about security, licensing, and audience make or break and what kind of publication pathway is best for your own specific situation.&lt;/p&gt;




&lt;h2&gt;
  
  
  Understanding the Publishing Process
&lt;/h2&gt;

&lt;p&gt;When you "publish" a Power BI report, you are uploading it from Power BI Desktop (your PC) to Power BI Service (the cloud). And we’re not just copying a file — the publishing also distills your data model, DAX measures, visualizations, and formatting into the Power BI Service’s cloud infrastructure, becoming resources that are independent of you and can be managed, refreshed, and shared on their own. Then once published, the report is a live thing you can share directly with your specific users through email; add to Power BI apps for organization-wide distribution; iframe code to embed into websites or applications; scheduled for data refresh automatically from source systems, all of which you can monitor for usage using built-in analytics. The publishing destinations are known as a &lt;strong&gt;workspace&lt;/strong&gt; — a container containing related reports, dashboards, datasets, dataflows and all the related reports such as analytics. Every Power BI user has a "My Workspace" set-to-default for personal work. For work-a-day-work, however, professional analysis frequently occurs in shared workspaces where teams come together working together. &lt;/p&gt;




&lt;h2&gt;
  
  
  Step 1: Workspace
&lt;/h2&gt;

&lt;p&gt;Workspace organizes your projects and controls who can access it. Here is how to create one:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open web browser and click through app.powerbi.com. Sign in with your Microsoft account.
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Workspaces&lt;/strong&gt; in the left navigation pane.
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;+ New workspace&lt;/strong&gt; at the bottom of the workspace list.
&lt;/li&gt;
&lt;li&gt;Fill in the workspace details:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Name&lt;/strong&gt;: Name it very clearly according to your report like example;Sale analytics report.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Description&lt;/strong&gt;: Optional but useful for teams to know the meaning of workspace.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Advanced options&lt;/strong&gt;: Configures access level and license mode.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Apply&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You will see your new workspace in the Workspaces list. You can add team members later on by clicking the &lt;strong&gt;Access&lt;/strong&gt; button within the workspace that will also input their email addresses with assigned roles.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqxwqp3s06o8zgsrppfbq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqxwqp3s06o8zgsrppfbq.png" alt=" " width="800" height="388"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The Roles of workspaces
&lt;/h3&gt;

&lt;p&gt;Power BI provides four workspace roles, all with different permissions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Admin&lt;/strong&gt;: Has complete control over members,can delete workspace and update content as well as users&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Member&lt;/strong&gt;: Can only edit and share content but cannot add other admins or delete workspaces
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Contributor&lt;/strong&gt;: Has the ability to add and edit content but not permissions, does not own permissions, cannot publish apps
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Normally, there are one or two admins to handle the workspace, members to building the report, and viewers consuming the finished reports.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Creating shared workspaces requires a Power BI Pro or Premium Per User license. If you only have a free license you  still have an access to publish to My Workspace, but sharing will be limited to users who also have Pro licenses.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 2: Uploading and Publishing Reports
&lt;/h2&gt;

&lt;p&gt;After creating your own workspace, you can post your report via Power BI Desktop.&lt;/p&gt;

&lt;h3&gt;
  
  
  Publishing from Power BI Desktop
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Open your finished report in Power BI Desktop.
&lt;/li&gt;
&lt;li&gt;Save the file (Ctrl+S) to ensure all of your most recent changes have been recorded.
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Publish&lt;/strong&gt; on the Home ribbon.
&lt;/li&gt;
&lt;li&gt;Sign in, if you are prompted, with your Microsoft account.
&lt;/li&gt;
&lt;li&gt;Then a dialog appears, with available workspaces — choose your target workspace.
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Select&lt;/strong&gt;.
&lt;/li&gt;
&lt;li&gt;The tool is uploaded and the file is verified when uploaded to Power BI and once it has been posted that it is complete.
&lt;/li&gt;
&lt;li&gt;Click that link to open your report in Power BI Service.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The complete publishing usually takes 30 seconds to a few minutes each time depending on file size and the complexity of the presented data.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff1afcmjhkt2eh4jjfze0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff1afcmjhkt2eh4jjfze0.png" alt=" " width="800" height="539"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Confirming the Published Report
&lt;/h3&gt;

&lt;p&gt;After publishing, click your workspace in Power BI Service. Three items will be revealed: The &lt;strong&gt;Report&lt;/strong&gt; , the &lt;strong&gt;Dataset&lt;/strong&gt;  and if needed a &lt;strong&gt;Dashboard&lt;/strong&gt; .&lt;/p&gt;

&lt;p&gt;Open by clicking the report name. Test every page, slicer, drill-through, and visual to make sure everything works exactly how it was in Power BI Desktop. Look through the images — embedded images can sometimes upload wrong and have to be added again in the Service.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkwjkvnlmbjip3paykl2j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkwjkvnlmbjip3paykl2j.png" alt=" " width="800" height="398"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 3: Create the Embed Code.
&lt;/h2&gt;

&lt;p&gt;There are three embedding solutions available with Power BI for different scenarios. Choosing the wrong option may put security at risk.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Option&lt;/th&gt;
&lt;th&gt;Who Can View&lt;/th&gt;
&lt;th&gt;License Needed&lt;/th&gt;
&lt;th&gt;Best For&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Publish to Web&lt;/td&gt;
&lt;td&gt;Anyone with the link (public)&lt;/td&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;td&gt;Blogs, public dashboards, portfolios&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Secure Embed&lt;/td&gt;
&lt;td&gt;Authenticated Power BI users&lt;/td&gt;
&lt;td&gt;Pro for each viewer&lt;/td&gt;
&lt;td&gt;Internal corporate portals, SharePoint&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Power BI Embedded&lt;/td&gt;
&lt;td&gt;Any app user (via developer setup)&lt;/td&gt;
&lt;td&gt;Azure capacity&lt;/td&gt;
&lt;td&gt;Customer-facing SaaS products&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxqsvje5877cdc4lrmgj2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxqsvje5877cdc4lrmgj2.png" alt=" " width="645" height="583"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Option A: Publishing to the Web (Public Embedding)
&lt;/h3&gt;

&lt;p&gt;This option creates an embed code that makes your report &lt;strong&gt;publicly accessible to anyone with the link&lt;/strong&gt;. Perfect for blog posts, public dashboards, portfolio pieces, and marketing sites — but never for confidential information.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open your published report in Power BI Service
&lt;/li&gt;
&lt;li&gt;In the report menu bar, click &lt;strong&gt;File&lt;/strong&gt; → &lt;strong&gt;Embed report&lt;/strong&gt; → &lt;strong&gt;Publish to web (public)&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Read the warning dialog carefully — this makes your report public and indexable by search engines
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Create embed code&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Confirm by clicking &lt;strong&gt;Publish&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;A dialog displays two items: a direct &lt;strong&gt;Link&lt;/strong&gt; URL and an &lt;strong&gt;HTML&lt;/strong&gt; iframe code snippet
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Copy the HTML code — it looks similar to this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;iframe&lt;/span&gt; 
  &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;"800"&lt;/span&gt; 
  &lt;span class="na"&gt;height=&lt;/span&gt;&lt;span class="s"&gt;"600"&lt;/span&gt; 
  &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://app.powerbi.com/view?r=eyJrIjoiYWJjMTIzNDU2NyIsInQiOiJ4eXo5ODc2NTQzMjEifQ"&lt;/span&gt; 
  &lt;span class="na"&gt;frameborder=&lt;/span&gt;&lt;span class="s"&gt;"0"&lt;/span&gt; 
  &lt;span class="na"&gt;allowFullScreen=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/iframe&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Option B: Secure Embed (Internal Use)
&lt;/h3&gt;

&lt;p&gt;For reports containing sensitive data, use secure embedding instead. Viewers must have a Power BI account with explicit permission to access the report.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open the report in Power BI Service
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;File&lt;/strong&gt; → &lt;strong&gt;Embed report&lt;/strong&gt; → &lt;strong&gt;Website or portal&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Copy the provided URL and embed code
&lt;/li&gt;
&lt;li&gt;Users accessing the embedded report will be prompted to sign in with their Microsoft credentials&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Option C: Power BI Embedded (For Customer-Facing Apps)
&lt;/h3&gt;

&lt;p&gt;This is a paid Azure service for embedding reports into commercial applications where end users don't have Power BI licenses — for example, a SaaS analytics product that serves dashboards to thousands of customers. It requires developer setup with access tokens, API integration, and Azure capacity provisioning.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 4: Embedding the Report on a Website
&lt;/h2&gt;

&lt;p&gt;Once you have the embed code, adding it to a website takes minutes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Embedding in a Standard HTML Page
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Open your website's HTML file in any text editor
&lt;/li&gt;
&lt;li&gt;Locate the spot where you want the report to appear
&lt;/li&gt;
&lt;li&gt;Paste the iframe code block directly into the HTML
&lt;/li&gt;
&lt;li&gt;Save the file and upload it to your web server&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Example full HTML structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Sales Dashboard&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Quarterly Sales Performance&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Interactive dashboard below:&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;iframe&lt;/span&gt; 
    &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;"100%"&lt;/span&gt; 
    &lt;span class="na"&gt;height=&lt;/span&gt;&lt;span class="s"&gt;"600"&lt;/span&gt; 
    &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://app.powerbi.com/view?r=YOUR_REPORT_ID"&lt;/span&gt; 
    &lt;span class="na"&gt;frameborder=&lt;/span&gt;&lt;span class="s"&gt;"0"&lt;/span&gt; 
    &lt;span class="na"&gt;allowFullScreen=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/iframe&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Common Issues and Troubleshooting
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Publish button grayed out.&lt;/strong&gt; This usually means that you are not signed in. Go to File → Sign in and authenticate with your Microsoft account.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"You don't have permission to publish to this workspace" error.&lt;/strong&gt; The workspace admin has not granted you Contributor access. Request access from  workspace admin.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Embedded report shows blank or "Access denied".&lt;/strong&gt; For public embeds, verify that Publish to Web is enabled in your tenant settings (your Power BI administrator controls this). For secure embeds, ensure the viewer has been granted workspace access.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Report does not refresh automatically.&lt;/strong&gt; Check that scheduled refresh is enabled and that data source credentials haven't expired. Expired credentials are the most common cause of failed refreshes.&lt;/p&gt;




&lt;h2&gt;
  
  
  Best Practices and Security Considerations
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Security first.&lt;/strong&gt; Never use "Publish to web" for reports containing personal information, financial details, customer data, or any sensitive business information. Once published publicly, the report is indexable by search engines and accessible to anyone who finds the link.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Monitor your published content.&lt;/strong&gt; Navigate to &lt;strong&gt;Settings&lt;/strong&gt; → &lt;strong&gt;Manage embed codes&lt;/strong&gt; in Power BI Service to see all your public embeds. Delete any that are no longer needed. Auditing public embeds should be a regular part of your Power BI governance routine.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Test across devices.&lt;/strong&gt; Open your embedded report on desktop, and mobile to verify visuals are showing correctly. Consider building a mobile-optimized layout in Power BI Desktop before publishing, accessible through View → Mobile Layout.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Plan for data refresh.&lt;/strong&gt; Embedded reports display the most recent dataset refresh. Configure your refresh schedule to match how often your audience expects updated numbers — daily for most business reports, hourly for operational dashboards.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Document your workspaces.&lt;/strong&gt; As your library of reports grows, maintain documentation describing each workspace's purpose, owner, refresh schedule, and data sources. Future team members will thank you.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use app workspaces for distribution.&lt;/strong&gt; Instead of sharing individual reports, store related content into a Power BI app. Apps provide consumers with a curated, navigation-friendly experience and keep your behind-the-scenes workspace clean.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Publishing a Power BI report transforms it from a local file into an accessible business tool. The four-step workflow — creating a workspace, publishing the report, generating embed code, and inserting it into a website — takes only minutes once you understand the process.&lt;/p&gt;

&lt;p&gt;For portfolio pieces or blog posts, publishing to web is straightforward and free. For internal business reporting, secure embedding maintains data protection while still allowing easy integration into company portals and intranets. For commercial applications serving external customers, Power BI Embedded provides the scalable infrastructure to serve reports to thousands of users with a secure access.&lt;/p&gt;

&lt;p&gt;The technical steps are easy to learn but the strategic choices around security, licensing, and audience determine whether your published reports succeed or create problems. Always consider who should see the data before choosing an embedding option, and revisit your published content regularly to ensure it remains accurate, relevant, and appropriately secured.&lt;/p&gt;

&lt;p&gt;Whichever path fits your needs, publishing is where Power BI reports become genuinely valuable — moving from analysis to action by putting insights directly in front of decision-makers where they work every day.&lt;/p&gt;

</description>
      <category>automation</category>
      <category>data</category>
      <category>analytics</category>
      <category>datascience</category>
    </item>
    <item>
      <title>Understanding Data Modeling in Power BI: Joins, Relationships, and Schemas Explained</title>
      <dc:creator>Abdihamid Idris</dc:creator>
      <pubDate>Sun, 29 Mar 2026 15:47:15 +0000</pubDate>
      <link>https://dev.to/abdihamid_idris_5b327e49e/-understanding-data-modeling-in-power-bi-joins-relationships-and-schemas-explained--337b</link>
      <guid>https://dev.to/abdihamid_idris_5b327e49e/-understanding-data-modeling-in-power-bi-joins-relationships-and-schemas-explained--337b</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Data modeling is about how the tables of Power BI gets organized and linked with other tables so it can properly do the work. In this article I will be going through the basic building blocks of Power BI data modeling - SQL-style joins, relationships, fact vs dimension tables, schema patterns, and the common mistakes I see people make all the time. I’ll try to keep it practical in the form of examples and give you real guidance on where to click in the Power BI interface.&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 1: What Is Data Modeling?
&lt;/h2&gt;

&lt;p&gt;Data modeling is about determining how you structure your tables and how they communicate with one another. In Power BI, your data model is everything — the tables, relationships between them, and calculated columns and measures you build on top.&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 2: SQL Joins — Combining Data Before It Hits the Model
&lt;/h2&gt;

&lt;p&gt;Before your data even makes it into the Power BI model, you often need to combine tables from different sources. That's where joins come in.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbss5rygew6xnyng2io5e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbss5rygew6xnyng2io5e.png" alt="Image containing SQL joins" width="800" height="479"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A join is like asking, “Every row in this table, which rows in this other table match up?” The answer varies depending on what type of join you choose. A common catch for beginners is the fact that &lt;strong&gt;joins happen in Power Query Editor&lt;/strong&gt;  the transformation layer and not the model itself. You're literally smashing tables together before they load.&lt;/p&gt;




&lt;h3&gt;
  
  
  2.1 INNER JOIN
&lt;/h3&gt;

&lt;p&gt;This one is the strictest. It  will only show you rows when both tables match. No match? That row gets tossed.&lt;/p&gt;

&lt;p&gt;Say you have an Orders table and Customers table. When you INNER JOIN on CustomerID, the data that appears from customers you've already recorded to your Customers table is only for those customers currently in it. Got an order from customer C3 (your order, but C3 isn't in your customer list)? Gone.&lt;/p&gt;

&lt;p&gt;Orders Table              Customers Table&lt;br&gt;
┌──────────┬────────┐     ┌──────────┬──────────┐&lt;br&gt;
│ OrderID  │ CustID │     │ CustID   │ Name     │&lt;br&gt;
├──────────┼────────┤     ├──────────┼──────────┤&lt;br&gt;
│ 1001     │ C1     │     │ C1       │ Alice    │&lt;br&gt;
│ 1002     │ C2     │     │ C2       │ Bob      │&lt;br&gt;
│ 1003     │ C3     │     │ C4       │ Diana    │&lt;br&gt;
│ 1004     │ C5     │     │ C5       │ Eve      │&lt;br&gt;
└──────────┴────────┘     └──────────┴──────────┘&lt;/p&gt;

&lt;p&gt;INNER JOIN Result (on CustID):&lt;br&gt;
┌──────────┬────────┬──────────┐&lt;br&gt;
│ OrderID  │ CustID │ Name     │&lt;br&gt;
├──────────┼────────┼──────────┤&lt;br&gt;
│ 1001     │ C1     │ Alice    │&lt;br&gt;
│ 1002     │ C2     │ Bob      │&lt;br&gt;
│ 1004     │ C5     │ Eve      │&lt;br&gt;
└──────────┴────────┴──────────┘&lt;br&gt;
→ Order 1003 (C3) is dropped: no match in Customers.&lt;br&gt;
→ Customer C4 (Diana) is dropped: no matching Order.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
![Image explaining inner joins](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y5mv35yc7tuqril90nj6.png)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
plaintext&lt;/p&gt;


&lt;h3&gt;
  
  
  2.2 LEFT (OUTER) JOIN
&lt;/h3&gt;

&lt;p&gt;This is the join I use most. You keep every row from the left table, and if there's a match in the right table, great — those columns get filled in. If not, you get nulls, but the row stays.&lt;/p&gt;

&lt;p&gt;Basically a LEFT JOIN flipped. Everything from the right table stays, with matching rows from the left traveling along. Unmatched left-side stuff appears as null. If you needed to see all your customers — even those who’d never bought anything — you would use this. Diana would show up with null for OrderID. As it stands now, most analysts I know just swap the table order and use a LEFT JOIN. Same outcome, easier to keep track of.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;LEFT JOIN Result (Orders LEFT JOIN Customers on CustID):

┌──────────┬────────┬──────────┐
│ OrderID  │ CustID │ Name     │
├──────────┼────────┼──────────┤
│ 1001     │ C1     │ Alice    │
│ 1002     │ C2     │ Bob      │
│ 1003     │ C3     │ null     │  ← No match, but order sticks around
│ 1004     │ C5     │ Eve      │
└──────────┴────────┴──────────┘
→ All 4 orders are preserved.  Diana (C4) does not show up, because she has no orders.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
plaintext&lt;br&gt;
This is your go-to when the left table is the important one and you want to enrich it with extra info from somewhere else.&lt;/p&gt;


&lt;h3&gt;
  
  
  2.3 RIGHT (OUTER) JOIN
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;RIGHT JOIN Result (Orders RIGHT JOIN Customers on CustID):
┌──────────┬────────┬──────────┐
│ OrderID  │ CustID │ Name     │
├──────────┼────────┼──────────┤
│ 1001     │ C1     │ Alice    │
│ 1002     │ C2     │ Bob      │
│ null     │ C4     │ Diana    │  ← No order, but she stays
│ 1004     │ C5     │ Eve      │
└──────────┴────────┴──────────┘
→ Order 1003 (C3) is dropped because C3 is does not exist in Customers.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;br&gt;
plaintext&lt;/p&gt;

&lt;p&gt;2.4 FULL OUTER JOIN&lt;br&gt;
The "keep everything" option. Every row from both tables comes into the output. Columns merge where there is a match between the rows. Where there isn’t, you get nulls on whichever side is missing. This is a lot easier when it comes to data reconciliation, when you’re trying to find what is in Table A and what is not in Table B or vice versa.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FULL OUTER JOIN Result:
┌──────────┬────────┬──────────┐
│ OrderID  │ CustID │ Name     │
├──────────┼────────┼──────────┤
│ 1001     │ C1     │ Alice    │
│ 1002     │ C2     │ Bob      │
│ 1003     │ C3     │ null     │  ← Order with no customer
│ null     │ C4     │ Diana    │  ← Customer with no order
│ 1004     │ C5     │ Eve      │
└──────────┴────────┴──────────┘
→ Nothing gets dropped. Both orphaned sides are preserved.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
plaintext&lt;br&gt;
I mostly pull this out during data quality audits, or when I'm first exploring a new dataset and want to see what matches up and what doesn't.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Filynr4ybtfiu98m2svqn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Filynr4ybtfiu98m2svqn.png" alt=" " width="800" height="513"&gt;&lt;/a&gt;&lt;/p&gt;



&lt;p&gt;2.5 LEFT ANTI JOIN&lt;br&gt;
For data validation, I'm a fan of this one personally. It only gives you the left-table rows that do not have a match on the right. It is kind of the opposite of an INNER JOIN. Looking for orders that refer to a customer ID that is nonexistent? Left anti join. Boom — orphaned records.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;LEFT ANTI JOIN Result:
┌──────────┬────────┐
│ OrderID  │ CustID │
├──────────┼────────┤
│ 1003     │ C3     │  ← This order has no matching customer
└──────────┴────────┘

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Super useful for catching data integrity problems early.&lt;/p&gt;




&lt;p&gt;2.6 RIGHT ANTI JOIN&lt;br&gt;
Same idea, other direction. Gives you rows from the right table that have no match in the left. Classic use case: identify customers who have never placed a single order.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;RIGHT ANTI JOIN Result:
┌────────┬──────────┐
│ CustID │ Name     │
├────────┼──────────┤
│ C4     │ Diana    │  ← Never ordered anything
└────────┴──────────┘

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Used for identifying inactive customers, unused products, or anything that should be connected but isn't.&lt;/p&gt;




&lt;h3&gt;
  
  
  2.7 How to Actually Do Joins in Power BI
&lt;/h3&gt;

&lt;p&gt;All of this happens in Power Query Editor, through the Merge Queries feature. Here's how to do it:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1:&lt;/strong&gt; Open Power BI Desktop. Hit &lt;strong&gt;Transform Data&lt;/strong&gt; on the Home ribbon — that drops you into Power Query Editor.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2:&lt;/strong&gt; In the Queries pane on the left, click the table you want as your "left" table.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3:&lt;/strong&gt; On the Home ribbon inside Power Query, click &lt;strong&gt;Merge Queries&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 4:&lt;/strong&gt; The Merge dialog will pop up. Your left table is pre-selected at the top. Pick your right table from the dropdown below. Click the matching column in both table previews — like CustID in each. Then, at the bottom, choose your &lt;strong&gt;Join Kind&lt;/strong&gt;: Inner, Left Outer, Right Outer, Full Outer, Left Anti, or Right Anti.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 5:&lt;/strong&gt; Click OK. A new column shows up containing nested tables — that's the merged data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 6:&lt;/strong&gt; Click the expand icon (those little arrows ↔) on the new column header and pick which columns from the right table you want to bring in.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 7:&lt;/strong&gt; Hit &lt;strong&gt;Close &amp;amp; Apply&lt;/strong&gt; and the merged result loads into your model.&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 3: Power BI Relationships
&lt;/h2&gt;

&lt;p&gt;Here's where things differ from joins in an important way. Joins  combine two tables into one. &lt;strong&gt;Relationships&lt;/strong&gt; keep the tables separate but create a logical link between them inside the model. They tell Power BI how to filter across tables and aggregate data without actually merging anything.&lt;/p&gt;

&lt;p&gt;So: joins happen during data loading (in Power Query). Relationships exist within the model, after the data's already loaded. This distinction matters.&lt;/p&gt;




&lt;h3&gt;
  
  
  3.1 Cardinality
&lt;/h3&gt;

&lt;p&gt;Cardinality shows how many rows on one side can match rows on the other."&lt;/p&gt;

&lt;h4&gt;
  
  
  One-to-Many (1:M) — This Is What You Want
&lt;/h4&gt;

&lt;p&gt;Think of it this way: one customer can have many orders, but each order belongs to him only.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Customers (1 side)          Orders (Many side)
┌────────┬────────┐         ┌──────────┬────────┬────────┐
│ CustID │ Name   │         │ OrderID  │ CustID │ Amount │
├────────┼────────┤         ├──────────┼────────┼────────┤
│ C1     │ Alice  │───1:M──▶│ 1001     │ C1     │ 50     │
│        │        │         │ 1005     │ C1     │ 120    │
│ C2     │ Bob    │───1:M──▶│ 1002     │ C2     │ 80     │
└────────┴────────┘         └──────────┴────────┴────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why is this the gold standard? Because filters flow cleanly. Choose “Alice” in a slicer and Power BI identifies and displays which orders to show. Aggregations will work here.&lt;/p&gt;

&lt;h4&gt;
  
  
  Many-to-Many (M:M)
&lt;/h4&gt;

&lt;p&gt;This occurs when neither table has unique values in the join column. Multiple rows match multiple rows on both sides.&lt;/p&gt;

&lt;p&gt;A common example would be students and courses — each student takes multiple courses, each course has several students. If you link these directly without a bridge table, you’ve got an M:M relationship on your hands.&lt;/p&gt;

&lt;p&gt;The problem? Filters can get weird. You might have double counting or totals that are larger than they should be. Power BI technically does allow M:M relationships, but in my experience, they're generally a sign that there isn't a bridge table in between.&lt;/p&gt;

&lt;h4&gt;
  
  
  One-to-One (1:1)
&lt;/h4&gt;

&lt;p&gt;Each row exactly corresponds to one row in the other table. Both sides have unique values.&lt;/p&gt;

&lt;p&gt;A lot of times this can be seen in situations where a specific table may have been split into two for the sake of organization.&lt;/p&gt;




&lt;h3&gt;
  
  
  3.2 Cross-Filter Direction
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Single Direction (typically the right choice)
Filters  from the "one" side to the "many" side only like a one way.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Customers ──filter──▶ Orders. (Select a customer → their orders are filtered).  
Orders ──X──▶ Customers. (Choose an order → doesn’t filter the Customers table)  
This keeps things predictable. Dimension tables filter fact tables, not the other way around. Exactly what you want for most reports.

#### Bidirectional  
Filters travel both ways. Selecting something in either table filters the other.

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
plaintext&lt;br&gt;
Customers ◀──filter──▶ Orders&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;I’d say use this sparingly. There are genuine scenarios — certain M:M bridge table setups need it — but when people start flipping everything to bidirectional, things get messy. Performance takes a hit, and you can end up with filter behavior that nobody on your team can explain.

My rule of thumb: start with single direction. Only switch to bidirectional when you've got a concrete reason and you've tested the impact.

---

### 3.3 Active vs. Inactive Relationships  
Power BI only lets you have **one active relationship** between any two tables at a time. If you've got multiple connections between the same pair of tables, pick one as active — the rest as inactive.

Here is where this comes up constantly. Your `Sales` table has `OrderDate`, `ShipDate`, and maybe `DeliveryDate`. All three should connect to your `Calendar` table. But only one relationship can be active at a time.

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
plaintext&lt;br&gt;
Calendar (Date)&lt;br&gt;&lt;br&gt;
│&lt;br&gt;&lt;br&gt;
├── Active Relationship ──── Sales[OrderDate]&lt;br&gt;&lt;br&gt;
│&lt;br&gt;&lt;br&gt;
└── Inactive Relationship ─ ─ ─ Sales&lt;a href="https://dev.todashed%20line"&gt;ShipDate&lt;/a&gt;&lt;br&gt;&lt;br&gt;
Active relationship is the default function used by DAX. If you need the inactive one, you write USERELATIONSHIP:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Ship Date Sales = 
CALCULATE(
    SUM(Sales[Amount]),
    USERELATIONSHIP(Sales[ShipDate], Calendar[Date])
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Not the best solution, but it works. In my dimensions role-playing later on, I'll discuss some possible alternate methods.&lt;/p&gt;




&lt;h3&gt;
  
  
  3.4 Creating relationships-step by step
&lt;/h3&gt;

&lt;p&gt;There are three methods for doing that.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Method 1: Drag and Drop in Model View&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Click the Model View icon in your left sidebar (the one that looks like three boxes) and you will actually see how they are connected together. You will notice all your tables arranged. You just tap one column in one table and drag it to the other corresponding column. Power BI auto-determines the cardinality and filter direction — so just click on the line twice to adjust those settings.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Method 2: Manage Relationships Dialog&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Redirect to Home (or Modeling) ribbon → &lt;strong&gt;Manage Relationships&lt;/strong&gt;. Click &lt;strong&gt;New&lt;/strong&gt;, select your tables and columns from the dropdowns, set cardinality, filter direction, select if it's active, and hit the OK button.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Method 3: Let Power BI Auto-Detect&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Once you load the data, Power BI will then try to guess some relationships based on column names and what data types you have. It does an okay job for stuff, but I always check what it generates. Go to &lt;strong&gt;Manage Relationships&lt;/strong&gt; and check. I've watched auto-detect build quite dubious relationships.&lt;/p&gt;


&lt;h2&gt;
  
  
  Part 4: Joins vs. Relationships — What Is the Difference?
&lt;/h2&gt;

&lt;p&gt;This mystifies people who are just getting started, so just a couple words:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fraa0md3jomllgiysa6j1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fraa0md3jomllgiysa6j1.png" alt="Image illustrating the differences btwn joins and r/ships" width="800" height="454"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspect&lt;/th&gt;
&lt;th&gt;Joins (Power Query)&lt;/th&gt;
&lt;th&gt;Relationships (Model)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Where&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Power Query Editor&lt;/td&gt;
&lt;td&gt;Model View / Manage Relationships&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;When&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;During data loading&lt;/td&gt;
&lt;td&gt;After data is in the model&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;What happens&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Tables physically merge into one&lt;/td&gt;
&lt;td&gt;Tables stay separate, linked logically&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Row count&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Can change (more or fewer rows)&lt;/td&gt;
&lt;td&gt;Tables keep their original row counts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;When to use&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Enriching or cleaning data&lt;/td&gt;
&lt;td&gt;Enabling cross-table filtering and aggregation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Performance&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Makes tables bigger&lt;/td&gt;
&lt;td&gt;VertiPaq handles it efficiently&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;DAX&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Merged columns are all in one table&lt;/td&gt;
&lt;td&gt;Uses RELATED/RELATEDTABLE to traverse&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;My general rule: Use joins (Merge in Power Query) when you need to physically combine or clean stuff — adding a lookup value or deduplicating. Use relationships for pretty much everything else. Keeping tables separate and letting Power BI handle the filtering is always the better approach.&lt;/p&gt;


&lt;h2&gt;
  
  
  Part 5: Fact Tables vs. Dimension Tables
&lt;/h2&gt;

&lt;p&gt;If there's one concept that makes everything click, it's understanding the difference between facts and dimensions. This is the foundation.&lt;/p&gt;
&lt;h3&gt;
  
  
  Fact Tables
&lt;/h3&gt;

&lt;p&gt;These hold the &lt;strong&gt;events&lt;/strong&gt; — the things that happened. A sale, a shipment, a website click, a support ticket. Each row is a transaction.&lt;/p&gt;

&lt;p&gt;What makes a fact table a fact table:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It has &lt;strong&gt;measures&lt;/strong&gt; — numbers you want to add up (revenue, quantity, cost, duration)&lt;/li&gt;
&lt;li&gt;It has &lt;strong&gt;foreign keys&lt;/strong&gt; — pointers to dimension tables (CustomerID, ProductID, DateKey)&lt;/li&gt;
&lt;li&gt;It's &lt;strong&gt;tall&lt;/strong&gt; — lots of rows, not too many columns&lt;/li&gt;
&lt;li&gt;It &lt;strong&gt;grows&lt;/strong&gt; — new transactions keep getting added&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Think: Sales, Orders, WebClicks, SupportTickets, Shipments.&lt;/p&gt;
&lt;h3&gt;
  
  
  Dimension Tables
&lt;/h3&gt;

&lt;p&gt;These provide the &lt;strong&gt;context&lt;/strong&gt; — the who, what, where, when, and why behind your transactions.&lt;/p&gt;

&lt;p&gt;What makes a dimension table a dimension table:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It has &lt;strong&gt;descriptive columns&lt;/strong&gt; — names, categories, regions, dates&lt;/li&gt;
&lt;li&gt;It has a &lt;strong&gt;primary key&lt;/strong&gt; — a unique identifier for each row&lt;/li&gt;
&lt;li&gt;It's &lt;strong&gt;wide&lt;/strong&gt; — many columns, relatively fewer rows&lt;/li&gt;
&lt;li&gt;It &lt;strong&gt;changes slowly&lt;/strong&gt; — a customer's name or address doesn't change every day&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Think: Customers, Products, Calendar, Geography, Employees, Stores.&lt;/p&gt;
&lt;h3&gt;
  
  
  How They Fit Together
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌──────────────┐     ┌──────────────────────────────┐     ┌──────────────┐
│  Customers   │     │         Sales (Fact)          │     │   Products   │
│  (Dimension) │     │                               │     │  (Dimension) │
├──────────────┤     ├──────────────────────────────┤     ├──────────────┤
│ *CustomerID  │◀─1:M│ SaleID                        │M:1─▶│ *ProductID   │
│  Name        │     │ CustomerID (FK)               │     │  ProductName │
│  City        │     │ ProductID (FK)                │     │  Category    │
│  Segment     │     │ DateKey (FK)                  │     │  Price       │
└──────────────┘     │ Quantity                      │     └──────────────┘
                     │ Amount                        │
                     └──────────────────────────────┘
                                   │
                                  M:1
                                   │
                              ┌─────────┐
                              │Calendar │
                              │(Dim)    │
                              ├─────────┤
                              │*Date    │
                              │ Month   │
                              │ Quarter │
                              │ Year    │
                              └─────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The asterisk identifies the primary key. Filters move from the dimension tables (the "one" side) to the fact table (the "many" side). Choose a customer, a product, or a date — and the sales figures update accordingly. That's the whole magic trick.&lt;/p&gt;


&lt;h2&gt;
  
  
  Part 6: Schema Designs
&lt;/h2&gt;

&lt;p&gt;Schema is just a word for the overall shape of your model — how you've arranged your fact and dimension tables.&lt;/p&gt;


&lt;h3&gt;
  
  
  6.1 Star Schema
&lt;/h3&gt;

&lt;p&gt;If you take one thing away from this entire article, let it be this: &lt;strong&gt;use of a star schema&lt;/strong&gt;. It's what Power BI was designed for.&lt;/p&gt;

&lt;p&gt;The idea is simple. You’ve got a fact table in the center, and your dimension tables connect to it directly — like points on a star.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzwbfm80zrmzjlm4yvipt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzwbfm80zrmzjlm4yvipt.png" alt="Image showing star schema" width="800" height="569"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                    ┌────────────┐
                    │  Calendar  │
                    └──────┬─────┘
                           │
┌────────────┐    ┌────────┴────────┐    ┌────────────┐
│ Customers  ├────┤   Sales (Fact)  ├────┤  Products  │
└────────────┘    └────────┬────────┘    └────────────┘
                           │
                    ┌──────┴─────┐
                    │   Stores   │
                    └────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every dimension goes directly to the fact table. The dimensions themselves are &lt;strong&gt;denormalized&lt;/strong&gt;, so you group all the descriptive properties into a single table, even if there’s some duplication. You maintain a ProductName, a SubCategory, a Category, and a &lt;em&gt;Department&lt;/em&gt; in one table, even though that hierarchy technically could be normalized into separate tables. Why bother with the redundancy? Because it's worth it. Power BI's VertiPaq engine is optimized for exactly that kind of pattern. Filters from dimension to fact — no detours. DAX behaves predictably. Report writers can uncover what they need without detective work. In practically every project, I rely on star schemas. It should be your default.&lt;/p&gt;




&lt;h3&gt;
  
  
  6.2 Snowflake Schema
&lt;/h3&gt;

&lt;p&gt;A snowflake schema is what happens when you take a star schema and &lt;strong&gt;normalize&lt;/strong&gt; the dimensions — splitting them into chains of sub-tables.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌──────────────┐    ┌──────────────┐    ┌──────────────────┐
│  Department  ├────┤  Category    ├────┤    Products      │
└──────────────┘    └──────────────┘    └────────┬─────────┘
                                                 │
                                        ┌────────┴────────┐
                                        │  Sales (Fact)   │
                                        └────────┬────────┘
                                                 │
                                          ┌──────┴─────┐
                                          │  Calendar  │
                                          └────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While one Products table might have everything, now you have Products → Category → Department as separate tables in a chain. If this is a traditional SQL data warehouse, it's going to save storage space. But in Power BI? VertiPaq already compresses data incredibly well, so those storage savings are basically meaningless. Meanwhile, you’ve added extra problems for filters to travel through, made writing DAX hard, and confused anyone who tries to build a report. My advice: if the source data that you’re using is snowflaked (and that is often the case when it comes from enterprise data warehouses), flatten those dimension chains before you load them in Power Query. Merge the sub-tables back together. Turn it into a star.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fix39u7gl7l5548gwb27d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fix39u7gl7l5548gwb27d.png" alt="Image showing snowflake schemas example" width="800" height="497"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;h3&gt;
  
  
  6.3 Flat Table
&lt;/h3&gt;

&lt;p&gt;This is the approach of "dump everything into one giant table." That is — facts, dimensions, all of it — one wide table with no associations in it, because there’s nothing to connect to.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌─────────────────────────────────────────────────────────┐
│                   FlatSalesTable                        │
├─────────────────────────────────────────────────────────┤
│ SaleID │ Date │ CustomerName │ City │ ProductName │ ... │
│ Amount │ Quantity │ Category │ Segment │ StoreName │ ... │
└─────────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Look, we've all done this. You export something out of Excel and load it directly into Power BI and begin building visuals. For a quick personal analysis with a few hundred rows, it works, for sure.&lt;/p&gt;

&lt;p&gt;But the second you scale up, things unravel. Every single row has repeat customer names and addresses. The file balloons in size. Compression suffers. DAX becomes quirky since a measure is hard to tell apart from a descriptive attribute. And heaven help you if you ever needed to update a customer address — you'd have to change it on maybe thousands of rows.&lt;/p&gt;

&lt;p&gt;Flat tables make analysis easy to toss. If you need to separate your facts apart from your dimensions for anything else, take the time to do so.&lt;/p&gt;




&lt;h3&gt;
  
  
  6.4 Quick comparison
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Star Schema&lt;/th&gt;
&lt;th&gt;Snowflake Schema&lt;/th&gt;
&lt;th&gt;Flat Table&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Complexity&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;td&gt;Medium-High&lt;/td&gt;
&lt;td&gt;Lowest&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Power BI Performance&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Best&lt;/td&gt;
&lt;td&gt;Decent (extra hops)&lt;/td&gt;
&lt;td&gt;Poor at scale&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Data redundancy&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Some (in dimensions)&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;td&gt;Very high&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;DAX friendliness&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Very friendly&lt;/td&gt;
&lt;td&gt;Trickier (multi-hop)&lt;/td&gt;
&lt;td&gt;Unpredictable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Scalability&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Excellent&lt;/td&gt;
&lt;td&gt;Good&lt;/td&gt;
&lt;td&gt;Poor&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;My Recommendation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;default choice&lt;/td&gt;
&lt;td&gt;Flatten it first&lt;/td&gt;
&lt;td&gt;Small stuff only&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4bsr6kp9nkjj9yfgbt36.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4bsr6kp9nkjj9yfgbt36.png" alt=" " width="800" height="308"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 7: Role-Playing Dimensions
&lt;/h2&gt;

&lt;p&gt;Here’s one scenario that crops up all the time. You’ve got a Calendar table, and your Sales fact table has a bunch of date columns — OrderDate, ShipDate, DeliveryDate. All three logically connect to the same Calendar table, but they each contribute a disparate analytical perspective. This is a role-playing dimension. There is one dimension table and multiple hats on.&lt;/p&gt;

&lt;p&gt;When you need ship date analysis, employ USERELATIONSHIP in DAX:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;Shipped&lt;/span&gt; &lt;span class="n"&gt;Amount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 
&lt;span class="n"&gt;CALCULATE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;SUM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Sales&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Amount&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
    &lt;span class="n"&gt;USERELATIONSHIP&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Sales&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ShipDate&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;Calendar&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It’s something tidy too. One calendar to follow. On the downside, report writers have to be informed that they get USERELATIONSHIP and only the active relationship can work by default.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Option B: Duplicate Calendar Table&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Make separate calendar tables in Power Query — OrderCalendar, ShipCalendar, DeliveryCalendar — with its own active relationship to the date column. Also, more tables in the model. I have come to realize with every relationship in operation, you do not use USERELATIONSHIP, you can drop independent slicers for each date role without DAX gymnastics. When secondary date roles are seldom discussed in reports I opt for Option A. If stakeholders always have to slice by ship date and delivery date as well as by order date, Option B saves a lot of headaches.&lt;/p&gt;


&lt;h2&gt;
  
  
  Part 8: Common Data Modeling Mistakes and How to Correct Them
&lt;/h2&gt;

&lt;p&gt;Let me take you through the problems I encounter most frequently.&lt;/p&gt;
&lt;h3&gt;
  
  
  Ambiguous Relationships
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;What you will see:&lt;/strong&gt; A mistake regarding the presence of a relationship between tables, or as in “ambiguous paths.”&lt;br&gt;&lt;br&gt;
&lt;strong&gt;What you missed:&lt;/strong&gt; You have multiple active paths between two tables, and Power BI cannot determine which relationship to use.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;The fix:&lt;/strong&gt; That any two tables will connect only one active relationship. And put the extras on dormant, USE USERELATIONSHIP if you need them.&lt;/p&gt;
&lt;h3&gt;
  
  
  Circular Dependencies
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;What you’ll see:&lt;/strong&gt; Power BI does not want to form a relationship, and cautions against circular dependencies.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;What went wrong:&lt;/strong&gt; Your relationships build a loop — A connects to B, B connects to C, C connects back to A. Power BI doesn't know which way filters flow round the round.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;The fix:&lt;/strong&gt; Break the loop. Typically this involves cutting out a repetitive relation or adding the tables together so that no single path continues.&lt;/p&gt;
&lt;h3&gt;
  
  
  Many-to-Many Without a Bridge Table
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;What you’ll see:&lt;/strong&gt; Totals that look excessive or simply don’t add up.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;What went wrong:&lt;/strong&gt; Two tables are connected M:M because neither one has unique values in the join column. Filters spread in unclear ways and you ultimately double-count.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;The solution:&lt;/strong&gt; Add a bridge table (a junction or associative table) that places between the two. Every row in the bridge table is a single valid combination, making your M:M into two pure 1:M relations.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Before (problematic):
Students ──M:M──▶ Courses

After (correct):
Students ──1:M──▶ Enrollments ◀──M:1── Courses
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Problem 4: Bidirectional Filtering Throughout The Site
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;What you’ll see:&lt;/strong&gt; Weird filter behavior, sluggish performance, or filters “leaking” to parts of the model where they shouldn’t be.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;What went wrong:&lt;/strong&gt; Someone clicked “both” in cross-filter direction on a bunch of relationships, likely because one particular visual wasn’t working correctly.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;The solution:&lt;/strong&gt; Reset everything to single direction. Turn bidirectional back on only that way as long as you have a particular, tried reason.&lt;/p&gt;

&lt;h3&gt;
  
  
  Descriptive Columns Messed Up Into Fact Tables
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;What you will notice:&lt;/strong&gt; Expensive model that is slow to refresh and poorly compressed.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;What went wrong:&lt;/strong&gt; Customer names, product categories, addresses, and other descriptive data lie not in the dimension tables, but in the fact table.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;The solution:&lt;/strong&gt; Locate those descriptive columns and drag them out to the appropriate table of dimensions. In truth, key(s) (CustomerID, ProductID, DateKey) and measure(s) (Amount, Quantity, Cost), should never occupy your fact table.&lt;/p&gt;

&lt;h3&gt;
  
  
  Missing / Broken Date Table
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;What you’ll see:&lt;/strong&gt; Time intelligence functions — TOTALYTD, SAMEPERIODLASTYEAR, and the like — either don’t function at all or are nonsensical.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;How it went wrong:&lt;/strong&gt; You either don’t even have a date table, or you have one with gaps.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;The fix:&lt;/strong&gt; Create a Calendar table that covers all the dimensions of your data with no missing dates. Mark it as a Date Table in Power BI (select the table → Modeling ribbon → Mark as Date Table). Ensure it has a Date column containing distinctive, contiguous dates. This bewilders more people than you would think.&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 9: Putting It All Together — A Modeling Workflow
&lt;/h2&gt;

&lt;p&gt;When creating a new Power BI model, here is a technique I follow. Nothing radical—simply a series of activities that keeps me from finding myself in the dirt.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Figure out what the business needs.&lt;/strong&gt; What questions do stakeholders want answered? Revenue by region? Support tickets by priority? These questions give you what facts and dimensions you want.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2: Define your fact and dimension tables.&lt;/strong&gt; Facts are the events that are measurable. Dimensions are the describing context where things are located. Draw a line between the two.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3: Clean and transform in Power Query.&lt;/strong&gt; This is what joins do. Enrich your data, flatten any snowflaked dimensions, remove unnecessary columns, and ensure your data types are correct.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 4: Load into the model and get relationships formed.&lt;/strong&gt; Switch to Model View. Generate 1:M relationships to dimensions (one side) and facts (many side). Do not cross-filter the directional information on single unless you feel there is some good reason not to.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 5: Organize for usability.&lt;/strong&gt; Keep foreign key columns hidden from Report View (e.g., no one who’s building a report should get to see CustomerID). If you have too much to work with, use display folders. Add descriptions for key columns.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 6: Construct metrics and trial and fail.&lt;/strong&gt; Write your DAX, then actually test. Click through slicers. Verify numbers are logical. Don't assume — verify.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 7: Optimize.&lt;/strong&gt; Remove non-using columns. Check your model size. Profile query performance. Date table must be properly marked.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion. Data modeling isn’t the glamorous part of Power BI — no one will go ahead and screenshot your Model View and post it on LinkedIn. But it’s the part that decides whether everything else is successful. Here’s what I want you to keep in mind:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Joins&lt;/strong&gt; physically combine tables when they are loaded. They happen in Power Query. Use them for enrichment &amp;amp; cleanup. &lt;strong&gt;Relationships&lt;/strong&gt; are the logical connections in the model. They are how Power BI knows to filter one table based on selections in another. They’re the spine.
&lt;strong&gt;Star schemas&lt;/strong&gt; are what Power BI was constructed for. Fact table in the middle, denormalized dimensions around it. Use this unless you have a very good reason not to.
&lt;strong&gt;Cardinality&lt;/strong&gt; should be one-to-many whenever you can find it. If you are going many-to-many, then you probably want a bridge table. 
The &lt;strong&gt;cross-filter direction&lt;/strong&gt; should default to single
&lt;strong&gt;Bidirectional filtering&lt;/strong&gt; is powerful but dangerous — apply it like hot sauce, not ketchup. The role-playing dimensions solve the problems for the many dates associated with a single calendar. Select between shared calendar with USERELATIONSHIP or duplicate calendars depending on how much each date role is used in reports. The modeling error? Most of them boil down to the same thing: not spending enough time upfront separating facts from dimensions and building a clean star schema. Every minute you spend designing saves you hours of debugging later. ---&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>powerbi</category>
      <category>data</category>
    </item>
  </channel>
</rss>
