<?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: akello</title>
    <description>The latest articles on DEV Community by akello (@akello).</description>
    <link>https://dev.to/akello</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4124794%2Fbb830465-5e4a-4a57-8222-2670ad57f181.png</url>
      <title>DEV Community: akello</title>
      <link>https://dev.to/akello</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/akello"/>
    <language>en</language>
    <item>
      <title># Data Modelling, Relationships &amp; Joins in Power BI</title>
      <dc:creator>akello</dc:creator>
      <pubDate>Mon, 14 Sep 2026 15:51:29 +0000</pubDate>
      <link>https://dev.to/akello/-data-modelling-relationships-joins-in-power-bi-538p</link>
      <guid>https://dev.to/akello/-data-modelling-relationships-joins-in-power-bi-538p</guid>
      <description>&lt;h2&gt;
  
  
  1. Data Modelling
&lt;/h2&gt;

&lt;p&gt;A data model is the structural blueprint linking your tables so Power BI can filter, aggregate, and calculate correctly. A well-designed model improves DAX simplicity, report performance, scalability, and long-term maintainability.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Schema&lt;/th&gt;
&lt;th&gt;Structure&lt;/th&gt;
&lt;th&gt;Pros&lt;/th&gt;
&lt;th&gt;Cons&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;&lt;strong&gt;Flat Table&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;One wide table, all columns together&lt;/td&gt;
&lt;td&gt;Simple, no relationships needed&lt;/td&gt;
&lt;td&gt;High redundancy, slow on large data, hard to maintain&lt;/td&gt;
&lt;td&gt;Small, one-off datasets&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Star Schema&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;One fact table + denormalized dimensions directly connected&lt;/td&gt;
&lt;td&gt;Fast performance, simple DAX, easy to navigate&lt;/td&gt;
&lt;td&gt;Some data redundancy in dimensions&lt;/td&gt;
&lt;td&gt;Most standard BI reporting&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Snowflake Schema&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Dimensions normalized into sub-dimensions&lt;/td&gt;
&lt;td&gt;Less redundancy, smaller storage&lt;/td&gt;
&lt;td&gt;More joins/relationships, slower, complex DAX&lt;/td&gt;
&lt;td&gt;Very large, highly structured dimension hierarchies&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Flat Table:            Star Schema:                 Snowflake Schema:
[ One big table ]      DimCustomer   DimDate         DimCustomer─DimRegion
                            \         /               DimProduct─DimCategory
                          FactSales                        \      /
                            /        \                    FactSales
                     DimProduct   DimLocation                /
                                                        DimDate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  2. Fact vs Dimension Tables
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Fact tables&lt;/strong&gt; (e.g., &lt;code&gt;FactSales&lt;/code&gt;, &lt;code&gt;FactOrders&lt;/code&gt;) store measurable, numeric business events (SalesAmount, Quantity) plus foreign keys — defined at a specific &lt;strong&gt;grain&lt;/strong&gt; (e.g., one row per order line). &lt;strong&gt;Dimension tables&lt;/strong&gt; (&lt;code&gt;DimCustomer&lt;/code&gt;, &lt;code&gt;DimProduct&lt;/code&gt;, &lt;code&gt;DimDate&lt;/code&gt;, &lt;code&gt;DimLocation&lt;/code&gt;) store descriptive attributes used to filter and group facts. Example: &lt;code&gt;FactSales&lt;/code&gt; connects to &lt;code&gt;DimProduct&lt;/code&gt;, &lt;code&gt;DimCustomer&lt;/code&gt;, &lt;code&gt;DimDate&lt;/code&gt;, and &lt;code&gt;DimLocation&lt;/code&gt; — a classic star schema.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Relationships
&lt;/h2&gt;

&lt;p&gt;A relationship links tables via keys so filters flow correctly across the model.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;One-to-Many (1:*)&lt;/strong&gt; — e.g., &lt;code&gt;DimCustomer[CustomerID]&lt;/code&gt; → &lt;code&gt;FactSales[CustomerID]&lt;/code&gt;. Standard for fact-to-dimension links.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One-to-One (1:1)&lt;/strong&gt; — e.g., &lt;code&gt;Employee&lt;/code&gt; ↔ &lt;code&gt;EmployeeDetails&lt;/code&gt;. Rare; usually signals tables should be merged.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Many-to-Many (*:*)&lt;/strong&gt; — e.g., &lt;code&gt;Students&lt;/code&gt; ↔ &lt;code&gt;Courses&lt;/code&gt;. Use only when no unique key exists; avoid otherwise due to ambiguity risk.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Key concepts: &lt;strong&gt;Primary Key&lt;/strong&gt; (unique row identifier, e.g., &lt;code&gt;CustomerID&lt;/code&gt; in &lt;code&gt;DimCustomer&lt;/code&gt;), &lt;strong&gt;Foreign Key&lt;/strong&gt; (repeats in &lt;code&gt;FactSales&lt;/code&gt; to link back), &lt;strong&gt;Cardinality&lt;/strong&gt;, &lt;strong&gt;Referential Integrity&lt;/strong&gt; (every fact key must exist in its dimension), and &lt;strong&gt;Active vs Inactive&lt;/strong&gt; relationships (only one active path between two tables at a time; inactive paths need &lt;code&gt;USERELATIONSHIP&lt;/code&gt; in DAX).&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Filter Direction
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Single-direction&lt;/strong&gt;: filters flow dimension → fact (default, recommended). Selecting a product in &lt;code&gt;DimProduct&lt;/code&gt; filters &lt;code&gt;FactSales&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bidirectional&lt;/strong&gt;: filters flow both ways — useful for many-to-many bridges, but risks &lt;strong&gt;ambiguous filter paths&lt;/strong&gt; and unnecessary model complexity. Use sparingly.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  5. Joins in Power Query (Merge)
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Join Type&lt;/th&gt;
&lt;th&gt;Keeps&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Left Outer&lt;/td&gt;
&lt;td&gt;All of left table + matches from right&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Right Outer&lt;/td&gt;
&lt;td&gt;All of right table + matches from left&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Full Outer&lt;/td&gt;
&lt;td&gt;All rows from both tables&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Inner&lt;/td&gt;
&lt;td&gt;Only matching rows from both&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Left Anti&lt;/td&gt;
&lt;td&gt;Left rows with &lt;strong&gt;no&lt;/strong&gt; match in right&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Right Anti&lt;/td&gt;
&lt;td&gt;Right rows with &lt;strong&gt;no&lt;/strong&gt; match in left&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Example: &lt;code&gt;Customers&lt;/code&gt; ⋈ &lt;code&gt;Orders&lt;/code&gt; — Inner join returns only customers who placed orders; Left Anti returns customers who never ordered.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Power Query Joins vs Power BI Relationships
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;Merge&lt;/strong&gt; in Power Query happens at the ETL stage and physically combines columns into one new table. A &lt;strong&gt;Relationship&lt;/strong&gt; happens at the model stage and links tables logically without duplicating data. Use merges sparingly (only when you truly need combined columns) — excessive merging flattens the model, increases redundancy, and reduces scalability. Keeping facts and dimensions separate, linked by relationships, preserves a clean, performant star schema.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Recommendation
&lt;/h2&gt;

&lt;p&gt;For most BI projects, a &lt;strong&gt;Star Schema&lt;/strong&gt; is preferable: it balances performance, simple DAX, redundancy, and readability far better than a flat table (too redundant/slow at scale) or snowflake (unnecessary join complexity for typical reporting needs). Implement &lt;strong&gt;one-to-many relationships&lt;/strong&gt; from dimensions to the fact table, keep filters &lt;strong&gt;single-direction&lt;/strong&gt; by default, and reserve bidirectional or many-to-many relationships for specific bridging scenarios only.&lt;br&gt;
PowerBI_Data_Modelling_Article.md&lt;br&gt;
Displaying PowerBI_Data_Modelling_Article.md.&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>data</category>
      <category>database</category>
      <category>performance</category>
    </item>
  </channel>
</rss>
