<?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: Bonny Mark</title>
    <description>The latest articles on DEV Community by Bonny Mark (@kbonymark).</description>
    <link>https://dev.to/kbonymark</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%2F3958039%2F6ba65c9b-d447-4a5d-a844-08afce740723.jpg</url>
      <title>DEV Community: Bonny Mark</title>
      <link>https://dev.to/kbonymark</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kbonymark"/>
    <language>en</language>
    <item>
      <title>From Raw Data to Business Decisions: Building a Power BI Solution for JCars Logistics</title>
      <dc:creator>Bonny Mark</dc:creator>
      <pubDate>Sun, 27 Sep 2026 16:08:02 +0000</pubDate>
      <link>https://dev.to/kbonymark/from-raw-data-to-business-decisions-building-a-power-bi-solution-for-jcars-logistics-865</link>
      <guid>https://dev.to/kbonymark/from-raw-data-to-business-decisions-building-a-power-bi-solution-for-jcars-logistics-865</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;JCars Logistics imports, sells and delivers vehicles across Kenya. Management wanted a report that could answer simple questions like: how is the business doing, where is it making money, where is it losing money, and what needs a closer look? All I got was one raw CSV file, nothing else.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F45zr7montkcit31wi2nb.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F45zr7montkcit31wi2nb.png" alt="The raw CSV file, before any cleaning" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding the data before touching it
&lt;/h2&gt;

&lt;p&gt;I worked out what the data actually represented. One row equals one order line for a vehicle sale (sometimes more than one unit, since there's a Units Sold field). The 34 columns split into two kinds: descriptions of the customer, vehicle, branch and so on, and numbers like price, cost, fees and ratings. Two fields looked like they could be unique IDs, Order ID and Customer Name, but I didn't trust either one until I'd checked. Good thing I did.&lt;/p&gt;

&lt;h2&gt;
  
  
  Auditing the data
&lt;/h2&gt;

&lt;p&gt;I didn't assume any field was correct. I loaded everything into a dataframe and ran checks for nulls, duplicates, mismatched formulas and impossible logic. I found a lot more than the ten issues the brief asked for. The most important ones:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. The Revenue column was completely broken.&lt;/strong&gt; This was the single biggest find, and it shaped everything I did after it. I checked Revenue against Units Sold times Unit Selling Price and the ratio wasn't random. It was always exactly 455 divided by Units Sold, and 455 happens to be the total number of units sold across the whole dataset. Somewhere along the line, whoever built this field multiplied Unit Selling Price by the sum of every unit ever sold, instead of just that row's own quantity. It's the kind of mistake you get from an Excel formula that locked onto the wrong cell range. I dropped the column entirely and used Revenue Recorded instead, which I checked separately and found actually lines up with Units Sold times Unit Selling Price times one minus Discount, plus Delivery Fee.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Order IDs weren't actually unique.&lt;/strong&gt; There were five different formats floating around (ORD, CAR, LC, LCL, LCL-), a bunch of rows just said "UNKNOWN", and a few IDs were duplicated across totally different orders. So I couldn't count orders using a distinct count on Order ID. I made that mistake myself at first in my DAX before I caught it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Some prices were way off.&lt;/strong&gt; A Toyota Land Cruiser was listed at 122.4 million shillings when similar ones sold for 12 to 14 million. A VW Tiguan was listed at 47 million against a normal range of 4 to 5 million. Both look like an extra zero got typed in by mistake.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Delivery dates before order dates.&lt;/strong&gt; 18 orders had a delivery date earlier than the order date, which obviously can't happen.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. A lot of missing values.&lt;/strong&gt; Discount, Delivery Date, Logistics Cost, Customer Rating and Vehicle Year all had a meaningful chunk of nulls. I needed a clear policy for these instead of just filling them in and hoping for the best.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. Some very large discounts.&lt;/strong&gt; A handful of orders had discounts up to 50%, way outside the normal 0 to 15% range.&lt;/p&gt;

&lt;p&gt;For every one of these I made a decision instead of quietly fixing things behind the scenes. For the price outliers I kept the records and flagged them rather than deleting them, since I had no way to confirm what the "correct" value should have been. For category fields I standardized spelling. For currency, I assumed Kenya Shillings whenever no currency was shown, which is what the brief asked for.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sorting out the currency
&lt;/h2&gt;

&lt;p&gt;The dataset mixed KES with figures in USD, EUR and ZAR, using symbols, prefixes and "M" suffixes in no consistent way. In Power Query I built a function that detects which currency each value is in, then converts it using a rate table by currency and year.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Currency&lt;/th&gt;
&lt;th&gt;Rate to KES&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;USD&lt;/td&gt;
&lt;td&gt;130&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;EUR&lt;/td&gt;
&lt;td&gt;150&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ZAR&lt;/td&gt;
&lt;td&gt;7.5&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;These rates aren't official exchange rates from some external source. I worked them out from the numbers already in the dataset, picking rates that turn the foreign figures into round KES amounts. I applied them the same way across every money column and wrote this down as an assumption, since the brief says there's no single correct rate they're looking for.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cleaning it up in Power Query
&lt;/h2&gt;

&lt;p&gt;I didn't just run a standard cleaning routine. Every step traces back to something the audit found. A Standardize function maps dozens of spelling variations (corp, Corporate, govt, Government) to one clean category per field. A date parser tries several formats in order, since the file had at least six different date layouts mixed together. Functions for discount and rating enforce sensible limits and turn impossible values, like a 120% discount, into nulls rather than guessing what they should have been.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6ls8aoorwvexy3pj6tyi.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6ls8aoorwvexy3pj6tyi.png" alt="The Jcars_data Power Query steps in the Advanced Editor" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I built a star schema
&lt;/h2&gt;

&lt;p&gt;The original file was one big flat table with every field repeated on every row. I broke it into a star schema instead: one fact table holding the keys and numbers, and seven dimension tables for Branch, Geography, Sales Rep, Lead Source, Vehicle, Customer and Date. This stops branch names and vehicle details from being repeated hundreds of times, lets me do proper time comparisons with a real date table, and keeps the filtering behavior predictable.&lt;/p&gt;

&lt;p&gt;Here are the dimension tables once they were built:&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftct5p67l7y8ictd9sp2b.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftct5p67l7y8ictd9sp2b.png" alt="Dim_Geography" width="800" height="450"&gt;&lt;/a&gt;&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fphit9duu0aw82v5qh0zs.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fphit9duu0aw82v5qh0zs.png" alt="Dim_SalesRep" width="800" height="450"&gt;&lt;/a&gt;&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fl437f5n008abi7ooblk8.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fl437f5n008abi7ooblk8.png" alt="Dim_Vehicle" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And the model taking shape, as I worked through wiring up the relationships correctly:&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcuezuof0tvo028widf5k.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcuezuof0tvo028widf5k.png" alt="Model view, early stage" width="800" height="450"&gt;&lt;/a&gt;&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1mewehtp4wyqzm53c83q.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1mewehtp4wyqzm53c83q.png" alt="Model view, mid-build" width="800" height="450"&gt;&lt;/a&gt;&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9gpwnqm11ouzzuj8rvfv.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9gpwnqm11ouzzuj8rvfv.png" alt="Model view, after fixing the duplicate fact table issue" width="800" height="450"&gt;&lt;/a&gt;&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8g2xckcgknn219g3jpzp.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8g2xckcgknn219g3jpzp.png" alt="Model view, adding the date relationships" width="800" height="450"&gt;&lt;/a&gt;&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fa9dxzo2zxg77rrfyu9ic.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fa9dxzo2zxg77rrfyu9ic.png" alt="The finished model, 8 active relationships" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I'm going to be honest about a couple of mistakes I made while building this, because I only found them by actually testing the model, not by assuming it was right.&lt;/p&gt;

&lt;p&gt;I ended up with two fact tables loaded at once, the original raw query and my new Facts table, both linked to the same dimensions. Power BI only allows one active relationship between two tables, so it quietly deactivated the new table's links to Branch, Geography and Sales Rep. Everything still looked connected, but filtering by branch or city wouldn't actually have worked on the new measures. I fixed it by turning off "Enable load" on the original raw query, so it exists purely as a source step for the other queries, never as its own table in the model.&lt;/p&gt;

&lt;p&gt;I also had a bug in how I matched rows during the merges. I was checking "if the lookup result equals null" to catch rows with no match, but a failed merge in Power Query returns an empty table, not null. So any row with a genuinely blank join key, like a missing Vehicle Year, threw an error instead of just getting a null key. Twelve rows failed to load because of this. Switching the check to "is the table empty" instead of "does it equal null" fixed all twelve at once.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fm06l3q1cothvv1hghq4g.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fm06l3q1cothvv1hghq4g.png" alt="The " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I also broke one query completely by renaming a step and forgetting that a later step still referenced the old name. Power Query gave me an error saying the import didn't match any exports, which is its way of saying "this step no longer exists." That one taught me to check every step downstream before renaming anything.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmjhi4xsqoj6undg458hn.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmjhi4xsqoj6undg458hn.png" alt="The " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For dates, I made Order Date the active relationship to the date table, and kept Delivery Date as a second, inactive relationship that I switch on with USERELATIONSHIP whenever I need to look at something from the delivery side instead.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpg83yd8745p8ktlqzo3s.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpg83yd8745p8ktlqzo3s.png" alt="The final relationship diagram" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The measures and calculated columns
&lt;/h2&gt;

&lt;p&gt;I tried to make sure every measure existed for a reason, not just to pad out the model. Some of the core ones:&lt;/p&gt;

&lt;p&gt;Dax:&lt;/p&gt;

&lt;p&gt;Total Revenue = SUM('Facts table'[Revenue Recorded])&lt;br&gt;
Total Orders = COUNTROWS('Facts table')&lt;br&gt;
Gross Profit = [Total Revenue] - [Total Cost]&lt;br&gt;
Gross Profit Margin % = DIVIDE([Gross Profit], [Total Revenue])&lt;/p&gt;

&lt;p&gt;Completed Revenue =&lt;br&gt;
CALCULATE([Total Revenue],&lt;br&gt;
    'Facts table'[Payment Status] &amp;lt;&amp;gt; "Cancelled",&lt;br&gt;
    'Facts table'[Payment Status] &amp;lt;&amp;gt; "Refunded")&lt;/p&gt;

&lt;p&gt;Revenue YoY % = DIVIDE([Total Revenue] - [Revenue PY], [Revenue PY])&lt;/p&gt;

&lt;p&gt;One more bug worth mentioning. My first version of Total Orders used a distinct count on Order ID, which undercounted by 21 orders, because Order ID isn't actually unique (remember the UNKNOWN rows and the duplicates). Since each row in the fact table already represents one order, a plain row count was the right fix. Once I changed it, everything downstream that depended on it, like Return Count and Completed Orders, corrected itself automatically.&lt;/p&gt;

&lt;p&gt;I also added a few calculated columns to make investigation easier without needing a separate measure for every possible slice: Discount Bracket, Rating Bracket, Price to Cost Ratio, Delivery Lag Days, and a Flag for Investigation column that catches any order with a strange price ratio, a very large discount, or a negative delivery lag. These are the same problems the audit found, just now something a manager can actually filter and click on in the report instead of something buried in my analysis notes.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F427ly0xnto40xlm56ndd.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F427ly0xnto40xlm56ndd.png" alt="The finished Facts table, 276 rows" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Designing the Executive Dashboard
&lt;/h2&gt;

&lt;p&gt;The first page is meant to answer "how is the business doing" in one glance. It has a title, six KPI cards, all built off "Completed" measures so they're consistent with each other (Completed Revenue, Completed Gross Profit, Gross Profit Margin %, Units Sold, Completed Orders, and Logistics Cost % of Revenue). That last card has conditional formatting, turning red once logistics cost passes 2% of revenue, which is my simple way of flagging something that needs attention rather than just displaying a number. Below that sits a monthly trend chart and two comparison charts, one for branch and one for car make. A year slicer sits next to the title.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsm57h9t86jsmp5urejmv.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsm57h9t86jsmp5urejmv.png" alt="The finished Executive Dashboard" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The detail pages
&lt;/h2&gt;

&lt;p&gt;I grouped related topics into pages instead of making one page per business question, since the brief specifically says a single well-designed page can answer several questions at once. I ended up with these five pages:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sales, Vehicle and Profitability&lt;/strong&gt;&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fugr3jvum2pnotrfiecd3.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fugr3jvum2pnotrfiecd3.png" alt="Sales, Vehicle and Profitability page" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Branch, Region and Sales Channel Performance&lt;/strong&gt;&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Forkgnavw9tr9gx6pej5p.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Forkgnavw9tr9gx6pej5p.png" alt="Branch, Region and Sales Channel Performance page" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Payments, Delivery and Logistics&lt;/strong&gt;&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7wws7exle3rag6hc9b4i.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7wws7exle3rag6hc9b4i.png" alt="Payments, Delivery and Logistics page" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Customers, Discounts and Investigation&lt;/strong&gt;&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxqwik23vix6re0pezkxo.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxqwik23vix6re0pezkxo.png" alt="Customers, Discounts and Investigation page" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There's also a hidden Order Investigation page that you only reach through drill-through:&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fegsy8lud9s8qffd8jrc2.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fegsy8lud9s8qffd8jrc2.png" alt="The hidden Order Investigation page" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Making it interactive
&lt;/h2&gt;

&lt;p&gt;There's a Year slicer on the Executive Dashboard. Right-clicking a branch bar anywhere in the report opens the hidden Order Investigation page, filtered to that branch's flagged orders, showing Order ID, Branch, Car Make, Car Model, Sales Rep, Payment Status, Discount, Price to Cost Ratio, Delivery Lag Days and Returned. Normal cross-filtering between visuals works throughout the report too.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Friv8pubd7cig9qpyb55c.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Friv8pubd7cig9qpyb55c.png" alt="Right-clicking a branch bar to drill through to Order Investigation" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I found
&lt;/h2&gt;

&lt;p&gt;The Revenue field, if I'd used it as it was, would have overstated total revenue by about 455 times. That's a good reminder that a field's name tells you nothing about whether the value in it is correct. Every number needs checking before you trust it.&lt;/p&gt;

&lt;p&gt;Nairobi HQ has the lowest branch revenue in the dataset, despite being in the capital. That's worth looking into properly, whether it's staffing, stock levels or something about local demand, rather than guessing.&lt;/p&gt;

&lt;p&gt;Pending and Partially Paid orders together make up around 40% of both order volume and revenue value. That's a lot of recorded sales that hasn't actually turned into cash yet, which matters more for cash flow than the headline revenue figure suggests.&lt;/p&gt;

&lt;p&gt;Bigger discounts don't lead to bigger deals. Average order value is actually lower at 15% plus discount than it is at 0 to 5%. That suggests discounting might be reactive rather than a deliberate strategy.&lt;/p&gt;

&lt;p&gt;Trucks and Sedans are the only vehicle types with negative or near-zero profit margin. SUVs carry most of the volume and most of the profit. That's a solid, specific thing to act on for pricing and stock decisions.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'd recommend
&lt;/h2&gt;

&lt;p&gt;Look into why Nairobi HQ is underperforming specifically. Compare its lead source mix, staffing and stock availability against Kakamega and Thika Yard, the two strongest branches, before assuming you know the reason.&lt;/p&gt;

&lt;p&gt;Review how Trucks and Sedans are priced. Since they're the only vehicle types losing money on average, either the cost side or the pricing side needs a second look, rather than a blanket instruction to "cut costs."&lt;/p&gt;

&lt;p&gt;Put a tighter limit on discounts above 15%. Since bigger discounts don't seem to be buying bigger deals, someone giving away that much margin without a clear payoff is worth reviewing, whether that's a policy gap or a few individual exceptions.&lt;/p&gt;

&lt;p&gt;I've kept these as things worth investigating rather than proven facts. Correlation isn't causation, and the brief is clear that it doesn't want claims the data can't actually back up.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I struggled with and what I took away from it
&lt;/h2&gt;

&lt;p&gt;The bugs I described above were the most useful part of the whole project. Every single one of them looked fine at first glance, the model appeared connected, the query loaded without complaint in preview, and only broke once I actually tested it properly: filtering with a slicer, loading the full 276 rows instead of a sample, or renaming something without checking what depended on it. The main thing I'm taking away from this is that a report that builds without an error showing isn't the same thing as a report that's correct. The only way to know the difference is to actually try to break it before you call it finished.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Repository: [link to GitHub repo]&lt;/em&gt;&lt;/p&gt;

</description>
      <category>powerbi</category>
      <category>dataanalytics</category>
      <category>dax</category>
      <category>businessintelligence</category>
    </item>
    <item>
      <title>Data Modelling, Relationships &amp; Joins in Power BI.</title>
      <dc:creator>Bonny Mark</dc:creator>
      <pubDate>Fri, 11 Sep 2026 11:17:12 +0000</pubDate>
      <link>https://dev.to/kbonymark/data-modelling-relationships-joins-in-power-bi-ojf</link>
      <guid>https://dev.to/kbonymark/data-modelling-relationships-joins-in-power-bi-ojf</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Power BI is used to analyse data and turn it into useful reports and dashboards. For the reports to produce accurate and meaningful results, the underlying data needs to be organized properly. This is where data modelling, relationships, and joins become important.&lt;/p&gt;

&lt;p&gt;A good data model makes it easier to create DAX calculations, improve report performance, manage large datasets, and maintain a Power BI project as it grows. This article explains the main approaches to data modelling, the role of fact and dimension tables, relationships and filter directions, and the different types of joins available in Power Query.&lt;/p&gt;

&lt;h2&gt;
  
  
  Data Modelling in Power BI
&lt;/h2&gt;

&lt;p&gt;Data modelling in Power BI is the process of organizing tables and defining how they are connected. A data model determines how information from different tables works together when creating reports, calculations, filters, and visualizations.&lt;/p&gt;

&lt;p&gt;For example, a retail business may store customers, products, dates, locations, and sales transactions in separate tables. These tables can be connected using common fields such as CustomerID, ProductID, and DateKey.&lt;/p&gt;

&lt;p&gt;A simple model can be represented as follows:&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flzrukk66vd2sfra3nbiw.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flzrukk66vd2sfra3nbiw.png" alt=" " width="483" height="354"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A well-designed model can make DAX calculations easier, improve query performance, reduce unnecessary duplication, and make the report easier to maintain.&lt;/p&gt;

&lt;p&gt;There are three common ways of organizing data for analysis: &lt;strong&gt;flat tables&lt;/strong&gt;, &lt;strong&gt;star schemas&lt;/strong&gt;, and &lt;strong&gt;snowflake schemas.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Flat Table
&lt;/h2&gt;

&lt;p&gt;A flat table stores most of the required information in a single table.&lt;/p&gt;

&lt;p&gt;For example:&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7fsbndn3fcqy6n7u454q.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7fsbndn3fcqy6n7u454q.png" alt=" " width="800" height="290"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Information is often repeated. If examples one makes 1,000 purchases, his name, region, and other customer information may appear many times. This creates data redundancy and can increase the size of the model.&lt;/p&gt;

&lt;h3&gt;
  
  
  Advantages
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Easy to understand.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Simple to create.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use for small datasets.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Requires fewer relationships.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Suitable for simple reports.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Disadvanatges
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Creates repeated information.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Can become very large.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;More difficult to maintain.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Can make the model less flexible.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Not ideal for complex business intelligence solutions.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A flat table can be appropriate for a small report where the data is already prepared and there are relatively few records.&lt;/p&gt;

&lt;h2&gt;
  
  
  Star Schema
&lt;/h2&gt;

&lt;p&gt;A star schema separates the main business events from the descriptive information used to analyse those events.&lt;/p&gt;

&lt;p&gt;The centre of the model is normally a fact table, while dimension tables surround it.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fixuc1nm3wrksf0yyuifx.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fixuc1nm3wrksf0yyuifx.png" alt=" " width="798" height="518"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Advantages
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Clear and easy to understand.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Usually requires fewer relationships than a highly normalized model.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Makes filtering and reporting straightforward.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Makes DAX calculations easier to manage.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Reduces unnecessary duplication.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Scales well for business intelligence projects.&lt;/p&gt;
&lt;h3&gt;
  
  
  Disadvantages
&lt;/h3&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Requires proper planning.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;More tables are involved than in a flat table.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The designer needs to understand keys and relationships.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Poorly designed dimensions can still cause problems.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The star schema is appropriate for sales systems, financial reporting, inventory systems, customer analytics, and many other business intelligence applications.&lt;/p&gt;

&lt;p&gt;It is also a good choice when several reports need to use the same customers, products, dates, or locations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Snowflake Schema
&lt;/h2&gt;

&lt;p&gt;A snowflake schema is similar to a star schema, but some dimension tables are divided into additional related tables.&lt;/p&gt;

&lt;p&gt;For example, instead of storing a product's category directly in DimProduct, category information can be placed in a separate DimCategory table.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9734hf1o1xxssdgyjbp6.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9734hf1o1xxssdgyjbp6.png" alt=" " width="799" height="559"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Advantages
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Reduces some data duplication.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Can represent complex hierarchies.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Can be useful when dimensions contain large amounts of related information.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Can fit well with highly normalized source systems.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Disadvantages
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Creates more tables.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Requires more relationships.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Makes the model harder to understand.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Can make filtering more complicated.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Can increase model maintenance requirements.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A snowflake schema may be useful when the additional separation provides a genuine benefit. However, unnecessarily splitting dimensions can make a Power BI model more complicated than it needs to be.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fact Tables and Dimension Tables
&lt;/h2&gt;

&lt;p&gt;Fact and dimension tables are the main building blocks of a star schema&lt;/p&gt;

&lt;p&gt;A fact table stores measurable business events.&lt;/p&gt;

&lt;p&gt;Examples include:FactSales,FactOrders,FactTransactions,FactInventory &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dimension Tables&lt;/strong&gt; contain descriptive attributes that provide context for the facts.&lt;br&gt;
Common dimensions include:DimCustomer,DimProduct,DimDate,DimLocation.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Foo53l09txj3d015m88z1.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Foo53l09txj3d015m88z1.png" alt=" " width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Practical Fact-Dimension Example
&lt;/h2&gt;

&lt;p&gt;Consider an online retail company.&lt;/p&gt;

&lt;p&gt;The central table is:&lt;/p&gt;

&lt;p&gt;FactSales&lt;/p&gt;

&lt;p&gt;It records each sale.&lt;/p&gt;

&lt;p&gt;It connects to:&lt;/p&gt;

&lt;p&gt;DimCustomer — who purchased?&lt;br&gt;
DimProduct — what was purchased?&lt;br&gt;
DimDate — when was it purchased?&lt;br&gt;
DimLocation — where was the sale made?&lt;/p&gt;

&lt;p&gt;The model can therefore answer questions such as:&lt;/p&gt;

&lt;p&gt;What were total sales?&lt;br&gt;
Which product generated the most revenue?&lt;br&gt;
Which county generated the highest sales?&lt;br&gt;
How much did each customer spend?&lt;br&gt;
What were sales during 2026?&lt;br&gt;
Which product category performed best?&lt;/p&gt;

&lt;p&gt;This is the main strength of the star schema: dimensions provide the context while the fact table provides the measurable events.&lt;/p&gt;

&lt;h2&gt;
  
  
  Relationships in Power BI
&lt;/h2&gt;

&lt;p&gt;A relationship connects two tables using related columns.&lt;/p&gt;

&lt;p&gt;Relationships are necessary because business information is usually stored in multiple tables rather than one large table.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;p&gt;DimCustomer[CustomerID]&lt;/p&gt;

&lt;p&gt;can be connected to:&lt;/p&gt;

&lt;p&gt;FactSales[CustomerID]&lt;/p&gt;

&lt;p&gt;When a customer is selected in a report, the relationship allows the selection to affect the relevant sales records. Power BI relationships propagate filters between connected tables.&lt;/p&gt;

&lt;h3&gt;
  
  
  Relationship Cardinality
&lt;/h3&gt;

&lt;p&gt;Cardinality describes how values in one table relate to values in another.&lt;/p&gt;

&lt;p&gt;Power BI supports four main cardinality types:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;One-to-One 1:1&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;One-to-many 1:*&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Many-to-many &lt;em&gt;:&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7ea125mn8aanxltbipof.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7ea125mn8aanxltbipof.png" alt=" " width="477" height="643"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One-to-One Relationship (1:*)&lt;/strong&gt;&lt;br&gt;
A one-to-one relationship means each value in one table corresponds to only one value in another table.&lt;/p&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;p&gt;Product SkU may appear once in both:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Product table&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Productcategory table&lt;/p&gt;&lt;/li&gt;
&lt;/ul&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4ihvwjn513cjiklmskul.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4ihvwjn513cjiklmskul.png" alt=" " width="800" height="415"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When to use it&lt;/p&gt;

&lt;p&gt;It can be useful when information belonging to one entity has been deliberately separated into two tables.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One-to-Many Relationship (1:*)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is the most common relationship in a star schema.&lt;/p&gt;

&lt;p&gt;Example:&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpogp3vqjguk1qrh775so.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpogp3vqjguk1qrh775so.png" alt=" " width="640" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;DimCustomer[CustomerID] 1 → * FactSales[CustomerID]&lt;/p&gt;

&lt;p&gt;A customer appears once in the customer dimension but can appear many times in the sales table.&lt;/p&gt;

&lt;p&gt;When to use it&lt;/p&gt;

&lt;p&gt;Use it when one record in the first table can be associated with multiple records in the second table.&lt;/p&gt;

&lt;p&gt;This is normally the preferred relationship between dimensions and fact tables.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Many-to-Many Relationship (:)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A many-to-many relationship occurs when values in both tables can occur multiple times.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;p&gt;One student can belong to several courses.&lt;br&gt;
One course can have many students.&lt;/p&gt;

&lt;p&gt;Direct many-to-many relationships can be useful, but they can also make filter propagation harder to understand.&lt;/p&gt;

&lt;p&gt;A bridge table can provide a clearer solution.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;p&gt;DimStudent&lt;/p&gt;

&lt;p&gt;↓&lt;/p&gt;

&lt;p&gt;StudentCourse&lt;/p&gt;

&lt;p&gt;↓&lt;/p&gt;

&lt;p&gt;DimCourse&lt;/p&gt;

&lt;p&gt;The bridge table records the combinations between students and courses.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyzdbcnd59bdrf9p4hu98.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyzdbcnd59bdrf9p4hu98.png" alt=" " width="452" height="442"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Keys and Referential Integrity
&lt;/h3&gt;

&lt;p&gt;Relationships normally depend on matching key columns.&lt;/p&gt;

&lt;h3&gt;
  
  
  Primary Key
&lt;/h3&gt;

&lt;p&gt;A primary key uniquely identifies a record.&lt;/p&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;p&gt;DimCustomer[CustomerID]&lt;/p&gt;

&lt;p&gt;could contain:&lt;/p&gt;

&lt;p&gt;C001&lt;br&gt;
C002&lt;br&gt;
C003&lt;/p&gt;

&lt;p&gt;Each value appears only once.&lt;/p&gt;

&lt;h3&gt;
  
  
  Foreign Key
&lt;/h3&gt;

&lt;p&gt;A foreign key refers to a record in another table.&lt;/p&gt;

&lt;p&gt;In FactSales, the CustomerID may appear repeatedly:&lt;/p&gt;

&lt;p&gt;C001&lt;br&gt;
C001&lt;br&gt;
C002&lt;br&gt;
C001&lt;/p&gt;

&lt;p&gt;This is because one customer can make many purchases.&lt;/p&gt;

&lt;h3&gt;
  
  
  Referential Integrity
&lt;/h3&gt;

&lt;p&gt;Referential integrity means that foreign-key values should correctly correspond to valid records on the related dimension side.&lt;/p&gt;

&lt;p&gt;For example, if FactSales contains CustomerID C001, the corresponding customer should normally exist in DimCustomer.&lt;/p&gt;

&lt;p&gt;If the dimension side is supposed to be the "one" side of a relationship, its values must be unique. Power BI can detect relationship problems when the supposed one-side column contains duplicates.&lt;/p&gt;

&lt;h3&gt;
  
  
  Active and Inactive Relationships
&lt;/h3&gt;

&lt;p&gt;Power BI relationships can be active or inactive.&lt;/p&gt;

&lt;p&gt;An active relationship is the default relationship used for filtering and reporting.&lt;/p&gt;

&lt;p&gt;Inactive relationships can be useful when two tables have multiple possible relationships.&lt;/p&gt;

&lt;p&gt;For example, a Sales table may contain:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;OrderDate&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;ShipDate&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;DeliveryDate&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All three dates could relate to a Date table, but normally only one relationship may be active at a time for a particular role.&lt;/p&gt;

&lt;p&gt;Inactive relationships can then be activated in specific DAX calculations when required.&lt;/p&gt;

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

&lt;p&gt;Filter direction determines how filters move between related tables.&lt;/p&gt;

&lt;h3&gt;
  
  
  Single Direction
&lt;/h3&gt;

&lt;p&gt;In a typical star schema:&lt;/p&gt;

&lt;p&gt;DimProduct → FactSales&lt;/p&gt;

&lt;p&gt;A product selection filters the sales table.&lt;/p&gt;

&lt;p&gt;For example, selecting:&lt;/p&gt;

&lt;p&gt;Product Category = Electronics&lt;/p&gt;

&lt;p&gt;can filter the sales records belonging to Electronics products.&lt;/p&gt;

&lt;p&gt;Single-direction filtering is commonly used because it makes the filter path easier to understand.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bidirectional Filtering
&lt;/h2&gt;

&lt;p&gt;Bidirectional filtering allows filters to travel in both directions.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;p&gt;DimProduct ↔ FactSales&lt;/p&gt;

&lt;p&gt;A filter can travel from the product table to sales and, depending on the model, from sales back toward the product table.&lt;/p&gt;

&lt;p&gt;Bidirectional filtering can solve certain modelling problems, but excessive use can create:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Ambiguous filter paths&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Unexpected results&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;More complex models&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Potential performance problems&lt;/p&gt;&lt;/li&gt;
&lt;/ul&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxxs5g07sefn6vv84k3zx.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxxs5g07sefn6vv84k3zx.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkgc5hakjz67i1hd10hsm.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkgc5hakjz67i1hd10hsm.png" alt=" " width="624" height="444"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Power Query Joins
&lt;/h2&gt;

&lt;p&gt;Power Query joins are used during the data preparation stage.&lt;/p&gt;

&lt;p&gt;In Power Query, a Merge Queries operation combines information from two queries using matching columns.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;strong&gt;Sales&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;CountryID   Units&lt;br&gt;
1            20&lt;br&gt;&lt;br&gt;
2            15&lt;br&gt;
3           30&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Countries&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;ID  Country&lt;br&gt;
1   Kenya&lt;br&gt;
2   Uganda&lt;br&gt;
3   Tanzania&lt;/p&gt;

&lt;p&gt;The tables can be merged using:&lt;/p&gt;

&lt;p&gt;Sales[CountryID] = Countries[ID]&lt;/p&gt;

&lt;p&gt;After the merge, the Country column can be expanded into the Sales query.&lt;/p&gt;

&lt;p&gt;Power Query supports several join types, including Left Outer, Right Outer, Full Outer, Inner, Left Anti, and Right Anti.&lt;/p&gt;

&lt;h3&gt;
  
  
  Left Outer Join
&lt;/h3&gt;

&lt;p&gt;A Left Outer Join keeps every row from the left table and adds matching information from the right table.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sales:&lt;/strong&gt; This table includes the fields Date, CountryID, and Units. CountryID is a whole number value that represents the unique identifier from the Countries table.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgxtoyxlqbk5fmug6x684.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgxtoyxlqbk5fmug6x684.png" alt=" " width="408" height="168"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Countries&lt;/strong&gt;: This table is a reference table with the fields ID and Country. The ID field represents the unique identifier for each record.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvpmmt4lvp3ghtn1tqdok.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvpmmt4lvp3ghtn1tqdok.png" alt=" " width="269" height="137"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;n this example, you merge both tables, with the Sales table as the left table and the Countries table as the right one. The join is made between the following columns.&lt;/p&gt;

&lt;p&gt;Field from the Sales table  Field from the Countries table&lt;br&gt;
CountryID                        ID&lt;/p&gt;

&lt;p&gt;The goal is to create a table like the following, where the name of the country appears as a new Country column in the Sales table as long as the CountryID exists in the Countries table. If there are no matches between the left and right tables, a null value is the result of the merge for that row. In the following image, this null value is shown to be the case for CountryID 4, which was brought in from the Sales table.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8dfr97wxu67canvd160h.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8dfr97wxu67canvd160h.png" alt=" " width="540" height="171"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To do a left outer join:&lt;/p&gt;

&lt;p&gt;Select the Sales query, and then select Merge queries.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;In the Merge dialog box, under Right table for merge, select Countries.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In the Sales table, select the CountryID column.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In the Countries table, select the ID column.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In the Join kind section, select Left outer.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Select OK.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyy8engud0c1207fm4giz.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyy8engud0c1207fm4giz.png" alt=" " width="800" height="892"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;From the newly created Countries column, expand the Country field. Don't select the Use original column name as prefix check box.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcrghi438f5jdxc4wzlcp.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcrghi438f5jdxc4wzlcp.png" alt=" " width="800" height="412"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After performing this operation, you create a table that looks like the following image.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fi229iusxa2vmbx5keweg.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fi229iusxa2vmbx5keweg.png" alt=" " width="540" height="171"&gt;&lt;/a&gt;&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fal0njnir0yx1otu5n3wn.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fal0njnir0yx1otu5n3wn.png" alt=" " width="464" height="379"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Right Outer Join
&lt;/h2&gt;

&lt;p&gt;One of the join kinds available in the Merge dialog box in Power Query is a right outer join, which keeps all the rows from the right table and brings in any matching rows from the left table&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3eqrbxsrrmth3ey1spcq.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3eqrbxsrrmth3ey1spcq.png" alt=" " width="464" height="305"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Examples :&lt;br&gt;
&lt;strong&gt;Sales&lt;/strong&gt;: This table includes the fields Date, CountryID, and Units. The CountryID is a whole number value that represents the unique identifier from the Countries table.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fi169d9szfswqw07zzevq.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fi169d9szfswqw07zzevq.png" alt=" " width="414" height="174"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Countries:&lt;/strong&gt; This table is a reference table with the fields ID and Country. The ID field represents the unique identifier for each record.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbmmjfkth8uyttt0dq632.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbmmjfkth8uyttt0dq632.png" alt=" " width="279" height="81"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To do a right outer join:&lt;/p&gt;

&lt;p&gt;Select the Sales query, and then select Merge queries.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;In the Merge dialog box, under Right table for merge, select Countries.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In the Sales table, select the CountryID column.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In the Countries table, select the ID column.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In the Join kind section, select Right outer.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Select OK.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsir49nan2949843zacf5.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsir49nan2949843zacf5.png" alt=" " width="800" height="890"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;From the newly created Countries column, expand the Country field. Don't select the Use original column name as prefix check box.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Figuxqpjziucp4cvjx4sy.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Figuxqpjziucp4cvjx4sy.png" alt=" " width="800" height="412"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After performing this operation, you create a table that looks like the following image.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8dcryfsj7lup53rjot5x.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8dcryfsj7lup53rjot5x.png" alt=" " width="543" height="79"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Full Outer Join
&lt;/h2&gt;

&lt;p&gt;One of the join kinds available in the Merge dialog in Power Query is a full outer join, which brings in all the rows from both the left and right tables. &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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fh08vg543uxwaotrdh1rz.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fh08vg543uxwaotrdh1rz.png" alt=" " width="464" height="404"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sales&lt;/strong&gt;: This table includes the fields Date, CountryID, and Units. CountryID is a whole number value that represents the unique identifier from the Countries table.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fybi45if94sulo5sdoyu6.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fybi45if94sulo5sdoyu6.png" alt=" " width="411" height="166"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Countries&lt;/strong&gt;: This table is a reference table with the fields ID and Country. The ID field represents the unique identifier for each record.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3v5jix3tso4iv5tbdggi.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3v5jix3tso4iv5tbdggi.png" alt=" " width="273" height="167"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The goal is to create a table like the following, where the name of the country appears as a new Country column in the Sales table. Because of how the full outer join works, all rows from both the left and right tables are brought in, regardless of whether they only appear in one of the tables.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F87iazss2flfhes3rmbub.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F87iazss2flfhes3rmbub.png" alt=" " width="539" height="202"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To perform a full outer join:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Select the Sales query, and then select Merge queries.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In the Merge dialog box, under Right table for merge, select Countries.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In the Sales table, select the CountryID column.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In the Countries table, select the ID column.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In the Join kind section, select Full outer.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Select OK&lt;/p&gt;&lt;/li&gt;
&lt;/ol&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fse9i22mtgrhvui5cvxs7.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fse9i22mtgrhvui5cvxs7.png" alt=" " width="800" height="889"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Best use&lt;/p&gt;

&lt;p&gt;A full outer join is useful when the objective is to identify and retain records from both datasets, including unmatched records.&lt;/p&gt;

&lt;h2&gt;
  
  
  Inner Join
&lt;/h2&gt;

&lt;p&gt;An Inner Join keeps only records that have matching values in both tables.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;p&gt;Customers:&lt;/p&gt;

&lt;p&gt;C001&lt;br&gt;
C002&lt;br&gt;
C003&lt;/p&gt;

&lt;p&gt;Orders:&lt;/p&gt;

&lt;p&gt;C001&lt;br&gt;
C002&lt;br&gt;
C004&lt;/p&gt;

&lt;p&gt;The inner join returns:&lt;/p&gt;

&lt;p&gt;C001&lt;br&gt;
C002&lt;/p&gt;

&lt;p&gt;C003 and C004 are removed because they do not have matching records in both tables.&lt;/p&gt;

&lt;p&gt;Best use&lt;/p&gt;

&lt;p&gt;An inner join is useful when only records with matching information in both datasets are required.&lt;/p&gt;

&lt;h2&gt;
  
  
  Left Anti Join
&lt;/h2&gt;

&lt;p&gt;A Left Anti Join returns records that exist in the left table but do not have a matching record in the right table.&lt;/p&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;p&gt;Customers:&lt;/p&gt;

&lt;p&gt;C001&lt;br&gt;
C002&lt;br&gt;
C003&lt;/p&gt;

&lt;p&gt;Orders:&lt;/p&gt;

&lt;p&gt;C001&lt;br&gt;
C002&lt;/p&gt;

&lt;p&gt;The left anti join returns:&lt;/p&gt;

&lt;p&gt;C003&lt;/p&gt;

&lt;p&gt;Practical use&lt;/p&gt;

&lt;p&gt;This can be used to identify customers who have never placed an order.&lt;/p&gt;

&lt;p&gt;It is also useful for data-quality checks and identifying missing relationships.&lt;/p&gt;

&lt;h2&gt;
  
  
  Right Anti Join
&lt;/h2&gt;

&lt;p&gt;A Right Anti Join returns records from the right table that do not have matching records in the left table.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;p&gt;Customers:&lt;/p&gt;

&lt;p&gt;C001&lt;br&gt;
C002&lt;/p&gt;

&lt;p&gt;Orders:&lt;/p&gt;

&lt;p&gt;C001&lt;br&gt;
C002&lt;br&gt;
C003&lt;/p&gt;

&lt;p&gt;A right anti join returns:&lt;/p&gt;

&lt;p&gt;C003&lt;/p&gt;

&lt;p&gt;This could identify an order containing a CustomerID that does not exist in the Customers table.&lt;/p&gt;

&lt;p&gt;Practical use&lt;/p&gt;

&lt;p&gt;It is particularly useful for finding missing or unmatched records.&lt;/p&gt;

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

&lt;p&gt;Although joins and relationships connect data, they perform different jobs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Power Query Merge
&lt;/h3&gt;

&lt;p&gt;A merge is performed during data preparation.&lt;/p&gt;

&lt;p&gt;It combines data from two queries and can add columns from one query into another.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;p&gt;Sales + Customer&lt;/p&gt;

&lt;p&gt;can produce a query containing:&lt;/p&gt;

&lt;p&gt;SalesID&lt;br&gt;
CustomerID&lt;br&gt;
SalesAmount&lt;br&gt;
CustomerName&lt;/p&gt;

&lt;p&gt;After the merge, the resulting query can be loaded into the Power BI model.&lt;/p&gt;

&lt;p&gt;Microsoft's Power Query documentation demonstrates that Merge Queries can be used to combine queries and then expand columns from the merged table.&lt;/p&gt;

&lt;h2&gt;
  
  
  Power BI Relationship
&lt;/h2&gt;

&lt;p&gt;A relationship is created in the data model.&lt;/p&gt;

&lt;p&gt;Instead of physically putting all columns into one table, the tables remain separate.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DimCustomer&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;↓&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;FactSales&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The relationship allows filters to move between the tables.&lt;/p&gt;

&lt;p&gt;Power BI relationships therefore support the analytical model, while Power Query merges are mainly used for preparing and shaping the data.&lt;/p&gt;

&lt;p&gt;When Should You Merge?&lt;/p&gt;

&lt;p&gt;A Power Query merge is appropriate when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;You need to add a column from another query.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Data needs to be cleaned or transformed before loading.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You want to resolve a lookup during data preparation.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The combined result makes the final model simpler.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The information logically belongs together.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, if a product ID needs to be converted into a product category before the data reaches the model, a merge can be appropriate.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When Should You Use a Relationship?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A relationship is normally preferable when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Tables represent different business entities.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A fact table needs several dimensions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The same dimension will be reused across multiple reports or fact tables.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You want dimensions to filter facts.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You want to maintain a star-schema structure.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The data should remain logically separated.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;p&gt;DimProduct → FactSales&lt;/p&gt;

&lt;p&gt;is generally better than repeatedly copying product information into every sales record.&lt;/p&gt;

&lt;h2&gt;
  
  
  Problems with Excessive Merging
&lt;/h2&gt;

&lt;p&gt;Although merging can be useful, excessive merging can create a very large and complicated table.&lt;/p&gt;

&lt;p&gt;For example, instead of having:&lt;/p&gt;

&lt;p&gt;DimCustomer&lt;/p&gt;

&lt;p&gt;DimProduct&lt;/p&gt;

&lt;p&gt;DimDate&lt;/p&gt;

&lt;p&gt;FactSales&lt;/p&gt;

&lt;p&gt;a developer might merge everything into one huge sales table.&lt;/p&gt;

&lt;p&gt;This can result in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Repeated customer information.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Repeated product information.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Increased redundancy.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Larger datasets.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;More difficult maintenance.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Less flexible modelling.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A star schema avoids much of this unnecessary repetition by keeping dimensions separate from facts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Recommended Power BI Model
&lt;/h2&gt;

&lt;p&gt;For a typical business reporting application, the recommended approach is a star schema.&lt;/p&gt;

&lt;p&gt;A suitable model could be:&lt;/p&gt;

&lt;p&gt;DimDate&lt;/p&gt;

&lt;p&gt;↓&lt;br&gt;
FactSales&lt;br&gt;
↑&lt;br&gt;
DimCustomer&lt;/p&gt;

&lt;p&gt;along with:&lt;/p&gt;

&lt;p&gt;DimProduct → FactSales ← DimLocation&lt;/p&gt;

&lt;p&gt;The fact table contains transactions and numerical measures, while dimensions contain descriptive attributes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why Star Schema?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Performance&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A well-structured star schema provides a model that is optimized for analytical queries. Microsoft specifically describes star schema as an important design approach for Power BI semantic models optimized for performance and usability.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; &lt;strong&gt;DAX Simplicity&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Measures can be created in the fact table while dimensions provide the filtering context.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;p&gt;Total Sales = SUM(FactSales[SalesAmount])&lt;/p&gt;

&lt;p&gt;A user can then place:&lt;/p&gt;

&lt;p&gt;Year from DimDate&lt;br&gt;
Category from DimProduct&lt;br&gt;
County from DimLocation&lt;/p&gt;

&lt;p&gt;into a visual while Power BI uses the relationships to filter FactSales.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Readability&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A model with clearly named fact and dimension tables is easier for developers and report users to understand.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Scalability&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;New dimensions can be added without rebuilding the entire model.&lt;/p&gt;

&lt;p&gt;For example, the organization could later add:&lt;/p&gt;

&lt;p&gt;DimEmployee&lt;/p&gt;

&lt;p&gt;or&lt;/p&gt;

&lt;p&gt;DimSupplier&lt;/p&gt;

&lt;p&gt;while retaining the central sales fact table.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Maintainability&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Separating business entities reduces duplication and makes it easier to update descriptive information.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Filter Propagation&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Relationships provide controlled paths for filters to travel from dimensions to facts.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Relationship Simplicity&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The most common pattern is a one-to-many relationship:&lt;/p&gt;

&lt;p&gt;Dimension 1 → * Fact&lt;/p&gt;

&lt;p&gt;This makes the model easier to understand than a network containing many unnecessary many-to-many or bidirectional relationships.&lt;/p&gt;

&lt;h2&gt;
  
  
  Practical Design Example
&lt;/h2&gt;

&lt;p&gt;Consider a supermarket reporting system.&lt;/p&gt;

&lt;p&gt;The model could contain:&lt;/p&gt;

&lt;p&gt;FactSales&lt;br&gt;
SalesID&lt;br&gt;
DateKey&lt;br&gt;
CustomerID&lt;br&gt;
ProductID&lt;br&gt;
StoreID&lt;br&gt;
Quantity&lt;br&gt;
SalesAmount&lt;br&gt;
Cost&lt;br&gt;
DimProduct&lt;br&gt;
ProductID&lt;br&gt;
ProductName&lt;br&gt;
Category&lt;br&gt;
Brand&lt;br&gt;
DimCustomer&lt;br&gt;
CustomerID&lt;br&gt;
CustomerName&lt;br&gt;
Gender&lt;br&gt;
CustomerType&lt;br&gt;
DimDate&lt;br&gt;
DateKey&lt;br&gt;
Date&lt;br&gt;
Month&lt;br&gt;
Quarter&lt;br&gt;
Year&lt;br&gt;
DimStore&lt;br&gt;
StoreID&lt;br&gt;
StoreName&lt;br&gt;
County&lt;br&gt;
Region&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Relationships&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;DimProduct[ProductID] 1 → * FactSales[ProductID]&lt;br&gt;
DimCustomer[CustomerID] 1 → * FactSales[CustomerID]&lt;br&gt;
DimDate[DateKey] 1 → * FactSales[DateKey]&lt;br&gt;
DimStore[StoreID] 1 → * FactSales[StoreID]&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This model can support reports such as&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;Total sales by product category&lt;/p&gt;

&lt;p&gt;Sales by county&lt;/p&gt;

&lt;p&gt;Monthly revenue&lt;/p&gt;

&lt;p&gt;Sales per customer&lt;/p&gt;

&lt;p&gt;Profit by store&lt;/p&gt;

&lt;p&gt;Best-performing products&lt;/p&gt;

&lt;p&gt;The model remains understandable because each table has a clear purpose.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Common Modelling Mistakes&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Several mistakes can reduce the quality of a Power BI model.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Using One Huge Table&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This creates unnecessary duplication and can make the model difficult to maintain.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Incorrect Cardinality&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, treating a column containing duplicate customer IDs as the "one" side of a relationship can produce errors or incorrect results.&lt;/p&gt;

&lt;p&gt;Power BI requires the one side of a relationship to contain unique values.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Excessive Many-to-Many Relationships&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Many-to-many relationships can create more complex filtering behaviour. A bridge table can often provide a clearer design.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Excessive Bidirectional Filtering&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Using Both everywhere can create ambiguous filter paths and make the model harder to understand.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Ignoring Fact Table Grain&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A fact table should have a clearly defined meaning for each row.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Unnecessary Merging&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Not every table needs to be merged. Maintaining separate fact and dimension tables is often preferable.&lt;/p&gt;

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

&lt;p&gt;Data modelling is fundamental to successful Power BI development. The way tables are organized directly affects reporting accuracy, DAX calculations, performance, scalability, and maintainability.&lt;/p&gt;

&lt;p&gt;A flat table is simple and can be useful for small datasets, but it becomes less suitable as data grows. A snowflake schema can reduce redundancy but introduces additional tables and relationships. For most Power BI analytical models, the star schema provides the best balance of simplicity, performance, scalability, and usability.&lt;/p&gt;

&lt;p&gt;Fact tables should contain measurable business events at a clearly defined grain, while dimension tables should contain descriptive attributes. Relationships connect these tables and control filter propagation. One-to-many relationships are particularly important because they naturally represent the relationship between dimensions and facts.&lt;/p&gt;

&lt;p&gt;Power Query joins serve a different purpose. They are mainly used to prepare and combine data before it reaches the model. Left, right, full, inner, and anti joins allow developers to control which records are retained during data transformation.&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>datascience</category>
      <category>ai</category>
      <category>resources</category>
    </item>
    <item>
      <title>Building an Interactive Excel Dashboard.</title>
      <dc:creator>Bonny Mark</dc:creator>
      <pubDate>Sat, 05 Sep 2026 08:59:28 +0000</pubDate>
      <link>https://dev.to/kbonymark/building-an-interactive-excel-dashboard-2329</link>
      <guid>https://dev.to/kbonymark/building-an-interactive-excel-dashboard-2329</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;The dataset: 112 products scraped from Jumia Kenya, with fields for current price, old price, discount percentage, review count, and customer rating. The goal was to clean it, analyze it, and turn it into an interactive Excel dashboard with slicers and pivot charts, not just static tables.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cleaning
&lt;/h2&gt;

&lt;p&gt;Before any analysis, I had to fix:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Prices stored as text&lt;/strong&gt; — Excel treats "KSh 1,499" as a string, not a number, so no math works until you strip the formatting&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ratings buried in descriptive text&lt;/strong&gt; — extracting a clean numeric rating from messy scraped fields&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Invalid negative review counts&lt;/strong&gt; — clearly a scraping artifact, not real data&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;55 of 112 products (49%) with no review or rating.
I could have dropped those 55 rows,Instead labeled them "No reviews" and "Not Rated"  rather than treating them as blank. That turned out to matter a lot, because **half the catalog having zero customer feedback is itself one of the most important findings in the whole project&lt;/strong&gt;, did need cleaning.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Building Categories for Pivot Analysis
&lt;/h2&gt;

&lt;p&gt;To make pivot tables and slicers actually useful, I added four calculated columns:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Review_Category&lt;/strong&gt; — Low / Medium / High / No reviews&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rating_category&lt;/strong&gt; — Poor / Average / Excellent / Not Rated&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Discount_category&lt;/strong&gt; — Low / Medium / High Discount&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;price_category&lt;/strong&gt; — Low / Medium / High / Premium (quartile-based bands)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Building the Dashboard
&lt;/h2&gt;

&lt;p&gt;I built 8 pivot tables from a single shared table (&lt;code&gt;tblCleaned&lt;/code&gt;) &lt;strong&gt;every pivot table needs to come from the same source table for slicers to control all of them simultaneously.&lt;/strong&gt; Miss this, and you end up with a slicer that only filters one chart instead of your whole dashboard a mistake I made and had to fix along the way.&lt;/p&gt;

&lt;p&gt;The dashboard includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;5 KPI cards (total products, average price, average discount, average rating, total reviews)&lt;/li&gt;
&lt;li&gt;3 top-10 bar charts (by rating, by reviews, by discount)&lt;/li&gt;
&lt;li&gt;3 trend charts (discount vs. reviews, rating vs. reviews, price vs. rating)&lt;/li&gt;
&lt;li&gt;2 pie charts (rating breakdown, discount breakdown)&lt;/li&gt;
&lt;li&gt;3 slicers (rating category, discount category, price category) connected across all 8 pivots&lt;/li&gt;
&lt;/ul&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1hdk3bbgawlebaish9af.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1hdk3bbgawlebaish9af.png" alt="Dashboard" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What the Data Actually Said
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Discount % vs. Review count: correlation ≈ -0.14&lt;/strong&gt;&lt;br&gt;
Higher discounts do not lead to more reviews. If anything, there's a very weak negative relationship.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rating vs. Review count: correlation ≈ +0.06&lt;/strong&gt;&lt;br&gt;
Essentially zero relationship. Highly-rated products don't get meaningfully more reviews than mediocre ones.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Price vs. Rating: correlation ≈ +0.15&lt;/strong&gt;&lt;br&gt;
Barely positive. Expensive products are not reliably rated higher than cheap ones though mid-to-upper-priced items (KSh 1,190–1,820) did show the best average rating (~4.2) of any price tier.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Only &lt;strong&gt;16 of 112 products (14%)&lt;/strong&gt; hit "strong engagement" (14+ reviews)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;90% of heavily discounted products (40%+ off)&lt;/strong&gt; show low or no engagement&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;49% of the entire catalog has zero reviews&lt;/strong&gt;, regardless of discount or price&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The product that stuck with me most: a &lt;strong&gt;120W Cordless Vacuum Cleaner&lt;/strong&gt; with 69 reviews, most of any product in the dataset sitting at just &lt;strong&gt;2.8★&lt;/strong&gt;. High visibility, low satisfaction. That's a much bigger red flag than a discount that didn't move the needle.&lt;/p&gt;

&lt;h2&gt;
  
  
  Repo &amp;amp; Full Breakdown
&lt;/h2&gt;

&lt;p&gt;Full project, including the cleaned dataset, the Excel workbook (raw data → cleaned data → pivot tables → dashboard), and a detailed README with all findings:&lt;a href="https://github.com/kimutaikoros/jumia-product-performance" rel="noopener noreferrer"&gt;https://github.com/kimutaikoros/jumia-product-performance&lt;/a&gt; dashboard&lt;/p&gt;

</description>
      <category>analysis</category>
      <category>data</category>
      <category>productivity</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Building a Jumia Product Performance Dashboard in Excel.</title>
      <dc:creator>Bonny Mark</dc:creator>
      <pubDate>Thu, 03 Sep 2026 12:14:51 +0000</pubDate>
      <link>https://dev.to/kbonymark/building-a-jumia-product-performance-dashboard-in-excel-39hl</link>
      <guid>https://dev.to/kbonymark/building-a-jumia-product-performance-dashboard-in-excel-39hl</guid>
      <description>&lt;p&gt;An interactive Excel dashboard analyzing pricing, discounts, and customer engagement across 112 Jumia products built to uncover whether promotions, ratings, and price actually drive customer engagement, and which products need a different strategy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Project Objective
&lt;/h2&gt;

&lt;p&gt;Turn a raw Jumia product export into a working analysis that answers:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Are larger discounts associated with more reviews?&lt;/li&gt;
&lt;li&gt;Do highly rated products attract stronger engagement?&lt;/li&gt;
&lt;li&gt;Do price and rating move together?&lt;/li&gt;
&lt;li&gt;Which products perform best based on ratings and reviews?&lt;/li&gt;
&lt;li&gt;Which products may need a different pricing or marketing strategy?&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Data Source
&lt;/h2&gt;

&lt;p&gt;Raw product data scraped from Jumia (Kenya's e-commerce platform), covering 115 products with product name, current price, old price, discount percentage, review count, and star rating. The raw export contained several data quality issues typical of scraped e-commerce data — see Cleaning Process below.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tools Used
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Microsoft Excel — data cleaning, formulas, PivotTables, PivotCharts, slicers, interactive dashboard&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Cleaning Process
&lt;/h2&gt;

&lt;p&gt;The raw data had several issues that needed fixing before analysis:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Prices&lt;/strong&gt; stored as text (e.g. &lt;code&gt;KSh 1,525&lt;/code&gt;) — stripped the currency prefix and thousands separators, converted to numeric with &lt;code&gt;VALUE(SUBSTITUTE(...))&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Discount&lt;/strong&gt; stored as text percentages (e.g. &lt;code&gt;38%&lt;/code&gt;) — converted to a true decimal (&lt;code&gt;0.38&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Review counts&lt;/strong&gt; were all negative (a scraping artifact) — corrected with &lt;code&gt;ABS()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rating&lt;/strong&gt; was stored as descriptive text (&lt;code&gt;"4.5 out of 5"&lt;/code&gt;) — extracted the numeric value with &lt;code&gt;LEFT()&lt;/code&gt; and &lt;code&gt;FIND()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;column header typo&lt;/strong&gt; (&lt;code&gt;Ratingd&lt;/code&gt;) was corrected to &lt;code&gt;Rating&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;3 fully blank rows&lt;/strong&gt; were removed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;55 of 112 products had no Review or Rating data&lt;/strong&gt; — left blank rather than filled with 0.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Key Findings
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Discount size does not reliably predict review count.&lt;/strong&gt; Average reviews across discount bands bounce around with no consistent upward trend.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Higher ratings don't guarantee stronger engagement.&lt;/strong&gt; Products rated 2.5–3.0 stars actually average &lt;em&gt;more&lt;/em&gt; reviews (24.6) than products rated 4.5–5.0 stars (14.4).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Price and rating are essentially unrelated.&lt;/strong&gt; Average rating stays flat (3.78–4.1) across every price bracket.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Top performers&lt;/strong&gt; by review volume include a mix of ratings — the single most-reviewed product (69 reviews) is rated only 2.8/5.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Underperformers&lt;/strong&gt; — 18 products rated below 3.5 stars — already carry an average discount of 43%, similar to the dataset average, meaning discounting alone isn't fixing their poor engagement.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dashboard
&lt;/h2&gt;

&lt;p&gt;The workbook includes an interactive Dashboard tab with 5 linked PivotCharts and slicers allowing live filtering.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building a Jumia Product Performance Dashboard in Excel
&lt;/h2&gt;

&lt;p&gt;When I started this project, I had a Jumia product export sitting in front of me 115 rows of product names, prices, discounts, reviews, and ratings and five specific questions I needed to answer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Are larger discounts associated with more reviews?&lt;/li&gt;
&lt;li&gt;Do highly rated products attract stronger engagement?&lt;/li&gt;
&lt;li&gt;Do price and rating move together?&lt;/li&gt;
&lt;li&gt;Which products perform best based on ratings and reviews?&lt;/li&gt;
&lt;li&gt;Which products may need a different pricing or marketing strategy?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here's how I got from raw, messy scraped data to a working interactive dashboard that answers all five and what the data actually said, which wasn't always what I expected.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Cleaning the data
&lt;/h3&gt;

&lt;p&gt;Scraped e-commerce data is never clean, and this dataset was no exception. A few issues stood out immediately:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prices were stored as text&lt;/strong&gt;, like &lt;code&gt;KSh 1,525&lt;/code&gt;, not numbers. Excel couldn't do any math on that. I fixed it with:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;\&lt;/code&gt;&lt;code&gt;&lt;br&gt;
=VALUE(SUBSTITUTE(SUBSTITUTE(B2,"KSh ",""),",",""))&lt;br&gt;
\&lt;/code&gt;&lt;code&gt;\&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This strips the "KSh " prefix and the thousands-separator comma, then converts what's left into a real number.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Discount was also text&lt;/strong&gt;, formatted like &lt;code&gt;38%&lt;/code&gt;. A simple &lt;code&gt;=VALUE(D2)&lt;/code&gt; was actually enough here Excel is smart enough to parse the &lt;code&gt;%&lt;/code&gt; symbol itself and convert &lt;code&gt;"38%"&lt;/code&gt; straight into &lt;code&gt;0.38&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Review counts were all negative&lt;/strong&gt; every single one, like &lt;code&gt;-2&lt;/code&gt;, &lt;code&gt;-14&lt;/code&gt;, &lt;code&gt;-55&lt;/code&gt;. That's clearly a scraping glitch, not real data, so I corrected it with &lt;code&gt;=ABS(E2)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rating was buried in descriptive text&lt;/strong&gt;, like &lt;code&gt;"4.5 out of 5"&lt;/code&gt;. I extracted just the numeric part with:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;\&lt;/code&gt;&lt;code&gt;&lt;br&gt;
=IFERROR(VALUE(LEFT(H2,FIND(" ",H2)-1)),"")&lt;br&gt;
\&lt;/code&gt;&lt;code&gt;\&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;FIND(" ", H2)&lt;/code&gt; locates the first space, &lt;code&gt;LEFT()&lt;/code&gt; grabs everything before it, &lt;code&gt;VALUE()&lt;/code&gt; converts that to a number, and &lt;code&gt;IFERROR()&lt;/code&gt; handles blanks gracefully.&lt;/p&gt;

&lt;p&gt;55 of the 112 products had no Review or Rating data at all I left those cells genuinely blank instead of filling them with 0, since 0 would misleadingly suggest an actual rating of zero.&lt;/p&gt;

&lt;p&gt;I also caught a header typo (&lt;code&gt;Ratingd&lt;/code&gt; → &lt;code&gt;Rating&lt;/code&gt;) and removed 3 fully empty rows at the bottom of the sheet.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Building the analysis
&lt;/h3&gt;

&lt;p&gt;With clean numeric data, I built a Calculations layer with a few extra metrics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Discount Amount (Ksh)&lt;/strong&gt; — &lt;code&gt;=Old price - Current price&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Price-to-Rating ratio&lt;/strong&gt; — &lt;code&gt;=Current price / Rating&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Engagement Level&lt;/strong&gt; — bucketing products into Low/Medium/High/No reviews&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then five PivotTables, one per objective question, each with its own PivotChart:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Discount vs. Average Review&lt;/strong&gt; — discount grouped into ~10% bands&lt;/li&gt;
&lt;/ol&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8j1v5muhub7ravvck36i.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8j1v5muhub7ravvck36i.png" alt=" " width="752" height="452"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Rating vs. Average Review&lt;/strong&gt; — rating grouped into 0.5-point bands&lt;/li&gt;
&lt;/ol&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgazrrltsmubokx94v9t7.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgazrrltsmubokx94v9t7.png" alt=" " width="752" height="452"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Price vs. Average Rating&lt;/strong&gt; — price grouped into bands&lt;/li&gt;
&lt;/ol&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fv9chag8a97bp5yrirw2s.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fv9chag8a97bp5yrirw2s.png" alt=" " width="752" height="452"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Top Performing&lt;/strong&gt; — top 10 products by review count&lt;/li&gt;
&lt;/ol&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fab3cq91l85ia9qudpjom.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fab3cq91l85ia9qudpjom.png" alt=" " width="800" height="335"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Underperformers&lt;/strong&gt; — products rated below 3.5, sorted by lowest engagement&lt;/li&gt;
&lt;/ol&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0g8492b4pdz9btou72cp.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0g8492b4pdz9btou72cp.png" alt=" " width="752" height="452"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: What the data actually showed
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Discount size doesn't predict reviews.&lt;/strong&gt; Average reviews across discount bands were essentially random: 15, 8.8, 19.2, 12.3, 12.3, 8.4 — no trend at all.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Higher ratings don't mean more engagement, either.&lt;/strong&gt; Products rated &lt;strong&gt;2.5–3.0 stars average 24.6 reviews&lt;/strong&gt;, more than products rated &lt;strong&gt;4.5–5.0 stars (14.4)&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Price and rating are basically unrelated.&lt;/strong&gt; Average rating barely moves across price brackets — 3.78 to 4.1 to 3.85 to 4.0&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;My top performer by review count&lt;/strong&gt; — a cordless vacuum cleaner with 69 reviews is only rated &lt;strong&gt;2.8 out of 5&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;My underperformers list&lt;/strong&gt; (18 products rated below 3.5) already carry an average discount of 43%, almost identical to the dataset's overall average. Discounting harder isn't fixing whatever's actually wrong with them.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: The dashboard
&lt;/h3&gt;

&lt;p&gt;I pulled all 5 PivotCharts onto a single Dashboard tab with slicers (Discount, Current Price, Product) so the whole thing stays interactive.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;conclusion:&lt;/strong&gt; none of price, discount, or star rating strongly predicts customer engagement on their own in this dataset. That's a real, defensible finding.&lt;/p&gt;




&lt;p&gt;Full workbook, cleaned data, and dashboard are on GitHub: [&lt;a href="https://github.com/kimutaikoros/-Jumia-product-performance-dashboard" rel="noopener noreferrer"&gt;https://github.com/kimutaikoros/-Jumia-product-performance-dashboard&lt;/a&gt;]&lt;/p&gt;

</description>
      <category>analysis</category>
      <category>analytics</category>
      <category>data</category>
    </item>
    <item>
      <title>[Boost]</title>
      <dc:creator>Bonny Mark</dc:creator>
      <pubDate>Sat, 29 Aug 2026 06:32:52 +0000</pubDate>
      <link>https://dev.to/kbonymark/-5hlh</link>
      <guid>https://dev.to/kbonymark/-5hlh</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/kbonymark/getting-started-with-excel-for-data-analytics-from-basics-to-data-cleaning-bid" class="crayons-story__hidden-navigation-link"&gt;Getting Started with Excel for Data Analytics: From Basics to Data Cleaning.&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/kbonymark" class="crayons-avatar  crayons-avatar--l  "&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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3958039%2F6ba65c9b-d447-4a5d-a844-08afce740723.jpg" alt="kbonymark profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/kbonymark" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Bonny Mark
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Bonny Mark
                
                
              
              &lt;div id="story-author-preview-content-4501837" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/kbonymark" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3958039%2F6ba65c9b-d447-4a5d-a844-08afce740723.jpg" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Bonny Mark&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/kbonymark/getting-started-with-excel-for-data-analytics-from-basics-to-data-cleaning-bid" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Aug 27&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/kbonymark/getting-started-with-excel-for-data-analytics-from-basics-to-data-cleaning-bid" id="article-link-4501837"&gt;
          Getting Started with Excel for Data Analytics: From Basics to Data Cleaning.
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/tutorial"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;tutorial&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/beginners"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;beginners&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/datascience"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;datascience&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/data"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;data&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/kbonymark/getting-started-with-excel-for-data-analytics-from-basics-to-data-cleaning-bid" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;1&lt;span class="hidden s:inline"&gt;&amp;nbsp;reaction&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/kbonymark/getting-started-with-excel-for-data-analytics-from-basics-to-data-cleaning-bid#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              &lt;span class="hidden s:inline"&gt;Add&amp;nbsp;Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            7 min read
          &lt;/small&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
    </item>
    <item>
      <title>Getting Started with Excel for Data Analytics: From Basics to Data Cleaning.</title>
      <dc:creator>Bonny Mark</dc:creator>
      <pubDate>Thu, 27 Aug 2026 06:57:51 +0000</pubDate>
      <link>https://dev.to/kbonymark/getting-started-with-excel-for-data-analytics-from-basics-to-data-cleaning-bid</link>
      <guid>https://dev.to/kbonymark/getting-started-with-excel-for-data-analytics-from-basics-to-data-cleaning-bid</guid>
      <description>&lt;h2&gt;
  
  
  &lt;strong&gt;Introduction to Microsoft Excel&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Microsoft excel is  used for storing, organizing, cleaning, analyzing and presenting data. It provides a structured environment where users can enter data into rows and columns, perform calculations using formulas and functions, create charts, and apply formatting to make information easier to understand.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding the Interface
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Quick Access Toolbar&lt;/strong&gt;&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxi81tlf23w7dojub4nzp.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxi81tlf23w7dojub4nzp.png" alt=" " width="800" height="430"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Save icon&lt;/strong&gt;- Save icon or you can Ctrl + S&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Undo / Redo arrows&lt;/strong&gt;-step backward or forward through your recent actions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;File name&lt;/strong&gt;- shows the name of the current file in excel.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Search bar&lt;/strong&gt;-lets you search for any Excel command by typing what you want to do.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tabs&lt;/strong&gt;&lt;br&gt;
At the top holds most comomon tools used in excel:  File, Home, Insert, Draw, Page Layout, Formulas, Data, Review, View, Help.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Home Tab Groups&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Clipboard&lt;/strong&gt;  part we have the Paste,cut and Format Painter.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fonts&lt;/strong&gt;  part we have the font name needed to use and its font size,below it we have bold,italic,underline ,borders,Theme colors which helps change colors of the headings,we also can increase or reduce  the size of the heading with the "A"&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Alignment&lt;/strong&gt; part we have &lt;strong&gt;Vertical alignment ** (top/middle/bottom),&lt;/strong&gt;Horizontal alignment** (left/center/right),&lt;strong&gt;Wrap Text&lt;/strong&gt; — makes long text fit into one cell and &lt;strong&gt;Merge &amp;amp; Center&lt;/strong&gt; — combines multiple cells as one, often used with title headings.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Styles&lt;/strong&gt; part we have &lt;strong&gt;Preset cell styles&lt;/strong&gt;: &lt;strong&gt;Normal&lt;/strong&gt;, &lt;strong&gt;Bad&lt;/strong&gt; (red), &lt;strong&gt;Good&lt;/strong&gt; (green), &lt;strong&gt;Neutral&lt;/strong&gt; (yellow), &lt;strong&gt;Calculation&lt;/strong&gt;, &lt;strong&gt;Check Cell&lt;/strong&gt;,&lt;br&gt;
&lt;strong&gt;Conditional Formatting&lt;/strong&gt; — changes the apperance of cell and you can uuse color filter and &lt;strong&gt;Format as Table&lt;/strong&gt; — turns a range into a structured, filterable table.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cells&lt;/strong&gt; we have the &lt;strong&gt;Insert&lt;/strong&gt;, &lt;strong&gt;Delete&lt;/strong&gt;, &lt;strong&gt;Format&lt;/strong&gt; which add/remove rows, column or sheets and adjust row height/column width or lock cells.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Editing&lt;/strong&gt; part we have &lt;strong&gt;AutoSum&lt;/strong&gt; (Σ) — quick shortcut to insert SUM, AVERAGE,MIN, MAX, COUNT  and more options,  &lt;strong&gt;Fill&lt;/strong&gt;  is an extend of values or formula across a range,  &lt;strong&gt;Sort &amp;amp; Filter&lt;/strong&gt; is a tool behind sorting data and removing  blanks and duplicates, &lt;strong&gt;Find &amp;amp; Select&lt;/strong&gt; — search the sheet, or jump to special cells.&lt;/p&gt;

&lt;h3&gt;
  
  
  Other Ribbon Tabs.
&lt;/h3&gt;

&lt;p&gt;Besides the Home tab, the Ribbon has several other tabs, each grouping tools around a specific type of task:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Insert&lt;/strong&gt; — used to add things into the sheet beyond raw data: Tables, PivotTables, Charts (bar, line, pie, etc.), Pictures and Icons, Shapes, Text Boxes, Headers &amp;amp; Footers, and Hyperlinks.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Draw&lt;/strong&gt; — lets you draw or write freehand directly on the sheet using a mouse, stylus, or touchscreen, useful for annotating or sketching ideas quickly.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Page Layout&lt;/strong&gt; — controls how the sheet looks when printed or exported: Margins, Orientation (Portrait/Landscape), Page Size, Print Area, and Themes that change the overall color/font scheme of the workbook.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Formulas&lt;/strong&gt; — the home of the Function Library (organized by category: Financial, Logical, Text, Date &amp;amp; Time, Lookup &amp;amp; Reference, Math &amp;amp; Trig), along with Name Manager for naming ranges, and Formula Auditing tools like Trace Precedents/Dependents to see how cells are connected.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Data&lt;/strong&gt; — where you sort and filter, import data from external sources (like text files, other workbooks, or the web), use Data Validation, apply Text to Columns to split a single column into several, and access the What-If Analysis and Outline/Group tools for summarizing data.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Review&lt;/strong&gt;— used for checking and collaborating on a workbook: Spelling check, adding Comments or Notes, Protecting a sheet or workbook from edits, and Tracking Changes made by different people.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;View&lt;/strong&gt; — controls how the workbook is displayed: switching between Normal, Page Break Preview, and Page Layout views, showing/hiding Gridlines and the Formula Bar, Freeze Panes (covered earlier), and Zoom.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Help&lt;/strong&gt; — provides quick access to Microsoft's support resources, feedback options, and training content directly from within Excel.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  DATA CLEANING
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Removing duplicates
&lt;/h3&gt;

&lt;p&gt;Removing duplicates is applied across all collumns in a one technique way and is fast and easy and first thing to do is copy the first sheet and create another called clean data and have original data stay in a diffrent sheet.&lt;/p&gt;

&lt;p&gt;-Six duplicates removed from the 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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmval8xv1o6lfaxo6kds1.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmval8xv1o6lfaxo6kds1.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Sorting and Filtering
&lt;/h3&gt;

&lt;p&gt;sorting and filtering is the fastest way to check data quality issues and know whether they are blanks in the data and then go clean the data after this you Autofit colunm witdth.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqx8iz87tu7xaxvxpt90j.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqx8iz87tu7xaxvxpt90j.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the view bar you freeze the top row so that it can be intact.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cleaned data
&lt;/h3&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2mmg5aqv5dhpkyydsnvw.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2mmg5aqv5dhpkyydsnvw.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;While cleaning data we also use Find and replace to find the unwanted data that was entered and replace with the corect data use &lt;strong&gt;ctrl + H&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Data Validation
&lt;/h3&gt;

&lt;p&gt;Data Validation controls what a user is allowed to enter into a cell.&lt;/p&gt;

&lt;p&gt;EXample, if you have a column called Gender, you can make a dropdown containing:&lt;br&gt;
Male&lt;br&gt;
Female&lt;/p&gt;

&lt;p&gt;The screenshots bellow shows how data validation works it gives us adrop down on the data we supppose to enter and shows an error when one tries to enter invalid 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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyjnplsvfgdoy3lqjcepl.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyjnplsvfgdoy3lqjcepl.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3yrb728oizeadtbazvbc.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3yrb728oizeadtbazvbc.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Conditional Formating
&lt;/h3&gt;

&lt;p&gt;Conditional Formatting changes the appearance of cells automatically based on their values.&lt;br&gt;
The screenshot bellow shows we telll excel to make the cell red or certain  or  color of your choice.&lt;br&gt;
First we select the collumn you wannt to format and highlight cell rule and choose the color you'd like to use.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyfxkmqajz2oi0zo0852l.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyfxkmqajz2oi0zo0852l.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next you filter by color&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fx9lqa4q5nsk4dt8dxud5.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fx9lqa4q5nsk4dt8dxud5.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finnaly you have the filtered data by colour selected together in red.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6qx839e88p9u0kwy1twn.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6qx839e88p9u0kwy1twn.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Text Functions for Cleaning Data
&lt;/h2&gt;

&lt;p&gt;Text functions help standardize text, remove extra spaces, extract parts of strings, or find and replace substrings, it is very useful when a dataset has messy or inconsistent entries.&lt;/p&gt;

&lt;p&gt;Examples of the fucnctions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;UPPER()&lt;/strong&gt; — converts text to uppercase. =UPPER("john") → JOHN&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;LOWER()&lt;/strong&gt;— converts text to lowercase (lower case → lower c). =LOWER("JOHN") → john.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;PROPER()&lt;/strong&gt;— capitalizes the first letter of each word. =PROPER("john doe") → John Doe.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;TRIM()&lt;/strong&gt; — removes extra spaces from text, e.g. =TRIM(A2).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;LEFT()&lt;/strong&gt; — extracts the leftmost characters — abstract "left" is better read as "from the left." =LEFT("John", 2) → Jo.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;RIGHT()&lt;/strong&gt; — extracts the rightmost characters, e.g. =RIGHT(A2, 3) → last 3 characters.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;MID()&lt;/strong&gt; — extracts characters from the middle, e.g. =MID(A2, 2, 3) → 3 characters starting at position 2.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;LEN()&lt;/strong&gt; — returns the length of the text, e.g. =LEN("John") → 4.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;*&lt;em&gt;FIND() *&lt;/em&gt;— finds the position of a substring inside text (case-sensitive), e.g. =FIND("w", A2) returns the position of the letter "w".&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;SUBSTITUTE()&lt;/strong&gt; — replaces text within a string, e.g. =SUBSTITUTE("John Doe","Doe","Smith") → John Smith.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;CONCAT()&lt;/strong&gt; — joins two or more cells together into one string, e.g. =CONCATENATE(A2, B2) or =CONCAT(A2,B2), useful for merging a first name and last name into a full name.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Screenshot below shows implemented functions&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8vqihr3ser403v9i4n4o.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8vqihr3ser403v9i4n4o.png" alt=" " width="800" height="430"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Basic Calculations, Formulas and Arithmetic
&lt;/h2&gt;

&lt;p&gt;Heelps with calculation of cells or cell and a  certain figure.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Addition&lt;/strong&gt;- (+) = A1+B1&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Subtraction&lt;/strong&gt; - (-) = A1-B2&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Multiplication&lt;/strong&gt; - (*) = A1*B1&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Division&lt;/strong&gt; - (/) =A11/B1&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Exponent&lt;/strong&gt; - (^) = A1^2&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Common Functions
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;SUM()&lt;/strong&gt;— adds a range of numbers, e.g. =SUM(B1:B5)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;AVERAGE()&lt;/strong&gt; — calculates the mean of values.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;MIN()&lt;/strong&gt; — finds the smallest number.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;MAX()&lt;/strong&gt; — finds the largest number.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;MEDIAN()&lt;/strong&gt; — finds the middle value.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;MODE()&lt;/strong&gt;— finds the most frequently occurring value.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;PRODUCT(&lt;/strong&gt;) — multiplies numbers together.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;POWER()&lt;/strong&gt; — raises a number to an exponent, e.g. =POWER(10,3) → 10^3 = 1000.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Screenshot of how i worked some of the functions;&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhuiohgj3rfiw3lrwnke6.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhuiohgj3rfiw3lrwnke6.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Counting and Conditional Functions
&lt;/h3&gt;

&lt;p&gt;These are especially useful once you're cleaning or summarizing large datasets:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;COUNTA()&lt;/strong&gt;— counts all non-blank cells.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;COUNTBLANK()&lt;/strong&gt; — counts all blank cells.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;COUNT()&lt;/strong&gt; — counts numeric values only.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;COUNTIF()&lt;/strong&gt; — counts cells that match one condition, e.g. =COUNTIF(Q2:Q870,"Remote").&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;COUNTIFS()&lt;/strong&gt;— counts cells that match more than one condition, e.g.&lt;br&gt;
=COUNTIFS(Q2:Q870,"runner",P2:P870,"Madrid").&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;SUMIF()&lt;/strong&gt;— sums values that meet one condition.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;SUMIFS()&lt;/strong&gt;— sums values that meet more than one condition.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1uatvvakzrlbaorhl8lc.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1uatvvakzrlbaorhl8lc.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Date Functions
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;TODAY()&lt;/strong&gt; — returns today's date.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;YEAR()&lt;/strong&gt; — extracts the year from a date.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;MONTH()&lt;/strong&gt; — extracts the month from a date.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;NOW()&lt;/strong&gt;- returns the exact time&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Datedif()&lt;/strong&gt;-returns the diffrent number of days,months or years whatever you want from the previous date to the recent date. =datedif(g2,h2,"d").&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Networkdays&lt;/strong&gt;- returns the working days.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flxmfj3ly5mfuhm3hlpiy.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flxmfj3ly5mfuhm3hlpiy.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Cell References
&lt;/h2&gt;

&lt;p&gt;Instead of typing actual numbers into formulas, you can use cell references like A1 or B2, so that if the value in the referenced cell changes, the formula result updates automatically.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Relative reference&lt;/strong&gt; — changes when the formula is copied to another cell, e.g. A1.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Absolute reference&lt;/strong&gt; — stays fixed no matter where the formula is copied, e.g. $A$1.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, in a formula like =A2B1, if B1 holds a fixed rate that should never change as the formula is copied down, it should be written as =A2$B$1 instead, so B1 stays locked in place while A2 still adjusts for each row.&lt;/p&gt;

&lt;p&gt;These errors are common while writing formulas across a large dataset, and knowing what each one means makes troubleshooting much quicker than guessing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Common Formula Errors
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;#DIV/0!&lt;/strong&gt;- Division by zero.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;#REF!&lt;/strong&gt;- Invalid reference.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;#VALUE!&lt;/strong&gt;-  Wrong data type.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;#NAME?&lt;/strong&gt; - Misspelled function.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Excel is a lot more than a grid for typing numbers into — it's a genuine data-cleaning and analysis tool. From navigating the interface, to cleaning data with duplicates removal, sorting, filtering and validation to using text functions, arithmetic, and conditional functions like COUNTIFS and SUMIFS, Excel gives you everything needed to turn a messy, raw dataset into something clean and structured. Understanding cell references and common error codes also makes troubleshooting formulas much faster. Overall, this covers the core Excel toolkit needed to confidently work with real-world data, from basic entry all the way through to conditional summarizing and cleanup.&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>beginners</category>
      <category>datascience</category>
      <category>data</category>
    </item>
    <item>
      <title>GIT WORKFLOW</title>
      <dc:creator>Bonny Mark</dc:creator>
      <pubDate>Wed, 26 Aug 2026 15:12:57 +0000</pubDate>
      <link>https://dev.to/kbonymark/-git-workflow-jc0</link>
      <guid>https://dev.to/kbonymark/-git-workflow-jc0</guid>
      <description>&lt;p&gt;&lt;strong&gt;##How it all Operates&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I worked a path from creating an empty folder to a live repository,using Git Bash,powershell and SHH authentication insted of typing in the password each time i'm pushing aproject to github.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where this is going
&lt;/h2&gt;

&lt;p&gt;steps followed in each order?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Create a GitHub account&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Set up a project folder&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Generate an SSH key&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Register the key with GitHub&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create a repo and link your local folder to it&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Get a GitHub account
&lt;/h2&gt;

&lt;p&gt;If you don't already have one, head to github.com and sign up — email and  your password.&lt;/p&gt;

&lt;h2&gt;
  
  
  Set up a project folder
&lt;/h2&gt;

&lt;p&gt;Open git bash and enter this commands:&lt;/p&gt;

&lt;p&gt;cd Desktop&lt;br&gt;
mkdir my-project&lt;br&gt;
cd my-project&lt;/p&gt;

&lt;p&gt;once you're inside your project add a sub folder of data or scripts by running this command:&lt;/p&gt;

&lt;p&gt;mkdir data&lt;/p&gt;

&lt;p&gt;Inside the the folder we add a READNE.md file by running this command:&lt;/p&gt;

&lt;p&gt;touch README.md&lt;/p&gt;

&lt;h2&gt;
  
  
  Generate an SSH key
&lt;/h2&gt;

&lt;p&gt;Open PowerShell as Administrator first, just to confirm Git is actually installed:&lt;/p&gt;

&lt;p&gt;git --version&lt;/p&gt;

&lt;p&gt;You'll see averion of the git you have installed if you don't install one before moving to the next step.&lt;br&gt;
Then switch to &lt;strong&gt;Git bash&lt;/strong&gt; and generate the key:&lt;/p&gt;

&lt;p&gt;ssh-keygen -t ed25519 -C "&lt;a href="mailto:your_email@example.com"&gt;your_email@example.com&lt;/a&gt;"&lt;/p&gt;

&lt;p&gt;We get where to save it and prompted to set a passphrase,you can add a passphrase  or skip it and while adding you won't see it add it will be added once you type.&lt;/p&gt;

&lt;p&gt;Back to &lt;strong&gt;powershell&lt;/strong&gt; as &lt;strong&gt;Administrator&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;Get-Service -Name ssh-agent&lt;/p&gt;

&lt;p&gt;Start-Service ssh-agent&lt;/p&gt;

&lt;p&gt;On powershell close that admin window and open a regular PowerShell window. Add your key to the running agent:&lt;/p&gt;

&lt;p&gt;ssh-add C:/Users/YOUR_USERNAME/.ssh/id_ed25519&lt;/p&gt;

&lt;h2&gt;
  
  
  Add SSH key to GitHub account
&lt;/h2&gt;

&lt;p&gt;copy it manually from you git bash.&lt;/p&gt;

&lt;p&gt;On GitHub, go to Settings → SSH and GPG keys → New SSH key. Give it a descriptive title (your PC name) leave the key type as Authentication Key, paste in what you copied and save.&lt;/p&gt;

&lt;p&gt;Back in Git Bash, inside your project folder run this commands:&lt;/p&gt;

&lt;p&gt;git init&lt;/p&gt;

&lt;p&gt;git remote add origin &lt;a href="mailto:git@github.com"&gt;git@github.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;git add .&lt;/p&gt;

&lt;p&gt;git commit -m " "&lt;/p&gt;

&lt;p&gt;Meaning of each command that helps push a project to gitHub:&lt;/p&gt;

&lt;p&gt;git init turns the folder into a Git repository.&lt;/p&gt;

&lt;p&gt;git add . adds everything in the current directory for the next commit.&lt;/p&gt;

&lt;p&gt;git commit -m "..." saves it with the message described.&lt;/p&gt;

&lt;p&gt;git push -u origin main sends your commits to GitHub and links your local&lt;/p&gt;

</description>
      <category>ai</category>
      <category>python</category>
      <category>github</category>
      <category>database</category>
    </item>
  </channel>
</rss>
