<?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: Wendy Adika</title>
    <description>The latest articles on DEV Community by Wendy Adika (@wendy_adika_e0949a228a269).</description>
    <link>https://dev.to/wendy_adika_e0949a228a269</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%2F4070908%2Fc2db8dd2-baee-420e-abbb-57fdba86e17b.jpg</url>
      <title>DEV Community: Wendy Adika</title>
      <link>https://dev.to/wendy_adika_e0949a228a269</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/wendy_adika_e0949a228a269"/>
    <language>en</language>
    <item>
      <title>JCars Logistics Business Performance Analysis Using PowerBi</title>
      <dc:creator>Wendy Adika</dc:creator>
      <pubDate>Tue, 29 Sep 2026 14:50:29 +0000</pubDate>
      <link>https://dev.to/wendy_adika_e0949a228a269/jcars-logistics-business-performance-analysis-using-powerbi-16mg</link>
      <guid>https://dev.to/wendy_adika_e0949a228a269/jcars-logistics-business-performance-analysis-using-powerbi-16mg</guid>
      <description>&lt;h2&gt;
  
  
  Introduction.
&lt;/h2&gt;

&lt;p&gt;JCars Logistics imports, sells, and delivers vehicles to customers across different regions in Kenya. &lt;br&gt;
The overaching goal of this analysis to to help JCars Logistics management understand how business is perforrming and the factors that influence that performance. Data cleaning, analysis, visualization and recommendations will be done through Powerbi.&lt;/p&gt;
&lt;h2&gt;
  
  
  Understanding the JCars data set.
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Before working on the data open the JCars_data.csv on excel to get a glimpse and understand the data you will be working on. &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%2Fbibir8euwrkgt5wj1h0i.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%2Fbibir8euwrkgt5wj1h0i.png" alt="JCaars_Raw_dataset" width="800" height="434"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The original dataset has a total of &lt;em&gt;&lt;strong&gt;276 rows(minus the header row) and 32 columns&lt;/strong&gt;&lt;/em&gt; representing the following fields:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Order ID: Unique identifier key for a particular order. &lt;/li&gt;
&lt;li&gt;Order Date: Date a particular order was made.&lt;/li&gt;
&lt;li&gt;Delivery Date: Date delivery was made. &lt;/li&gt;
&lt;li&gt;Customer Name: Name of Purchaser&lt;/li&gt;
&lt;li&gt;Customer Type: Category of customer that made the order&lt;/li&gt;
&lt;li&gt;Customer Age: Age of customer&lt;/li&gt;
&lt;li&gt;Region: The region of purchase&lt;/li&gt;
&lt;li&gt;County: County of purchase&lt;/li&gt;
&lt;li&gt;City: City of Purchase&lt;/li&gt;
&lt;li&gt;Branch: Company Branch&lt;/li&gt;
&lt;li&gt;Sales Rep: Sales representative incharge of the Order.&lt;/li&gt;
&lt;li&gt;Lead source: Category channels or origin where a potential customer first discovers or hears about the business.&lt;/li&gt;
&lt;li&gt;Car Make: The Company that produced the car.&lt;/li&gt;
&lt;li&gt;Car Model: The specific name, series, or product line assigned to the vehicle by the manufacturer.&lt;/li&gt;
&lt;li&gt;Vehicle Type: category body style of vehicle.&lt;/li&gt;
&lt;li&gt;Vehicle Year: Version of vehicle in year form&lt;/li&gt;
&lt;li&gt;Fuel Type: Category source of energy the vehicle’s engine consumes to generate power.
&lt;/li&gt;
&lt;li&gt;Transmission: Mechanical component of a vehicle that transfers power from the engine to the wheels.&lt;/li&gt;
&lt;li&gt;Color: The color of your vehicle purchased.&lt;/li&gt;
&lt;li&gt;Units Sold: How many vehicles sold.&lt;/li&gt;
&lt;li&gt;Unit Selling Price: Original selling price per unit&lt;/li&gt;
&lt;li&gt;Unit Cost: Price after discount&lt;/li&gt;
&lt;li&gt;Discount: Discount in percentage &lt;/li&gt;
&lt;li&gt;Delivery Fee: price customer pays for the final transportation of a vehicle&lt;/li&gt;
&lt;li&gt;Logistics Cost:  internal expense business pays to move vehicles all the way to the final delivery.
&lt;/li&gt;
&lt;li&gt;Payment Method: Category means of Payment.&lt;/li&gt;
&lt;li&gt;Payment Status: Whether payment is completed of pending&lt;/li&gt;
&lt;li&gt;Delivery Status: If vehicle has been delivered&lt;/li&gt;
&lt;li&gt;Customer Rating: Customer satisfaction between 0 and 5&lt;/li&gt;
&lt;li&gt;Review Count: How many reviews were left&lt;/li&gt;
&lt;li&gt;Returned: Whether vehicle was returned&lt;/li&gt;
&lt;li&gt;Revenue Recorded: total amount of money business brings in from selling  vehicles before any expenses are taken out.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Initial Data Profiling
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Rows: &lt;strong&gt;276&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Columns: &lt;strong&gt;32&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Blank cells: &lt;strong&gt;79&lt;/strong&gt; using &lt;code&gt;=countblank(a2:af277)&lt;/code&gt; formula.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Data Quality assessment
&lt;/h3&gt;
&lt;h4&gt;
  
  
  Text inconsistencies
&lt;/h4&gt;

&lt;p&gt;The same category may appear with different casing or spelling. For example, Toyota is represented as &lt;em&gt;Toyota&lt;/em&gt;, &lt;em&gt;toyota&lt;/em&gt;, &lt;em&gt;TOYOTA&lt;/em&gt; and &lt;em&gt;Toyta&lt;/em&gt;. Proper case standardization can fix capitalization, but spelling variants require a mapping table or business rule.&lt;/p&gt;
&lt;h4&gt;
  
  
  Numeric and currency inconsistencies
&lt;/h4&gt;

&lt;p&gt;Price, cost and revenue fields contain values with &lt;code&gt;KSh&lt;/code&gt;, &lt;code&gt;KES&lt;/code&gt;, commas, question marks and &lt;code&gt;M&lt;/code&gt; suffixes. These should be converted into numeric columns in Power Query. Invalid values should be flagged rather than silently treated as zero.&lt;/p&gt;
&lt;h4&gt;
  
  
  Discount inconsistencies
&lt;/h4&gt;

&lt;p&gt;Discount values appear as &lt;code&gt;7%&lt;/code&gt;, &lt;code&gt;0.07&lt;/code&gt;, &lt;code&gt;10%&lt;/code&gt;, words and invalid values such as &lt;code&gt;120%&lt;/code&gt; and negative values. Valid discounts should be standardized to one representation and values outside 0–100% should be investigated.&lt;/p&gt;
&lt;h4&gt;
  
  
  Rating inconsistencies
&lt;/h4&gt;

&lt;p&gt;Ratings appear as both numeric values and strings such as &lt;code&gt;4.5 out of 5&lt;/code&gt;. A clean numeric rating column should be created and validated against the 0–5 range.&lt;/p&gt;
&lt;h4&gt;
  
  
  Date inconsistencies
&lt;/h4&gt;

&lt;p&gt;Order and delivery dates appear in different formats, including numeric date serials. Power Query should convert them using controlled parsing and validation.&lt;/p&gt;
&lt;h2&gt;
  
  
  Data cleaning using Power Query on Powerbi
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;After downloading the JCars_data.csv file, open Powerbi then click on blank report.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;On the ribbon click on get data which will display a dropdown menu, then click on the type of data source your data is on which for our case is text/csv, then choose your exact data file.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Once this is displayed &lt;strong&gt;click on transform data if it needs cleaning. The option of load is mostly use when data is already cleaned and ready for analysis.&lt;/strong&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%2Fqta5lwvmsc9yb6p9h9y3.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%2Fqta5lwvmsc9yb6p9h9y3.png" alt="Transforming data on powerquery" width="800" height="487"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Once you click on transfrom data it will direct you to the power query editor interface.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Cleaning on Power Query
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;To check column quality click on view tab then check on column quality and profile. directly under your header you will see validity, error and empty percentage checks. These will help validate your data during cleaning.&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%2Fmhsrzd0n6ngy15mtwjj8.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%2Fmhsrzd0n6ngy15mtwjj8.png" alt="Column checks" width="799" height="260"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;When a sheet has no  headers, you first click on use first row as headers under the transform group under the home tab as shown using the blue arrow.&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%2F5jl8msbay35w60ielu1a.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%2F5jl8msbay35w60ielu1a.png" alt="First row as headers" width="800" height="81"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;
  
  
  Column Cleaning
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;1. Order id column.&lt;/strong&gt;&lt;br&gt;
As seen earlier on the raw worksheet, our column has inconsistent data format: some are LC1000 others are LCL-1000, ORD1008 and ord1005 hence need for standardization. &lt;br&gt;
&lt;em&gt;Data type needs to be text, in uppercase and without any hyphens, and Blanks to be replaced with Not provided&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Solution:&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Select the whole Order id column by clicking on the header, then right click to display a dropdown list, click on change type and ensure it is text.&lt;/li&gt;
&lt;li&gt;Change column case to upper under the transform option in the dropdown menu once you right click.&lt;/li&gt;
&lt;li&gt;Select replace value then replace all hypens with blanks eg when LCL-1OOO once all hyphens are replaced with blanks will be LCL 1000 then trim your column&lt;/li&gt;
&lt;li&gt; Replace blanks and missing values with Not Provided.
&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%2Faxnres1nqhpeavt1qtwb.png" alt="Replace values" width="800" height="301"&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;2. Date columns.&lt;/strong&gt;&lt;br&gt;
Both the Order date and delivery date have inconcistent formats, with some cells having numbers and diffrent date formats. Another issue could arise in dates like 09/04/2025 where we are not not sure if the date or month come first. We will assume that the numbers in that column represent a date and that all dates 29/03/2016 read as 29th of March 2016.&lt;/p&gt;

&lt;p&gt;On the add column tab, select custom column then on the displayed formula workspace add clean order id as the name of the custom column then use this code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;let&lt;/span&gt;
    &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;Trim&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;From&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="k"&gt;Order&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;])),&lt;/span&gt;

    &lt;span class="k"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
        &lt;span class="n"&gt;if&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;""&lt;/span&gt; &lt;span class="k"&gt;or&lt;/span&gt; &lt;span class="nb"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;Lower&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;"not provided"&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
            &lt;span class="k"&gt;null&lt;/span&gt;

        &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="n"&gt;if&lt;/span&gt; &lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;Is&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="k"&gt;Order&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
            &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddDays&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1899&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;From&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="k"&gt;Order&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;

        &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="n"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;"0"&lt;/span&gt;&lt;span class="p"&gt;..&lt;/span&gt;&lt;span class="nv"&gt;"9"&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
            &lt;span class="n"&gt;try&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddDays&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1899&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;From&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="n"&gt;otherwise&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;

        &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="n"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;Contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;"-"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;and&lt;/span&gt; &lt;span class="nb"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
            &lt;span class="n"&gt;try&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FromText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;"en-US"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;otherwise&lt;/span&gt;
            &lt;span class="n"&gt;try&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FromText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;"en-GB"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;otherwise&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;

        &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="n"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;Contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
            &lt;span class="n"&gt;let&lt;/span&gt;
                &lt;span class="n"&gt;parts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="n"&gt;p1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;try&lt;/span&gt; &lt;span class="n"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FromText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="n"&gt;otherwise&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;p2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;try&lt;/span&gt; &lt;span class="n"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FromText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="n"&gt;otherwise&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;p3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;try&lt;/span&gt; &lt;span class="n"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FromText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="n"&gt;otherwise&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

                &lt;span class="n"&gt;dateResult&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
                    &lt;span class="n"&gt;if&lt;/span&gt; &lt;span class="n"&gt;p1&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt; &lt;span class="k"&gt;and&lt;/span&gt; &lt;span class="n"&gt;p2&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt; &lt;span class="k"&gt;and&lt;/span&gt; &lt;span class="n"&gt;p3&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
                        &lt;span class="n"&gt;if&lt;/span&gt; &lt;span class="n"&gt;p1&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
                            &lt;span class="n"&gt;try&lt;/span&gt; &lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;otherwise&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;
                        &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="n"&gt;if&lt;/span&gt; &lt;span class="n"&gt;p2&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
                            &lt;span class="n"&gt;try&lt;/span&gt; &lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;otherwise&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;
                        &lt;span class="k"&gt;else&lt;/span&gt;
                            &lt;span class="n"&gt;try&lt;/span&gt; &lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;otherwise&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;
                    &lt;span class="k"&gt;else&lt;/span&gt;
                        &lt;span class="k"&gt;null&lt;/span&gt;
            &lt;span class="k"&gt;in&lt;/span&gt;
                &lt;span class="n"&gt;dateResult&lt;/span&gt;

        &lt;span class="k"&gt;else&lt;/span&gt;
            &lt;span class="n"&gt;try&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FromText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;"en-US"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;otherwise&lt;/span&gt;
            &lt;span class="n"&gt;try&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FromText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;"en-GB"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;otherwise&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;
&lt;span class="k"&gt;in&lt;/span&gt;
    &lt;span class="k"&gt;result&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What this does is it handles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Excel serial numbers&lt;br&gt;
45671&amp;gt; actual date&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;DD/MM/YYYY&lt;br&gt;
19/01/2026&amp;gt; 19/01/2026&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;DD-MMM-YY&lt;br&gt;
26-Mar-25&amp;gt; 26/03/2025&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Month-name dates&lt;br&gt;
Feb 15, 2026&amp;gt; 15/02/2026&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;MM/DD/YYYY&lt;br&gt;
02/21/2025&amp;gt; 21/02/2025&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Invalid dates&lt;br&gt;
2026-13-04&amp;gt; null&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Missing values&lt;br&gt;
Not Provided&amp;gt; null&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The same goes for Delivery date. Use the same code but change column name.&lt;br&gt;
Change the clean columns type to date, then remove the original columns and rename the clean ones once you have ensured that the cleaned columns are correct.&lt;br&gt;
Add Date quality checks that check whether order dates come before delivery dates using this code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if [Clean Order Date] = null and [Clean Delivery Date] = null then
    "Both Dates Missing"
else if [Clean Order Date] = null then
    "Order Date Missing"
else if [Clean Delivery Date] = null then
    "Delivery Date Missing"
else if [Clean Order Date] &amp;lt;= [Clean Delivery Date] then
    "Valid"
else
    "Invalid - Order After Delivery"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3. Customer Name Column, Sales rep&lt;/strong&gt;&lt;br&gt;
You can use whichever type of casing to make cleaning faster.&lt;br&gt;
For these columns, Change capitalization to propercase by selecting the column, right click then select capitalize each word, replace blanks and N/A with Not provided. In the column sales rep, we assumed 1 is i hence 1 was replaced with i. &lt;br&gt;
Ensure data type is text.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Customer type, Region, County, City, Lead Source, Car Make, Car Model, Vehicle type, Transmission, Delivery status, payment staus, payment mehtod, returned.&lt;/strong&gt;&lt;br&gt;
Since these are category columns, ensure there are no duplicate categories due to capitalization and spelling inconsistencies by using text cases and replacing similar values with one consistent category name. Also ensure type is text. Replace blanks with Not Provided.&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%2Fhbbswj214u0407x4uqo0.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%2Fhbbswj214u0407x4uqo0.png" alt="customer type quality" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Some of the assumptions and changes made in these columns are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Customer type: Retail is individual, county government is government, dealer is car dealer and ngo is non profit.&lt;/li&gt;
&lt;li&gt;In Region: kisumu region is part of Nyanza region.&lt;/li&gt;
&lt;li&gt;Branch: Main yard is nairobi hq&lt;/li&gt;
&lt;li&gt;Lead source: Tender is associated with government and corporate tender with private sector/commercial business.&lt;/li&gt;
&lt;li&gt;Car Model: BMW x5 is X5&lt;/li&gt;
&lt;li&gt;Transmission: AT,A/T&amp;gt; Automatic and MT,M/T&amp;gt; Manual&lt;/li&gt;
&lt;li&gt;Fuel type: Gasoline was changed to petrol since they are the same.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;5. Customer Age&lt;/strong&gt;&lt;br&gt;
Ensure Age type is whole number and empties are placed by null.&lt;br&gt;
Min age:5&lt;br&gt;
Max age: 121&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%2F3kc7itw5yb7mlijgl7y6.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%2F3kc7itw5yb7mlijgl7y6.png" alt="Customer age" width="800" height="464"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. Vehicle year&lt;/strong&gt;&lt;br&gt;
Create a custom column then use this code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let
    x = Text.Trim(Text.Clean(Text.From([Vehicle Year]))),

    result =
        if x = "" or Text.Lower(x) = "null" or Text.Lower(x) = "not provided" then
            null
        else if Text.Lower(x) = "twenty twenty" then
            2020
        else
            try Number.From(x) otherwise null
in
    result
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then change Custom Vehicle Year to Whole Number.For the Power BI dashboard, keep Vehicle Year as a whole number, not Date, because 2020, 2021, etc. are years of manufacture, not dates.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;7. Color&lt;/strong&gt;&lt;br&gt;
As you standardize the column, you notice the GRE category could either be green or grey. To determine which one gre is part of, I assume its probably the one with more counts. To find this, load your file into power query then create two measure that will calculate count of grey and green.&lt;br&gt;
New measure:&lt;br&gt;
&lt;code&gt;Green count =calculate(COUNTROWS(Jcars_data), Jcars_data[Color] = "Green"&lt;/code&gt;&lt;br&gt;
Do this for grey as well then compare.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;8. Units Sold, Review Count&lt;/strong&gt;&lt;br&gt;
Replace texts with with corresponding numbers where necessary eg one&amp;gt; 1. Replace symbols (-) with blanks and trim column. Replace blanks with null then change type to whole number.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;9. Customer Rating&lt;/strong&gt;&lt;br&gt;
To make data format consistent in this column, replace out of 5. For unique cells like 4.7/5 you can manually remove the /5. Replace 6 and excellent with 5 as assumption made is that excellent and 6 are 5 as 5 is the highest value in this column. ratings with negatives will be nullk instead of assuming.Replace blanks with null then change type to decimal number.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;10. Discount&lt;/strong&gt;&lt;br&gt;
The discount column has different representations of percentages, that is 7% = 7%&lt;br&gt;
0.07 = 7%&lt;br&gt;
7 = 7%&lt;br&gt;
0.15 = 15%&lt;br&gt;
15 = 15%&lt;br&gt;
ten percent = 10%&lt;br&gt;
No Discount = 0%&lt;br&gt;
120% = invalid because it exceeds 100%&lt;br&gt;
-10 = invalid because it is negative&lt;br&gt;
NULL, unknown, Disc, #ERROR, - = missing/invalid&lt;/p&gt;

&lt;p&gt;To clean this, create custom column then use this power query code&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let
    x = Text.Lower(Text.Trim(Text.Clean(Text.From([Discount])))),

    // Convert written percentages into numbers
    wordValue =
        if x = "ten percent" or x = "ten" then "10"
        else if x = "fifteen percent" or x = "fifteen" then "15"
        else if x = "twelve percent" or x = "twelve" then "12"
        else if x = "seven percent" or x = "seven" then "7"
        else if x = "five percent" or x = "five" then "5"
        else if x = "three percent" or x = "three" then "3"
        else if x = "two percent" or x = "two" then "2"
        else if x = "twenty percent" or x = "twenty %" or x = "twenty" then "20"
        else if x = "zero percent" or x = "zero" then "0"
        else if x = "fifteen" then "15"
        else x,

    // Treat "No Discount" and "None" as a genuine 0% discount
    noDiscount =
        if x = "no discount" or x = "none" then
            0
        else
            null,

    // Remove the % sign
    cleanedText = Text.Trim(Text.Replace(wordValue, "%", "")),

    // Convert remaining values to numbers
    numericValue =
        if noDiscount &amp;lt;&amp;gt; null then
            noDiscount
        else if cleanedText = ""
            or cleanedText = "null"
            or cleanedText = "unknown"
            or cleanedText = "disc"
            or cleanedText = "#error"
            or cleanedText = "-"
        then
            null
        else
            try Number.FromText(cleanedText) otherwise null,

    // Convert whole-number percentages to decimals
    decimalValue =
        if numericValue = null then
            null
        else if numericValue &amp;lt; 0 then
            null
        else if numericValue &amp;gt; 1 then
            numericValue / 100
        else
            numericValue,

    // Keep only valid discounts between 0% and 100%
    finalValue =
        if decimalValue &amp;lt;&amp;gt; null
            and decimalValue &amp;gt;= 0
            and decimalValue &amp;lt;= 1
        then
            decimalValue
        else
            null
in
    finalValue
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It  will return the values in decimal number which we will change on Powerbi.&lt;br&gt;
120% was flagged as invalid hence null.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;11. Currency columns&lt;/strong&gt;&lt;br&gt;
For these columns have different curriencies and formats.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Duplicate the original column by rightclicking the column then choosing duplicate column.&lt;/li&gt;
&lt;li&gt;Trim and clean the column: Right click&amp;gt;transform&amp;gt; choose trim, then clean.&lt;/li&gt;
&lt;li&gt;Change NULL, missing, not available and any blanks to null. A missing amount should remain &lt;code&gt;null&lt;/code&gt; not 0.&lt;/li&gt;
&lt;li&gt;Create a &lt;strong&gt;Currency column&lt;/strong&gt; BEFORE removing currency labels because there are different currency labels and some unknown ?,- values.
Name it currency and use this code:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;=  if [#"Delivery Fee - Copy"] = null then null
else if Text.StartsWith(Text.Upper(Text.Trim([#"Delivery Fee - Copy"])), "KSh") then "KES"
else if Text.StartsWith(Text.Upper(Text.Trim([#"Delivery Fee - Copy"])), "KES") then "KES"
else if Text.StartsWith(Text.Upper(Text.Trim([#"Delivery Fee - Copy"])), "$") then "$"
else if Text.StartsWith(Text.Upper(Text.Trim([#"Delivery Fee - Copy"])), "USD") then "$"
else if Text.StartsWith(Text.Upper(Text.Trim([#"Delivery Fee - Copy"])), "R") then "ZAR"
else if Text.StartsWith(Text.Upper(Text.Trim([#"Delivery Fee - Copy"])), "ZAR") then "ZAR"
else if Text.StartsWith(Text.Upper(Text.Trim([#"Delivery Fee - Copy"])), "EUR") then "EUR"
else if Text.StartsWith(Text.Upper(Text.Trim([#"Delivery Fee - Copy"])), "error") then "Unknown"
else if Text.StartsWith(Text.Upper(Text.Trim([#"Delivery Fee - Copy"])), "-") then "Unknown"
else if Text.StartsWith(Text.Trim([#"Delivery Fee - Copy"]), "?") then "Unknown"
else "KES")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The last part say "KES" because your unlabeled values such as 3326000&lt;br&gt;
appear to be Kenyan amounts.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Now remove currency labels from the duplicate unit selling price column by replacing them with nothing.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Remove commas by replacing them with nothing.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;To deal with values like 4.2M where M means million, create a custom column for normalized unit selling price then use this code.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if [#"Unit Selling Price - Copy"] = null then null
else if Text.EndsWith(Text.Upper(Text.Trim([#"Unit Selling Price - Copy"])), "M") then
    Number.From(Text.BeforeDelimiter(Text.Upper(Text.Trim([#"Unit Selling Price - Copy"])), "M")) * 1000000
else
    Number.From(Text.Trim([#"Unit Selling Price - Copy"])))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then Change amount on the normalized column to decimal number.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;To change all our currencies to KES, we need to identify currency, order date and exchange rate in those years.&lt;/li&gt;
&lt;li&gt;I used &lt;a href="https://www.exchange-rates.org/exchange-rate-history/zar-kes-2025" rel="noopener noreferrer"&gt;&lt;/a&gt; to find average exchange rates for years 2025 and 2026
since that is the range on our dates.&lt;/li&gt;
&lt;li&gt;We will use order year to determine exchange rates. To extract year from Order date, select order date column, then on the add column tab selct date then year to create a custom year only order date. &lt;/li&gt;
&lt;li&gt;This table has the currency details that I will use.&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%2Fbscwgad3w6td86qh2i70.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%2Fbscwgad3w6td86qh2i70.png" alt="currency" width="589" height="315"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a custom column that will now convert our differnt currencies to kes using this code,
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if [#"Currency "] = "KES" then [Normalized Custom]
else if [#"Currency "]= "ZAR" and [Year] = 2026 then [Normalized Custom] * 7.89
else if [#"Currency "] = "ZAR" and [Year] = 2025 then [Normalized Custom] * 7.24
else if [#"Currency "] = "EUR" and [Year] = 2026 then [Normalized Custom] * 150.26
else if [#"Currency "] = "EUR" and [Year] = 2025 then [Normalized Custom] * 146.20
else if [#"Currency "] = "$" and [Year] = 2026 then [Normalized Custom] * 129.31
else if [#"Currency "] = "$" and [Year] = 2025 then [Normalized Custom] * 129.31


else
    null)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now change the column's data type to Decimal Number then you can use Amount_KES as your final currency field in Power BI.&lt;/p&gt;

&lt;p&gt;Once all the columns have been cleaned, I will remove duplicates using the order id column since it acts as the primary key for this table by right clicking on the column the selcting remove duplicates.&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%2F0vj1bunh69wo8ulv5ysj.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%2F0vj1bunh69wo8ulv5ysj.png" alt="removing duplicates" width="589" height="315"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;there were a total of 70 dupes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Data modelling
&lt;/h2&gt;

&lt;p&gt;For this dataset, the star schema is the recommended structure for the cleaned JCars dataset.A star schema places a fact table at the centre and descriptive dimensions around it. It provides clear filter paths and supports reusable DAX measures. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;To create and merging fact and dimension tables:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In Power Query, do not modify this original query directly. Instead, create references from it. Right click on the query name on navigation pane on the left of your screen the click on reference. &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%2Futjcupv3o28604qak7nx.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%2Futjcupv3o28604qak7nx.png" alt="query referencing" width="800" height="333"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Choose of the referenced queries be your fact table and rename it. Since we do not have foreign keys in this table, do not delete any columns from it first. eg Fact_orders&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Now create dimension tables using the other referenced queries.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;We will use the vehicles data.&lt;br&gt;
&lt;strong&gt;Creating dimension table&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Create Dim Vehicle by renaming one of the referenced queries.&lt;br&gt;
Keep: Car Make, Car Model, Vehicle Type, Vehicle Year, Fuel Type, Transmission, Color columns.&lt;br&gt;
Remove duplicates&lt;br&gt;
Add Column → Index Column → From 1&lt;br&gt;
Rename Index to Vehicle id&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Merging fact and dimnension table&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Return to Fact_Orders&lt;br&gt;
Home&amp;gt; Merge Queries&lt;br&gt;
Choose your fact table(fact_orders) as your first table &lt;br&gt;
Select Dim Vehicle&lt;br&gt;
Match the 7 vehicle columns, Ensure the columns are chosen in the exact same order.&lt;br&gt;
Choose Left Outerjoin to display all records in the first table and matching rows in the second.&lt;br&gt;
Expand the merged table&lt;br&gt;
Select Vehicle id&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Do the same for the rest of the dimesion table.&lt;/p&gt;

&lt;p&gt;Once you are done, goto your facts table and delete descriptive columns that are are in the corresponding dimension table and only remain with the keys for those tables.&lt;br&gt;
eg on fact table remove customer name , customer type and customer age and only remain with customer id.&lt;/p&gt;

&lt;p&gt;This is our recommended star schema:&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%2F5brp0pq3blbz5l7r15oc.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%2F5brp0pq3blbz5l7r15oc.png" alt="Star schema" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fact_Orders&lt;/strong&gt;&lt;br&gt;
The central fact table should represent one clearly defined sales transaction. Candidate measures include Units Sold, Unit Selling Price, Unit Cost, Discount, Delivery Fee, Logistics Cost and cleaned Revenue Recorded.&lt;/p&gt;

&lt;p&gt;The grain: one row represents one JCars vehicle sales transaction. If the source later contains multiple vehicle lines per order, the grain must be changed to one row per order line.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dim_Customer&lt;/strong&gt;&lt;br&gt;
Contains customer attributes such as Customer Name, Customer Type and Customer Age.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dim_Vehicle&lt;/strong&gt;&lt;br&gt;
Contains Car Make, Car Model, Vehicle Type, Vehicle Year, Fuel Type, Transmission and Color.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dim_Location&lt;/strong&gt;&lt;br&gt;
Contains Region, County, City and Branch.&lt;/p&gt;

&lt;p&gt;Dim_SalesRep&lt;br&gt;
Contains the sales representative and any additional representative attributes added later.&lt;/p&gt;

&lt;h2&gt;
  
  
  Relationships
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;To activate these relationships, load your tables to powerbi then select manage realtionships. Power bi automatically creates the relationships for you and shows cardianlity. The normal relationship pattern is dimension-to-fact one-to-many.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DimCustomer 1 ---- * FactSales
DimVehicle  1 ---- * FactSales
DimDate     1 ---- * FactSales
DimBranch   1 ---- * FactSales
DimSalesRep 1 ---- * FactSales
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then ensure status is active so that filtering is done throughout the whole data set.&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%2Frr5jxtwgveg32tk6jlsw.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%2Frr5jxtwgveg32tk6jlsw.png" alt="Relationship" width="800" height="498"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Filter Direction&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Single-direction filtering should normally flow from dimensions to the fact table. If a user selects &lt;code&gt;Vehicle Type = SUV&lt;/code&gt; in DimVehicle, the filter propagates to Fact_Orders and restricts the measures to SUV transactions.&lt;/p&gt;

&lt;p&gt;For our case we will choose both as our filter direction.&lt;/p&gt;

&lt;h2&gt;
  
  
  Business Logic and Dax
&lt;/h2&gt;

&lt;p&gt;Create the following measures:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Total Revenue: 
Create a new measure by clicking new measure on the ribbon when you click home then use the following formula for analysis.&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%2Fd66sbjmc6mducvfxjp7s.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%2Fd66sbjmc6mducvfxjp7s.png" alt="new measure" width="799" height="241"&gt;&lt;/a&gt;&lt;br&gt;
&lt;code&gt;Total Revenue =&lt;br&gt;
SUM(Fact_Orders[Revenue_Recorded])&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The measure will appear on the data tab on your furthest right as shown using the blue circle.&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%2F001aurfqnx4eud6k5sqt.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%2F001aurfqnx4eud6k5sqt.png" alt="data tab" width="799" height="241"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To display total revenue, click on report view then chose card from the visualizations. Card is marked in pink as shown below.&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%2F68ywzm1x6qj15wkuc7lv.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%2F68ywzm1x6qj15wkuc7lv.png" alt="Card visualization" width="799" height="241"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Drag your measure from the data table where your tables' details are and drop onto the card to display Total revenue. &lt;br&gt;
To ensure the numbers are accurate, ensure you have selected the card, then on the visualization tab select format visual&amp;gt; General&amp;gt; Data Format&amp;gt; Decimal number.  &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%2Faakxt50ilul02ft6wyb0.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%2Faakxt50ilul02ft6wyb0.png" alt="Data Format" width="799" height="305"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Do the same for the rest.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Gross Sales Value: &lt;br&gt;
Create new measure&lt;br&gt;
&lt;code&gt;Gross Sales Value = SUMX(Fact_Orders, Fact_Orders[Units_Sold] * Fact_Orders[Unit_Selling_Price]&lt;br&gt;
)&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Total Vehicle cost:&lt;br&gt;
Create a new measure.&lt;br&gt;
&lt;code&gt;Total Vehicle Cost = SUMX( Fact_Orders,   Fact_Orders[Units_Sold] * Fact_Orders[Unit_Cost]&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Total Delivery Cost:&lt;br&gt;
Create new measure.&lt;br&gt;
&lt;code&gt;Total Delivery Cost = SUM(Fact_Orders[Delivery_Fee])&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Total Logistics cost:&lt;br&gt;
Total Logistics Cost =&lt;br&gt;
&lt;code&gt;SUM(Fact_Orders[Logistics_Cost])&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Total Operating cost:&lt;br&gt;
&lt;code&gt;Total Operating Cost = [Total Vehicle Cost] + [Total Delivery Cost] + [Total Logistics Cost]&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Gross profit:&lt;br&gt;
&lt;code&gt;Gross Profit = [Total Revenue] - [Total Operating Cost]&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Profit Margin %&lt;br&gt;
&lt;code&gt;Profit Margin % = DIVIDE([Gross Profit], [Total Revenue],&lt;br&gt;
0)&lt;/code&gt;&lt;br&gt;
Format as Percentage.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Revenue per unit&lt;br&gt;
Click on Fact_Orders, create new column then use this formula&lt;br&gt;
&lt;code&gt;Revenue per Unit = DIVIDE([Total Revenue], [Units Sold],    0)&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Total Orders&lt;br&gt;
New Measure &amp;gt; &lt;br&gt;
&lt;code&gt;Total Orders = COUNT(Fact_Orders[Order ID])&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Total Customers: &lt;br&gt;
&lt;code&gt;Total Customers = DISTINCTCOUNT(Fact_Orders[Customer_Key])&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is preferable to counting customer names because your fact table can contain multiple orders from the same customer.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Average Customer Rating = AVERAGE(Fact_Orders[Customer_Rating])&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Delivered Orders:&lt;br&gt;
&lt;code&gt;Delivered Orders = CALCULATE([Total Orders],&lt;br&gt;
Fact_Orders[Delivery_Status] = "Delivered")&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Delivery Rate %:&lt;br&gt;
&lt;code&gt;Delivery Rate % = DIVIDE([Delivered Orders],&lt;br&gt;
[Total Orders], 0)&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Cancelled Orders &lt;br&gt;
&lt;code&gt;Cancelled Orders = CALCULATE([Total Orders], Fact_Orders[Delivery_Status] = "Cancelled")&lt;br&gt;
&lt;/code&gt;&lt;br&gt;
&lt;code&gt;Returned Orders =CALCULATE( [Total Orders],&lt;br&gt;
Fact_Orders[Returned] = "True")&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;Return Rate % = DIVIDE([Returned Orders], [Total Orders],&lt;br&gt;
    0)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Paid Orders =&lt;br&gt;
CALCULATE(&lt;br&gt;
    [Total Orders],&lt;br&gt;
    Fact_Orders[Payment_Status] = "completed"&lt;br&gt;
)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Payment Completion Rate % =&lt;br&gt;
DIVIDE(&lt;br&gt;
    [Paid Orders],&lt;br&gt;
    [Total Orders],&lt;br&gt;
    0&lt;br&gt;
)&lt;/code&gt;&lt;/p&gt;

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

&lt;p&gt;Create your dashboards on the report view using charts and slicers.&lt;br&gt;
This is how my dashboard looks like.&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%2Foln28pb34uw02r3hr5uy.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%2Foln28pb34uw02r3hr5uy.png" alt="Eecutive Overview" width="800" height="468"&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%2Fibs65xcn6wpjdqiuc8q9.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%2Fibs65xcn6wpjdqiuc8q9.png" alt="Vehicle Performance" width="800" height="480"&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%2Fpirqzhqybdgb9jswr2v7.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%2Fpirqzhqybdgb9jswr2v7.png" alt="Customers, Sales reps, Channels" width="800" height="490"&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%2Fehq3cs3dht3hk85y2o8s.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%2Fehq3cs3dht3hk85y2o8s.png" alt="Operations and Delivery" width="800" height="432"&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%2Fkvlq39nb0f9x2a006bxu.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%2Fkvlq39nb0f9x2a006bxu.png" alt="Profotability and investigation" width="800" height="461"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Findings and Recommendations
&lt;/h2&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%2F6ovb6luex9v29mv8o7f4.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%2F6ovb6luex9v29mv8o7f4.png" alt=" " width="800" height="476"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you are done. Save the Document and Move it Tto your Local Repo folder.&lt;/p&gt;

&lt;h2&gt;
  
  
  Practical Workflow
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Jcars_data.csv
      |
      v
Data Profiling
      |
      v
Power Query Cleaning
      |
      v
Fact + Dimension Tables
      |
      v
Relationships
      |
      v
DAX Measures
      |
      v
Power BI Report

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

&lt;/div&gt;



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

&lt;h2&gt;
  
  
  15. Conclusion
&lt;/h2&gt;

&lt;p&gt;The JCars dataset demonstrates that effective Power BI reporting starts with data preparation and modelling rather than visual design. Its 276 records and 32 fields contain enough customer, vehicle, location, transaction and operational information to support a rich analytical model, but the inconsistencies in the raw file must first be addressed.&lt;/p&gt;

&lt;p&gt;A star schema provides a clear structure in which FactSales records business events while dimensions provide customer, vehicle, date, branch and sales-representative context. One-to-many relationships provide predictable analytical behaviour. Power Query Merge should be used when data needs to be combined during preparation, whereas model relationships should be used for reusable analytical navigation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pushing to Github
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Open Git bash.&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;pwd&lt;/code&gt; to ensure you are on the right directory.&lt;/li&gt;
&lt;li&gt;use &lt;code&gt;cd&lt;/code&gt; command to navigate to your directory. &lt;/li&gt;
&lt;li&gt;Once on yoour dircetory(Project folder) run &lt;code&gt;ls&lt;/code&gt; to ensure all files needed are there.&lt;/li&gt;
&lt;li&gt;After confirming this run &lt;code&gt;git status&lt;/code&gt; to check the status of your repo.&lt;/li&gt;
&lt;li&gt;run &lt;code&gt;git init&lt;/code&gt;  to initialize your local repo as a Git repo.&lt;/li&gt;
&lt;li&gt;run &lt;code&gt;git status&lt;/code&gt; again to check state of your repo.- It will show files have not yet started being tracked.&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;git add .&lt;/code&gt;  to add the whole folder/ current directory.&lt;/li&gt;
&lt;li&gt;Write a commit message to commit this change using the &lt;code&gt;git commit -m "Add Jcars"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Go to github and create a new repo&amp;gt; copy the ssh address for that repo.&lt;/li&gt;
&lt;li&gt;Go back to git bash and run this command &lt;code&gt;git remote add origin paste the ssh address here.&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;git remote -v&lt;/code&gt; to show the connection between the local and remote repos.&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;git push -u origin main&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Check git status, then refresh your github repo to ensure the repo has been pushed.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>basic</category>
      <category>analytics</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Data Modelling, Relationships &amp; Joins in Power Bi</title>
      <dc:creator>Wendy Adika</dc:creator>
      <pubDate>Sun, 13 Sep 2026 11:29:39 +0000</pubDate>
      <link>https://dev.to/wendy_adika_e0949a228a269/data-modelling-relationships-joins-in-power-bi-2bfk</link>
      <guid>https://dev.to/wendy_adika_e0949a228a269/data-modelling-relationships-joins-in-power-bi-2bfk</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Microsoft Power BI&lt;/strong&gt; is a business intelligence platform used to find insights within an organization's data. It can help connect disparate data sets, transform and clean the data into a data model and create charts or graphs to provide visuals of the data. All of this can be shared with other Power BI users within the organization.&lt;br&gt;
Every Power BI report is only as good as the data model sitting underneath it. Visuals, DAX measures, and refresh performance all trace back to a handful of structural decisions made early on: how tables are shaped, how they relate to one another, and how data is combined before it ever reaches the report canvas. This article works through those decisions using a running sales scenario as a consistent example throughout, before closing with a recommended model design and the reasoning behind it.&lt;/p&gt;

&lt;h2&gt;
  
  
  i). Data Modelling
&lt;/h2&gt;

&lt;p&gt;A data model, at its core, comes down to how tables relate to one another. Each table is responsible for one piece of the data. An example is sales transactions or product details and clear connections that tie those tables together.&lt;/p&gt;

&lt;p&gt;Data Modeling in Power BI is the process of organizing multiple tables and defining relationships between them so that Power BI can efficiently analyze and visualize business data. The main data modelling approaches are flat table, star schema and snowflake schema.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Importance of a well designed data model.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Reporting&lt;/em&gt;: It will organize data into familiar business terms using dimensional structures (like fact and dimension tables) rather than rigid source-system formats. It will prevents conflicting metrics across departments by establishing standardized definitions and relationships.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Dax Calculations&lt;/em&gt;: It eliminates the need for complex, nested filter manipulation (FILTER, EARLIER) by letting relationships handle context automatically.It also prevents common errors like double-counting or incorrect cross-filtering between unrelated tables.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Performance&lt;/em&gt;: It reduces memory consumption and file size by removing unnecessary columns and optimizing data types wich equals to faster load time and efficient storage.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Scalability&lt;/em&gt;: It handles expanding data volumes and historical additions without degrading query response times and makes adding new data sources straightforward because you already have a clear conceptual framework for where new information fits.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Maintainability&lt;/em&gt;: It allows you to modify or expand reporting requirements locally without breaking existing visuals or downstream dashboards.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  1. Flat Table
&lt;/h3&gt;

&lt;p&gt;A flat table stores most or all reporting information in one wide table. For example, a retail dataset could contain OrderID, OrderDate, CustomerID, CustomerName, ProductID, ProductName, Category, Store, Quantity, UnitPrice, Discount, and SalesAmount in every transaction row.&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%2F3k6ietd8xcw1pqodhwpq.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%2F3k6ietd8xcw1pqodhwpq.png" alt="flat table model" width="800" height="214"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Simple to understand: There is nothing to join or relate since everything is visible in one place.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Fast to build for a one-off, small analysis with no ongoing maintenance need.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Straightforward for basic visuals.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Heavy data redundancy&lt;/em&gt;: The same customer or product attributes repeat on every transaction row, inflating file size and memory usage.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Update anomalies&lt;/em&gt;: if a customer's city changes, every historical row for that customer must be updated, or the data becomes inconsistent.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;DAX becomes harder at scale&lt;/em&gt;: Measures that should be simple aggregations end up needing extra logic to avoid double-counting repeated attribute values.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;When it is apprpriate&lt;/strong&gt;:&lt;br&gt;
In Power BI, a flat table can work well for a small dataset because there are fewer relationships and less modelling effort. However, as data grows, repeated customer, product, or location attributes increase redundancy and can make maintenance harder. A flat table also does not naturally express the business separation between facts and dimensions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Performance and complexity implications&lt;/strong&gt;:&lt;br&gt;
Model complexity is low (one table, no relationships), but runtime performance is often poor at scale: wide flat tables compress less efficiently, and repeated text values consume far more memory than the same values stored once in a dimension table and referenced by a numeric key.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Star Schema
&lt;/h3&gt;

&lt;p&gt;A star schema organizes data around a central fact table, connected directly to a set of surrounding dimension tables: one join per dimension, no intermediate tables. Viewed in Power BI's Model View, the fact table sits in the middle with relationship lines radiating outward to each dimension, resembling a star.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0ihk53wx7jj4ox0zmakm.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%2F0ihk53wx7jj4ox0zmakm.png" alt="Star Schema" width="800" height="715"&gt;&lt;/a&gt;&lt;br&gt;
The fact table (FactSales) holds transactional measures and foreign keys. Each dimension table (DimCustomer, DimProduct, DimDate, DimStore) is fully denormalized on its own. For example, DimCustomer holds every customer attribute in one table, with no further breakout into separate store or date tables.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Simple, predictable relationship paths&lt;/em&gt;: Every dimension is exactly one join away from the fact table, which keeps DAX filter logic intuitive.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Strong VertiPaq compression&lt;/em&gt;: Narrow, single-purpose dimension columns with repeated values compress extremely well.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Fast query performance&lt;/em&gt;: Fewer joins mean fewer hops for Power BI to resolve when a report applies a filter.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Easy for report authors to navigate&lt;/em&gt;: Dimension fields are grouped logically and predictably in the field list.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;Some redundancy remains inside each denormalized dimension table (e.g., a city name repeated for every customer in that city), though far less than a flat table.&lt;/li&gt;
&lt;li&gt;Less “textbook normalized” than a snowflake schema, which can matter in strict data-warehousing contexts outside of BI reporting.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;When it is appropriate&lt;/strong&gt;:&lt;br&gt;
The star schema is the recommended default for the overwhelming majority of Power BI reporting models such as sales analysis, financial reporting, operational dashboards because it balances simplicity, performance, and maintainability better than either alternative.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Performance and complexity implications&lt;/strong&gt;:&lt;br&gt;
Star schemas are what Power BI's VertiPaq engine and DAX language are optimized for. Model complexity stays low even as more dimensions are added, and performance scales well because each additional dimension is still just one join away from the fact table.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Snowflake Schema
&lt;/h3&gt;

&lt;p&gt;A snowflake schema takes a star schema's dimension tables and normalizes them further, splitting each into smaller, related sub-dimension tables. Instead of DimCustomer holding city and country directly, those attributes move into separate DimCity and DimCountry tables, connected in a chain back to DimCustomer.&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%2Fjhbab2lswjri5dr8vej4.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%2Fjhbab2lswjri5dr8vej4.png" alt="snowflake schema" width="800" height="669"&gt;&lt;/a&gt;&lt;br&gt;
The fact table still sits at the centre, but some dimensions now require two or more joins to reach. For example, filtering FactSales by Country means passing through DimCustomer &amp;gt; DimCity &amp;gt; DimCountry.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Eliminates redundancy within dimensions: A country name is stored once in DimCountry rather than repeated across every customer row.&lt;/li&gt;
&lt;li&gt;Can reduce dimension table size when a dimension has genuinely hierarchical, highly repetitive attributes shared by many members.&lt;/li&gt;
&lt;li&gt;Familiar to teams coming from traditional, fully normalized relational data-warehouse design.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;More relationships to maintain and reason about, increasing model complexity.&lt;/li&gt;
&lt;li&gt;Multi-hop filter paths can slow query performance, since Power BI must traverse several relationships to filter the fact table from an outer sub-dimension.&lt;/li&gt;
&lt;li&gt;Harder for report authors to navigate because related fields are spread across more tables in the field list.&lt;/li&gt;
&lt;li&gt;Diminishing returns in Power BI specifically: VertiPaq's columnar compression already minimizes much of the storage benefit that snowflaking is meant to achieve in traditional row-based databases.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;When it is appropriate&lt;/strong&gt;:&lt;br&gt;
Snowflaking is worth considering when a dimension is very large and its sub-attributes are reused identically across many other dimensions (a shared DimGeography used by both DimCustomer and DimStore, for instance), or when a data source is already normalized upstream, and further denormalizing it into a full star schema is not practical.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Performance and complexity implications&lt;/strong&gt;:&lt;br&gt;
Snowflake schemas generally increase model complexity and can reduce performance relative to a star schema, because Power BI must resolve longer filter-propagation chains. The storage savings that justify snowflaking in traditional relational databases are largely already achieved by VertiPaq's compression, which weakens the case for snowflaking in most Power BI models.&lt;/p&gt;

&lt;h3&gt;
  
  
  Schema comparison Table
&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%2Fkgure3ywzj1rg1z9pngk.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%2Fkgure3ywzj1rg1z9pngk.png" alt="Schema Comparison Table" width="688" height="326"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  ii). Fact Table and Dimension Table
&lt;/h2&gt;

&lt;p&gt;Star and snowflake schemas both depend on a clear division of labour between two table types: fact tables, which record business events, and dimension tables, which describe the entities involved in those events.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fact Tables
&lt;/h3&gt;

&lt;p&gt;A fact table stores measurable, numeric business events including the things a business wants to sum, average, or count. Typical fact tables include FactSales, FactOrders, and FactTransactions. Each row in a fact table generally represents one occurrence of the tracked event (one sale line, one order line, one transaction) and contains:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Foreign keys pointing to related dimension tables (CustomerKey, ProductKey, DateKey, LocationKey).&lt;/li&gt;
&lt;li&gt;Measures which are numeric values meant to be aggregated, such as SalesAmount, Quantity, or Discount.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A crucial concept for any fact table is its grain. Grain is the level of detail a single row represents. A fact table with a grain of “one row per order line” is very different from one with a grain of “one row per order,” even if both are called FactSales; the grain determines what can and cannot be calculated correctly from the table. Grain should be decided deliberately and kept consistent. Mixing grains within a single fact table (some rows per line item, others pre-aggregated per order) is a common source of double-counting errors in DAX measures.&lt;/p&gt;

&lt;h3&gt;
  
  
  Dimensions table
&lt;/h3&gt;

&lt;p&gt;Dimension tables contain descriptive attributes used to group, filter, and explain facts. Common dimensions include DimCustomer, DimProduct, DimDate, and DimLocation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Measures vs. Descriptive Attributes&lt;/strong&gt;&lt;br&gt;
The distinction between a measure and a descriptive attribute is really a distinction between what belongs in a fact table and what belongs in a dimension table. SalesAmount is a measure: it is meaningful to sum it across thousands of rows. ProductCategory is a descriptive attribute: summing it makes no sense, but grouping and filtering by it does. Keeping measures and descriptive attributes in separate tables is what makes a star schema efficient. Power BI can compress and filter a column of repeated category labels very differently from a column of continuously varying sale amounts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Worked Example: FactSales at the Centre of a Star Schema&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Consider a retail business tracking online sales. A single central fact table, FactSales, records one row per sale line: a SalesID, the numeric SalesAmount and Quantity, and foreign keys to four dimensions. Each dimension supplies the descriptive context needed to make that fact meaningful in a report:&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%2F154b2cjra9r0yvlbdos2.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%2F154b2cjra9r0yvlbdos2.png" alt="FactSales at the centre of a star schema" width="692" height="135"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With this structure, a report can answer “total SalesAmount by Region and Quarter” by summing FactSales while grouping by attributes pulled from DimLocation and DimDate without a single duplicated customer or product name anywhere in the fact table itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  iii). Relationships in PowerBI
&lt;/h2&gt;

&lt;p&gt;A relationship in the Power BI data model is a defined link between two tables, based on a shared column, that tells Power BI how to combine data from both tables when a report requests it. Relationships are what make a star or snowflake schema function as a single connected model rather than a collection of unrelated tables. Without them, filtering DimProduct to a single category would have no effect on FactSales at all.&lt;br&gt;
The diagram below shows the different types of relationships.&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%2F2yrifldndqrtufpkmyrk.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%2F2yrifldndqrtufpkmyrk.png" alt="Relationships types in powerbi" width="799" height="228"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  One-to-Many (1:*)
&lt;/h3&gt;

&lt;p&gt;This is the standard, most common relationship in a star schema: one row in a dimension table (the “1” side) can relate to many rows in a fact table (the “*” side). Example: one product in DimProduct appears on many rows in FactSales. Use this whenever a dimension's key is unique and a related table repeats that key for multiple events. It should not be used when the “one” side is not actually unique. If DimProduct itself contains duplicate ProductKey values, Power BI will raise an ambiguity error or produce a many-to-many relationship.&lt;/p&gt;

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

&lt;p&gt;Each row in one table relates to exactly one row in the other, with unique keys on both sides, for example, DimEmployee and a supplementary DimEmployeeDetail table both keyed by the same unique EmployeeID. This is uncommon in typical star schemas and is generally used only when splitting one logical entity across two physical tables (for security reasons, or because the data arrives from two separate systems).&lt;/p&gt;

&lt;h3&gt;
  
  
  Many-to-Many (&lt;em&gt;:&lt;/em&gt;)
&lt;/h3&gt;

&lt;p&gt;Both sides of the relationship can contain repeated key values. For example, FactSales and a DimPromotion table where a single sale can qualify for multiple promotions, and a single promotion can apply to multiple sales. Many-to-many relationships should be used carefully and sparingly. They can produce ambiguous or unexpectedly inflated aggregation results, and are usually better resolved with an intermediate bridge table that turns the problem back into two clean one-to-many relationships.&lt;/p&gt;

&lt;h3&gt;
  
  
  Primary Keys, Foreign Keys, and Uniqueness
&lt;/h3&gt;

&lt;p&gt;Every relationship in Power BI depends on two roles being clearly assigned:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Primary key&lt;/strong&gt;: A column in a dimension table containing unique values, with no duplicates, that identifies each row (CustomerID in DimCustomer).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Foreign key&lt;/strong&gt;: A column in another table (typically a fact table) that stores those same key values, but is expected to repeat many times, once for every event associated with that dimension member (CustomerID repeated across every row in FactSales for that customer).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is precisely why CustomerID contains unique values in DimCustomer but appears many times as a foreign key in FactSales: DimCustomer holds one row per customer, while FactSales holds one row per sale, and any customer can have many sales.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cardinality, Referential Integrity and Active/Inactive Relationships
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Cardinality&lt;/strong&gt; describes the matching pattern between tables: 1:&lt;em&gt;, 1:1, or *:&lt;/em&gt;. &lt;strong&gt;Referential integrity&lt;/strong&gt; means every foreign key value in the fact table has a matching primary key value in the related dimension table: no “orphan” sales pointing to a CustomerID that does not exist in DimCustomer. Power BI handles violations by grouping unmatched rows under a blank member rather than failing outright, but persistent referential-integrity gaps usually indicate an upstream data-quality problem worth fixing at the source.&lt;br&gt;
A single pair of tables can have more than one plausible relationship eg FactSales might have both an OrderDate and a ShipDate, each of which could relate to DimDate. Power BI allows only one active relationship between two tables at a time (the one used automatically by visuals); any additional relationship must be marked inactive and invoked explicitly in DAX using the USERELATIONSHIP function when a calculation specifically needs the alternate date.&lt;/p&gt;

&lt;h2&gt;
  
  
  iv). Filter Direction
&lt;/h2&gt;

&lt;p&gt;Filter direction determines which way a selection made on one table propagates to affect another, related table. This is set per relationship and is one of the most consequential yet most commonly misunderstood settings in a Power BI model.&lt;br&gt;
The diagram below shows the two filtering directions:&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%2Fpztk1pmfrv9d9khiw6di.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%2Fpztk1pmfrv9d9khiw6di.png" alt="filter directions" width="799" height="278"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;In single-direction filtering, a selection on the “1” side of a relationship (a dimension table) filters the “*” side (the fact table), but not the reverse. For example, selecting “Electronics” in DimProduct filters FactSales down to electronics sales but a selection made directly on FactSales does not filter DimProduct back. This is the default behaviour for one-to-many relationships in Power BI, and it correctly matches how most star schema reporting is meant to work: dimensions drive filters on facts, not the other way around.&lt;/p&gt;

&lt;h3&gt;
  
  
  Bidirectional Filtering
&lt;/h3&gt;

&lt;p&gt;Bidirectional (both-direction) filtering allows the filter to propagate both ways: a selection on DimProduct still filters FactSales, but a selection or calculation touching FactSales can now also filter back onto DimProduct. This is occasionally necessary, for example, to make a slicer built from a fact table correctly limit an unrelated dimension in a many-to-many scenario but it should be applied carefully and only when needed.&lt;/p&gt;

&lt;p&gt;The main risks of overusing bidirectional filtering are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ambiguous filter paths: When multiple bidirectional relationships create more than one possible route between two tables, Power BI may be unable to resolve which path should apply, or may apply one path unexpectedly.&lt;/li&gt;
&lt;li&gt;Unnecessary model complexity: Bidirectional relationships are harder to reason about and debug, since the effect of a single filter can now ripple through the model in ways that are not immediately obvious from looking at a single relationship line.&lt;/li&gt;
&lt;li&gt;Performance cost: Resolving filters in both directions requires more computation than a single, predictable direction.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The general guidance is to leave relationships single-directional by default and enable bidirectional filtering only on a specific relationship, for a specific, well-understood reason but never as a default troubleshooting step when a filter “isn't working.”&lt;/p&gt;

&lt;h2&gt;
  
  
  v) Joins in Power Query
&lt;/h2&gt;

&lt;p&gt;A join (called a Merge Query in Power Query) combines rows from two tables based on matching values in one or more key columns. It is a similar in concept to a SQL join, but performed during data loading and transformation, before the data ever reaches the Power BI data model. Power Query's Merge Queries dialog supports six join kinds, illustrated below using a Customers table and an Orders table.&lt;br&gt;
See figure below.&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%2F69295p52i78yjdzyht4y.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%2F69295p52i78yjdzyht4y.png" alt="joins" width="800" height="521"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Definition&lt;/strong&gt;: keeps every row from the left table (Customers) and attaches matching columns from the right table (Orders) where a match exists; unmatched left rows are kept with nulls in the right-hand columns.&lt;br&gt;
&lt;strong&gt;Retained&lt;/strong&gt;: all left rows, plus matched right rows.&lt;br&gt;
&lt;strong&gt;Example&lt;/strong&gt;: Customers = {Amina, John, Wanjiru}; Orders = {Amina–Order1, John–Order2}. A left outer join on Customer returns Amina with Order1, John with Order2, and Wanjiru with a null order. Wanjiru is not dropped even though she has no order.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Definition&lt;/strong&gt;: the mirror image of a left outer join. It keeps every row from the right table (Orders) and attaches matching columns from the left table (Customers) where a match exists.&lt;br&gt;
&lt;strong&gt;Retained&lt;/strong&gt;: all right rows, plus matched left rows.&lt;br&gt;
&lt;strong&gt;Example&lt;/strong&gt;: using the same tables, if Orders additionally contains an order with no matching customer record (a deleted or missing customer), a right outer join still returns that order, with null customer details attached.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Definition&lt;/strong&gt;: keeps every row from both tables, matching where possible and filling with nulls on whichever side has no match.&lt;br&gt;
&lt;strong&gt;Retained&lt;/strong&gt;: all rows from both Customers and Orders.&lt;br&gt;
&lt;strong&gt;Example&lt;/strong&gt;: the result includes Amina and John with their orders, Wanjiru with a null order, and any order with no matching customer, with null customer details or nothing from either table is dropped.&lt;/p&gt;

&lt;h3&gt;
  
  
  Inner Join
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Definition&lt;/strong&gt;: keeps only rows where a match exists in both tables.&lt;br&gt;
&lt;strong&gt;Retained&lt;/strong&gt;: only matched rows, which is the intersection.&lt;br&gt;
&lt;strong&gt;Example&lt;/strong&gt;: only Amina and John appear in the result, since only they have matching orders; Wanjiru (no order) and any unmatched order are excluded entirely.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Definition&lt;/strong&gt;: keeps only rows from the left table (Customers) that have no match in the right table (Orders); no columns from the right table are attached, since by definition there is nothing to attach.&lt;br&gt;
&lt;strong&gt;Retained&lt;/strong&gt;: unmatched left rows only.&lt;br&gt;
&lt;strong&gt;Example&lt;/strong&gt;: the result is just Wanjiru and is useful for a “customers who have never placed an order” report.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Definition&lt;/strong&gt;: the mirror image of a left anti join. It keeps only rows from the right table (Orders) that have no match in the left table (Customers).&lt;br&gt;
&lt;strong&gt;Retained&lt;/strong&gt;: unmatched right rows only.&lt;br&gt;
&lt;strong&gt;Example&lt;/strong&gt;: the result is only the order with no matching customer record. It is useful for finding orphaned transactions that point to a missing or deleted customer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Join summary table&lt;/em&gt;&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%2Fwn7gx8cl43qmasxnao1i.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%2Fwn7gx8cl43qmasxnao1i.png" alt="Join summary table" width="619" height="191"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  vi). Power Query Join vs Power BI Relationships.
&lt;/h2&gt;

&lt;p&gt;Merging tables in Power Query and creating a relationship in the Power BI data model can look superficially similar because both connect two tables on a matching key but they operate at different stages of the workflow and have very different consequences for the resulting model.&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%2F4ml5ju69znkno3rg38lh.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%2F4ml5ju69znkno3rg38lh.png" alt="Power Query Join vs Power BI Relationships" width="619" height="224"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A merge is the right choice when data genuinely needs to be flattened once upstream for example, resolving a lookup value from a small reference table into a single column before the query is loaded, where creating a full dimension table would be overkill. A relationship is the right choice for connecting a fact table to its dimensions, because it preserves each table's independent structure, avoids duplicating dimension attributes across every fact row, and lets Power BI's filter-propagation engine do the work of applying filters across tables at query time rather than at load time.&lt;br&gt;
Excessive merging pulls a model back toward the flat-table pattern discussed in Section 1: descriptive attributes get copied into transactional rows, redundancy increases, and the model loses the clean separation between facts and dimensions that makes a star schema efficient. Keeping fact and dimension tables separate, connected by relationships rather than merged into one wide table is preferable in a BI model because it keeps redundancy low, keeps each table's grain clean and unambiguous, and lets a single dimension table (like DimDate) be reused across multiple fact tables without being duplicated into each one.&lt;/p&gt;

&lt;h2&gt;
  
  
  vii). Recommended Power BI Model
&lt;/h2&gt;

&lt;p&gt;For a typical business intelligence project like sales, operations, or financial reporting against a fact table connected to a handful of descriptive dimensions(a star schema), connected with single-direction, one-to-many relationships, is the recommended default design.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why a star schema over a flat table&lt;/strong&gt;&lt;br&gt;
A flat table may look simpler at first glance, but it fails on almost every criterion that matters as a report grows: redundancy inflates file size, compression suffers, and DAX measures that look simple can silently double-count values once a single wide table mixes transactional and descriptive data. A star schema solves all three problems by separating facts from dimensions from the outset.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why a star schema over a snowflake schema&lt;/strong&gt;&lt;br&gt;
A snowflake schema's main benefit is reduced redundancy within dimensions. It is only marginally useful in Power BI, because VertiPaq's columnar compression already stores repeated values efficiently. What a snowflake schema does add is more relationships and longer filter-propagation paths, which increase model complexity and can slow down report performance without a corresponding benefit. Snowflaking is only worth the added complexity when a dimension is genuinely very large and its sub-attributes are shared identically across multiple other dimensions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Relationships and filter direction&lt;/strong&gt;&lt;br&gt;
Within the recommended star schema, relationships should be one-to-many between each dimension and the fact table, with the dimension on the “1” side. Filter direction should default to single-direction (dimension &amp;gt; fact), which matches how star schema reporting is meant to work and avoids the ambiguous filter paths that bidirectional relationships can introduce. Bidirectional filtering should be reserved for specific, well justified cases such as a genuine many-to-many scenario resolved through a bridge table rather than applied broadly&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%2Fm7zreme7tc1qvld0skzr.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%2Fm7zreme7tc1qvld0skzr.png" alt="Summary of recommendations" width="618" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;In short, build fact and dimension tables separately, connect them with one-to-many relationships kept single-directional by default, use Power Query merges sparingly and only for genuine upstream flattening needs, and reach for a snowflake schema only when a specific, large, shared dimension clearly justifies the added complexity. This combination gives the best balance of performance, simplicity, and long-term maintainability for the great majority of Power BI reporting projects.&lt;/p&gt;

</description>
      <category>datascience</category>
      <category>tutorial</category>
      <category>beginners</category>
      <category>basic</category>
    </item>
    <item>
      <title>Building a Product Analytics Dashboard from E-Commerce Data: A Jumia Case Study</title>
      <dc:creator>Wendy Adika</dc:creator>
      <pubDate>Sun, 06 Sep 2026 15:48:44 +0000</pubDate>
      <link>https://dev.to/wendy_adika_e0949a228a269/building-a-product-analytics-dashboard-from-e-commerce-data-a-jumia-case-study-2988</link>
      <guid>https://dev.to/wendy_adika_e0949a228a269/building-a-product-analytics-dashboard-from-e-commerce-data-a-jumia-case-study-2988</guid>
      <description>&lt;h2&gt;
  
  
  1. Introduction
&lt;/h2&gt;

&lt;p&gt;E-commerce sites collect huge amounts of listing data, but it's rarely ready to analyze right out of the box. Prices show up as messy text instead of numbers, review counts sometimes don't make logical sense, and ratings are missing more often than you'd expect. This article walks through the full process of turning raw Jumia product listings into a working, interactive Excel dashboard including the data problems I ran into, how I cleaned them, the formulas used to build new analytical fields, and what the data ultimately showed. The goal isn't just to show the final result, but to explain why each decision was made, so the same approach can be reused on similar marketplace data.&lt;/p&gt;

&lt;p&gt;The main question behind this project was easy to ask but harder to answer well: does discounting actually help sellers on Jumia, and if so, how? More specifically: do bigger discounts lead to more customer engagement (reviews), or better perceived quality (ratings)? To answer that, the analysis moved through four stages: getting the raw data in, cleaning and validating it, engineering useful features, and building a dashboard that non-technical people could actually use.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Dataset
&lt;/h2&gt;

&lt;p&gt;The raw dataset consists of 115 rows and six columns as per the Raw_Data   worksheet in the Jumia_product_dashboard.xlsl file. Below are screenshots of the Raw_Data worksheet and field descriptions.&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%2F5zvs3l2e6dli62ksjotb.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%2F5zvs3l2e6dli62ksjotb.png" alt="Raw data screenshot" width="800" height="447"&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%2Fn9tuvftr7m9fkrpkcvwf.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%2Fn9tuvftr7m9fkrpkcvwf.png" alt="Field Descriptions" width="575" height="228"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This dataset is just a single snapshot in time;it doesn't include sales numbers, how old each listing is, or who the seller is. That limits what we can actually claim. The analysis can show that things are related, not that one causes the other. &lt;/p&gt;

&lt;h2&gt;
  
  
  3. Data Quality Assessment
&lt;/h2&gt;

&lt;p&gt;Before any transformation, the raw data was profiled systematically. This produced a data quality audit with the following findings:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;345 price cells were text, not numbers&lt;/strong&gt;. Prices had things like currency symbols, commas, or extra spaces so Excel couldn't do math on them until we cleaned them up.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;58 blank cells in both Review and Ratings&lt;/strong&gt;. These weren't zero they just meant no review or rating existed yet. If they were treated as zero, it would have made every average look much worse than it really was.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;57 review counts were negative&lt;/strong&gt;. A review count can't be negative in real life, so this was likely an error from scraping or exporting the data.&lt;/li&gt;
&lt;li&gt;*&lt;em&gt;57 discount values didn't make sense *&lt;/em&gt;. Discounts should always be between 0% and 100%, so these were probably also export errors.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;3 rows were exact duplicates&lt;/strong&gt;. If left in, they would have been counted twice in every total and average.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;2 prices were written as a range&lt;/strong&gt; (like "100–200") instead of one number, which formulas can't use directly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Column headers weren't consistent with spelling mistakes&lt;/strong&gt;. This seems minor, but it causes real problems once formulas depend on typing the header name exactly right.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  4. Data Cleaning
&lt;/h2&gt;

&lt;p&gt;Before cleaning, I copied the data from Raw_Data sheet to Cleaned_Data sheet and converted the data range to an Excel Table with Ctrl+T and gave it the name &lt;strong&gt;&lt;em&gt;tblProducts.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Removed the 3 duplicate rows.&lt;/strong&gt; They added no new information and would have thrown off every total. 112 Products remained.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Renamed the column headers.&lt;/strong&gt; so they were consistent. This also made them safe to use as table references (like &lt;code&gt;tblproducts[Current Price]&lt;/code&gt;) instead of plain cell ranges.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Formatted prices column&lt;/strong&gt;.Removed KSh, commas, and extra spaces, then convert to a number using this formula. &lt;code&gt;=VALUE(SUBSTITUTE(SUBSTITUTE(B2,"KSh",""),",",""))&lt;/code&gt;
Format cleaned values as KSh #,##0.00&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Turned the price ranges into a midpoint number.&lt;/strong&gt; This keeps the row usable without guessing at an exact figure. I used the average function to do this.
&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%2Fobnhghm2xuuo3fkug8kp.png" alt="Midpoint calculation" width="673" height="72"&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Changed disount column data type&lt;/strong&gt;. Remove %, convert to a number, divide by 100 if necessary, and format as Percentage using the formula below.
&lt;code&gt;=VALUE(SUBSTITUTE(D2,"%",""))/100&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Converted negative review counts to whole numbers.&lt;/strong&gt; Since a negative review count isn't real, it was treated as an error and corrected it rather than deleting the row using the formula below.
&lt;code&gt;=IF(E2="","",ABS(VALUE(E2)))&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Formatted Ratings column&lt;/strong&gt;. Removed  out of 5, converted to a decimal, and leave genuinely missing ratings blank using this formula.
&lt;code&gt;=IF(F2="","",VALUE(SUBSTITUTE(F2," out of 5","")))&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Kept missing Review and Ratings cells as "Missing," not zero.&lt;/strong&gt; This was the most important cleaning decision in the whole project.&lt;/li&gt;
&lt;li&gt;Added checks for Price, Ratings and discounts column using the formulas shown.&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%2Fv01esmmt3r5lnnv0dqd2.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%2Fv01esmmt3r5lnnv0dqd2.png" alt="Price check" width="548" height="55"&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%2Ftecv1l731p1q7pmjhfi9.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%2Ftecv1l731p1q7pmjhfi9.png" alt="Ratings Check" width="533" height="77"&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%2F3g7il4bddpotxjgidlxa.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%2F3g7il4bddpotxjgidlxa.png" alt="Discount Check" width="563" height="85"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Excel formulas and enrichment fields.
&lt;/h2&gt;

&lt;p&gt;Once the numbers were clean, new columns were added to turn raw numbers into useful, easy to read categories.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Discount Amount:&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;=[@[Old Price]]-[@[Current Price]]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rating Category&lt;/strong&gt; (fixed thresholds, since a star rating means the same thing everywhere):&lt;br&gt;
&lt;code&gt;=IF([@Ratings]="","Missing",IF([@Ratings]&amp;lt;3,"Poor",IF([@Ratings]&amp;lt;=4.5,"Average","Excellent")))&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Discount Category&lt;/strong&gt; Chosen to match how discount tiers are usually talked about in retail.&lt;br&gt;
&lt;code&gt;=IF([@Discount]="","Missing",IF([@Discount]&amp;lt;20%,"Low Discount",IF([@Discount]&amp;lt;=40%,"Medium Discount","High Discount")))&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Price Category&lt;/strong&gt; used the dataset's own quartiles that were calculated in the analysis sheet instead of fixed numbers, since "expensive" or "cheap" depends on what's actually in this dataset:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Price_Q1 = QUARTILE.INC(tblproducts[Current Price], 1)
Price_Q3 = QUARTILE.INC(tblproducts[Current Price], 3)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;=IF([@[Current Price]]="","Missing",IF([@[Current Price]]&amp;lt;=Price_Q1,"Low Price",IF([@[Current Price]]&amp;lt;=Price_Q3,"Medium Price","High Price")))&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Customer Engagement&lt;/strong&gt; used the same quartile approach, splitting products into Low, Steady, and Strong engagement.&lt;br&gt;
&lt;code&gt;=IF([@Review]="","Missing",IF([@Review]&amp;lt;=Review_Q1,"Low Engagement",IF([@Review]&amp;lt;=Review_Q3,"Steady Engagement","Strong Engagement")))&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Review Category&lt;/strong&gt; &lt;br&gt;
&lt;code&gt;=IF([@Review]="","Missing",IF([@Review]&amp;lt;=Review_Q1,"Low Reviews",IF([@Review]&amp;lt;=Review_Q3,"Steady Reviews","Many Reviews")))&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Finally, three simple &lt;strong&gt;QC check columns&lt;/strong&gt; were added so problems would show up immediately if new data was ever added. &lt;em&gt;&lt;strong&gt;Price, Ratings and Disounts.&lt;/strong&gt;&lt;/em&gt; &lt;/p&gt;

&lt;h2&gt;
  
  
  6. PivotTable and analysis workflow;
&lt;/h2&gt;

&lt;p&gt;After cleaning, 112 products remained. Summary numbers were calculated directly from the cleaned table.&lt;br&gt;
These were the formulas used:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Total products   =ROWS(tblProducts[Product])&lt;br&gt;
Average current price   =AVERAGE(tblProducts[Current Price])&lt;br&gt;
Average old price   =AVERAGE(tblProducts[Old Price])&lt;br&gt;
Average discount    =AVERAGE(tblProducts[Discount])&lt;br&gt;
Average rating  =AVERAGE(tblProducts[Rating])&lt;br&gt;
Total reviews   =SUM(tblProducts[Review])&lt;br&gt;
Most expensive price    =MAX(tblProducts[Current Price])&lt;br&gt;
Least expensive price   =MIN(tblProducts[Current Price])&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Below is a screenshot of the summary.&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%2Fqhmu4d8bt8c14b37zex9.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%2Fqhmu4d8bt8c14b37zex9.png" alt="Data Summary" width="239" height="203"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Xlookup function was used to find the excat most and least expensive product.&lt;br&gt;
&lt;code&gt;=XLOOKUP(MAX(tblproducts[Current Price]),tblproducts[Current Price],tblproducts[Product])&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Correlation was also tested between the following fields using this formulas:&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;Discount (x) versus review *&lt;/em&gt;(y); -0.136822724&lt;br&gt;
As disount goes up the number of reviews tend to slightly go down but because the value is very close to zero the linear relationship is non-existent. That's worth pausing on, because it goes against the common assumption that bigger discounts automatically mean more customer engagement.&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%2F4emvpwpazrlulktqubck.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%2F4emvpwpazrlulktqubck.png" alt="Discount vs Reviews" width="442" height="72"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ratings (x) versus review (y)&lt;/strong&gt;; 0.057209035&lt;br&gt;
As the product rating increases, the number of reviews tends to increase very slightly.Because the strength of this relationship is so close to zero there is no meaningful linear relationship between the two variables, hence a product's rating does not predict how many reviews it will receive and vice versa.&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%2F1mw6crwb2ub3ofi01jhc.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%2F1mw6crwb2ub3ofi01jhc.png" alt="Ratings vs Review" width="360" height="46"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Current price (x) versus rating (y)&lt;/strong&gt;; 0.110090213&lt;br&gt;
As the current price of a product increases, its rating tends to increase slightly.The relationship is highly minimal. Because the value is so close to zero, price explains only a tiny fraction of the variation in product ratings. You cannot reliably use a product's price to predict its consumer satisfaction rating.&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%2F5w5oe71he8he2vwg4i5p.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%2F5w5oe71he8he2vwg4i5p.png" alt="Current Price vs Ratings" width="395" height="40"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;There are also three line charts for each correlation analysis.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;From there, PivotTables were built on top of the cleaned data. PivotTables act as a middle layer. They make the charts faster to load and let the slicers filter several charts at once without slowing the whole workbook down. &lt;br&gt;
The following are the tables created:&lt;br&gt;
&lt;em&gt;&lt;strong&gt;top 5 and bottom 5 products by rating;&lt;br&gt;
top 10 products by discount;&lt;br&gt;
top 10 products by reviews;&lt;br&gt;
top 10 products by rating;&lt;br&gt;
products with high discounts but low ratings;&lt;br&gt;
products with high discounts but low engagement; and&lt;br&gt;
products with many reviews but average ratings&lt;/strong&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Dashboard Design and Slicer Connections
&lt;/h2&gt;

&lt;p&gt;The dashboard was built so a non-technical person like a category manager could explore the data without ever touching a formula.&lt;/p&gt;

&lt;p&gt;Below are screenshots of the Dashboard.&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%2F8dnor7xmib5g3afjjjto.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%2F8dnor7xmib5g3afjjjto.png" alt="Dahboard 1" width="800" height="426"&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%2Fyci0ms97y19znhu2njj8.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%2Fyci0ms97y19znhu2njj8.png" alt="Dashboard 2" width="800" height="476"&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%2Fnlm02tvdzuufi617ey63.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%2Fnlm02tvdzuufi617ey63.png" alt="Overall dashboard" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The top part of the dashboard is the dashboard title: &lt;strong&gt;Product Performance and Pricing&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;The furthest left side of the board are the &lt;strong&gt;slicers&lt;/strong&gt;; &lt;em&gt;Price category, Rating Category and Discount Category&lt;/em&gt;.  All are connected to every PivotTable behind the charts, so clicking one option filters all the visuals on the sheet at once. Connecting both slicers to all five PivotTables (instead of just one chart each) is what makes the dashboard feel interactive rather than static: a single click updates the whole picture at once. You do this by right clicking on each slicer then reporting connections and choose all tables.&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%2Fdfo1p4cgex881ke4vye1.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%2Fdfo1p4cgex881ke4vye1.png" alt="Report Connections" width="394" height="585"&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%2F90bo50rdix5f3aonvg6c.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%2F90bo50rdix5f3aonvg6c.png" alt="Report connections 2" width="785" height="269"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Eight charts&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Top 10 products by ratings&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Top 10 products by review&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Top 10 products by Discounts&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Discount vs Reviews&lt;/strong&gt;: does a bigger discount mean more reviews?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rating vs Review&lt;/strong&gt;: how does review count change across different rating scores?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Price vs Ratings&lt;/strong&gt;: do more expensive products get rated higher?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rating Mix&lt;/strong&gt;: what share of products fall into each rating category, including "Missing"?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Discount Mix&lt;/strong&gt;: how many products sit in each discount tier?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Insights&lt;/strong&gt;&lt;br&gt;
The insight text box contains findings and recommendations.&lt;/p&gt;

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

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Bigger discounts bring more reviews, but not better ratings.&lt;/strong&gt; High and Medium Discount products get far more total reviews than Low Discount ones, but the correlation check shows this isn't a strong, reliable pattern at the individual product level.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Most products sit in the High Discount group&lt;/strong&gt; (about 63 products, versus 24 in Low Discount)The catalog leans heavily toward deep discounting.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Higher priced products get slightly better ratings&lt;/strong&gt; (about 4.1 vs. 3.75 for the cheapest tier), a small but consistent gap.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A clear "Missing" ratings group exists&lt;/strong&gt;, separate from "Poor": these are simply unrated products, not confirmed bad ones.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Discount size barely predicts review count&lt;/strong&gt; (correlation ≈ −0.14) something else is driving engagement more than the discount itself.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  9. Business Recommendations
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Test smaller discounts on Low Discount products to see if reviews still grow without hurting ratings.&lt;/li&gt;
&lt;li&gt;Check a sample of High Discount listings to see if they're real deals or just aging stock being cleared out.&lt;/li&gt;
&lt;li&gt;Improve photos and descriptions on Low Price listings, where ratings tend to be a bit lower.&lt;/li&gt;
&lt;li&gt;Focus review-request campaigns on "Missing" rated products before worrying about the smaller "Poor" group.&lt;/li&gt;
&lt;li&gt;Don't rely on discount depth alone to grow reviews because the data shows it's a weak lever on its own.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  10. Limitations and Lessons Learned
&lt;/h2&gt;

&lt;p&gt;This dataset has no sales numbers, no listing age, and no seller identity hence "more reviews" can't be read as "more sales," and older listings can't be told apart from genuinely more popular ones. With only 112 cleaned rows, smaller groups (like Low Discount, at about 24 products) carry more uncertainty than larger ones. And because this is a single snapshot, none of these patterns should be treated as fixed facts but starting points for real tests, like controlled discount experiments, not final answers.&lt;/p&gt;

&lt;p&gt;The biggest lesson from this project wasn't about charts or formatting. It was the decision to keep missing ratings labeled as "Missing" instead of quietly treating them as zero or dropping them. That one choice is what let the dashboard tell the difference between a product nobody has rated yet and one people genuinely dislike, a distinction that changes what a seller should actually do next.&lt;/p&gt;

&lt;h2&gt;
  
  
  10.Links
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/wendyadika/Jumia-Dashboard.git" rel="noopener noreferrer"&gt;Github Repo&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/wendyadika/Jumia-Dashboard/tree/c512fd491f32bd9f6a0f156e206ef6209335b47c/Dashboard" rel="noopener noreferrer"&gt;Dashboard file&lt;/a&gt;&lt;/p&gt;

</description>
      <category>datascience</category>
      <category>beginners</category>
      <category>database</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Getting Started with Excel for Data Analytics: From Basics to Data Cleaning.</title>
      <dc:creator>Wendy Adika</dc:creator>
      <pubDate>Thu, 27 Aug 2026 18:14:07 +0000</pubDate>
      <link>https://dev.to/wendy_adika_e0949a228a269/getting-started-with-excel-for-data-analytics-from-basics-to-data-cleaning-2mlo</link>
      <guid>https://dev.to/wendy_adika_e0949a228a269/getting-started-with-excel-for-data-analytics-from-basics-to-data-cleaning-2mlo</guid>
      <description>&lt;h2&gt;
  
  
  What is Excel?
&lt;/h2&gt;

&lt;p&gt;Excel is a spreadsheet program that enables users to capture, organize, calculate and visualize data. Excel is part of Microsoft office and is available for Windows and Mac. Operating systems that can't access excel like Linux will first require installation of a virtual Machine(A software based computer inside another physical computer) through a cloud-service provider like Microsoft Azure, Google Cloud Platform(GCP) or Amazon Web Services(AWS).&lt;/p&gt;

&lt;h2&gt;
  
  
  How Organizations Use Excel.
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Collection and storage of data.&lt;/li&gt;
&lt;li&gt;Data cleaning.&lt;/li&gt;
&lt;li&gt;Data analysis and visualization.&lt;/li&gt;
&lt;li&gt;Performance reporting.&lt;/li&gt;
&lt;li&gt;Accounting.&lt;/li&gt;
&lt;li&gt;Administrative and project management.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Excel User Interface and Components.
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Interface.
&lt;/h3&gt;

&lt;p&gt;When you open excel on your laptop, this is what you essentially see:&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%2Fd2ji9ozpxgszglt4bvke.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%2Fd2ji9ozpxgszglt4bvke.png" alt="Excel Interface" width="800" height="466"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Components of Excel.
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Ribbon&lt;/strong&gt;: A row of tabs that helps you locate and navigate commands. The tabs include Home, Insert, Page Layout, Formulas, Data, Review, View and Help.&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%2Fkt917a120fwfsosf16r1.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%2Fkt917a120fwfsosf16r1.png" alt="Ribbon" width="799" height="106"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Quick Access Toolbar&lt;/strong&gt;: Contains icons for save, undo and redo. Marked blue in the image below is the quick access toolbar.&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%2Fmb7jbwl0woxm0c28bfd5.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%2Fmb7jbwl0woxm0c28bfd5.png" alt="Quick access toolbar" width="800" height="81"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Formula bar&lt;/strong&gt;: Where contents of a selected cell are displayed. The formul bar is circled red in the image below. &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%2Fqdymb7b7f4yt4l1optll.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%2Fqdymb7b7f4yt4l1optll.png" alt="Formula Bar" width="798" height="136"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Worksheet&lt;/strong&gt;: A set of rows and columns.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Column&lt;/strong&gt;: A vertical line of cells labelled in Alphabetical Order(&lt;em&gt;Column A, Column B,C...&lt;/em&gt;)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Row&lt;/strong&gt;: Horizontal line of cells labelled in numerical order( &lt;em&gt;Row 1, Row 2,3...&lt;/em&gt;)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Cell&lt;/strong&gt;: Intersection of a row and column where raw data is captured. It is labelled as column_row(A1, B12)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Worksheet tabs&lt;/strong&gt;: Tabs at the bottom (&lt;em&gt;Original, Cleaned, Sheet2&lt;/em&gt;) that switch between spreadsheets within a workbook
&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%2Fs5tq9w9w2hm4i8owax74.png" alt="worksheet" width="800" height="425"&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Workbook&lt;/strong&gt;- A collection of multiple spreadsheets/worksheets that create an excel file.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Status bar&lt;/strong&gt;: Displays workbook status and quick calculation information. Refer on what it looks like using the image below.&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%2Fkfpsri28rdhc4hqi1e7h.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%2Fkfpsri28rdhc4hqi1e7h.png" alt="status bar" width="800" height="80"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Data Entry and Editing.
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Entering data:
&lt;/h3&gt;

&lt;p&gt;To enter data into a cell, click on any cell then add values. Columns store fields and rows store records. Click enter to move to the next row or the arrow keys to move to whichever cell you want.&lt;br&gt;
See example below:&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%2F1g7jxjf2t3ywafxdl5uw.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%2F1g7jxjf2t3ywafxdl5uw.png" alt="data structure in excel" width="800" height="181"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Data Types:
&lt;/h3&gt;

&lt;p&gt;Some commonly used data types that can be found on the home tab  under number group include:&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%2Fqg0f8alhh6i3bj4d177o.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%2Fqg0f8alhh6i3bj4d177o.png" alt="data types" width="800" height="343"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;General: No specific format&lt;/li&gt;
&lt;li&gt;Text: Words(Gloria)&lt;/li&gt;
&lt;li&gt;Number:2&lt;/li&gt;
&lt;li&gt;Dates: 02/12/2026&lt;/li&gt;
&lt;li&gt;Currency: $280&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Data types are also accessible when you select a cell/cells then right click and choose format cells on the dropdown list that appears.&lt;/p&gt;

&lt;h3&gt;
  
  
  Data formatting in excel:
&lt;/h3&gt;

&lt;p&gt;All data formatting commands are found in the home tab. &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%2F5jcbnmcq87smta3zw84g.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%2F5jcbnmcq87smta3zw84g.png" alt="formatting commands in home tab" width="799" height="81"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;To Format text: Click on home tab then under font group select whatever format you desire. Some format options include Bold(&lt;strong&gt;B&lt;/strong&gt;), Italics(&lt;strong&gt;I&lt;/strong&gt;), Underline(&lt;strong&gt;U&lt;/strong&gt;). You can also change Font type, Font color and Font size.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;To Align cells&amp;gt; Check alignment group.Some alignment options include aligning to either the right, left, center top or bottom, merging cells(combining cells) and wrappint text(moving words to a new line when they reach a margin instead of overflowing. &lt;br&gt;
Normally, when the data type is text, the cell contents are aligned to the left. Numerical data is usually aligned to the right.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;To Format numbers: Check the Number group which contains actions like number types and choose your data type from the dropdown list.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Borders and fill colors: Select your cell range then go to font group and click on the diagram that looks like a window pane. See borders in the image below marked in blue.&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%2Fbtkdo22gkvdyfwqvuu6t.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%2Fbtkdo22gkvdyfwqvuu6t.png" alt="borders" width="470" height="146"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Saving a Workbook:
&lt;/h3&gt;

&lt;p&gt;Different ways to save your workbook:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Click on file then click on save as. Select the directory/folder you want it save in.(eg.Desktop) then write your file name. Make sure the file type is excel workbook/ &lt;strong&gt;&lt;em&gt;.xlsx&lt;/em&gt;&lt;/strong&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%2Fbct0hfdaddyzllzucczp.png" alt="file type" width="679" height="246"&gt;
&lt;/li&gt;
&lt;li&gt;You can also click on the save icon at the quicktool bar at the top left part of the screen. 
&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%2F5u0fkc2d7t2f9s09t7ux.png" alt="Save icon" width="448" height="183"&gt;
&lt;/li&gt;
&lt;li&gt;To save time, use the save shortcut by clicking &lt;strong&gt;&lt;em&gt;ctrl and S&lt;/em&gt;&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Data Sorting and Filtering.
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Sorting:
&lt;/h3&gt;

&lt;p&gt;Sorting means arranging data in a specific order. You can sort &lt;strong&gt;&lt;em&gt;text&lt;/em&gt;&lt;/strong&gt; in alphabetical order(&lt;strong&gt;A-Z&lt;/strong&gt;) or (&lt;strong&gt;Z-A&lt;/strong&gt;), &lt;strong&gt;&lt;em&gt;numerical values&lt;/em&gt;&lt;/strong&gt; from &lt;strong&gt;largest to smallest&lt;/strong&gt; and &lt;strong&gt;vice versa&lt;/strong&gt; and &lt;strong&gt;&lt;em&gt;date&lt;/em&gt;&lt;/strong&gt; from &lt;strong&gt;oldest to newest&lt;/strong&gt; and &lt;strong&gt;vice versa&lt;/strong&gt;.&lt;br&gt;
Sorting helps to make data easier to read, search and manage.&lt;br&gt;
To sort:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Select column or range of cells you want to sort.&lt;/li&gt;
&lt;li&gt;Go to home tab then sort and filter under the editing group.&lt;/li&gt;
&lt;li&gt;Choose what type of sorting you desire. You can also custom sort. Then click ok to run that command.
&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%2Fwb9xnx6wbn6ewc7xckvw.png" alt="sort" width="799" height="81"&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Filtering:
&lt;/h3&gt;

&lt;p&gt;Filtering hides cells that don't meet a certain criteria. It only displays the cells that do. The filer button is at the same place where the sort is. Check the sorting diagram above. &lt;br&gt;
To filter:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Click anywhere on your data set.&lt;/li&gt;
&lt;li&gt;Click on sort&amp;amp;filter on the hometab in the editing group, then click filter.&lt;/li&gt;
&lt;li&gt;A dropdown arrow will appear on the column you want the filter.&lt;/li&gt;
&lt;li&gt;Click on the arrow and choose your filter option. Click ok.
&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%2Fxo2bijfe71uimzzd2rju.png" alt="Filtering" width="557" height="683"&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are three types of filter options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Text Filter: Contains, Begins With, Ends With.....&lt;/li&gt;
&lt;li&gt;Number Filter: Greater Than, Less Than......&lt;/li&gt;
&lt;li&gt;Date Filter: Before, After, Between.....&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Data validation restricts the type of data that can be keyed into a cell in a particular field/column.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Select range of cells you want to validate.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Go to data tab then click on data validation&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%2F9oiwzywu9dh5gbbv39q4.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%2F9oiwzywu9dh5gbbv39q4.png" alt="Data validation" width="800" height="167"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;On the dialog box, select the criteria you want to use.&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%2F0ysy7v1w3v5ga1x1jc4m.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%2F0ysy7v1w3v5ga1x1jc4m.png" alt="data validation dialog box" width="527" height="577"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;An example is when you want your column to only accept K, L and M, you can click on list then add the 3 values. No other value that is not the three will be accepted in that particular column. See demonstration below. &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%2Fz6qj2i4n514b7ml7gvv0.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%2Fz6qj2i4n514b7ml7gvv0.png" alt=" " width="800" height="315"&gt;&lt;/a&gt;&lt;br&gt;
 Any attempt to key in any value that is not in the criteria will bring an error message as shown in the illustration above.&lt;/p&gt;

&lt;h2&gt;
  
  
  Data Cleaning.
&lt;/h2&gt;

&lt;p&gt;Data cleaning is the process of finding and fixing errors, missing values and removing duplicates  in a dataset to make it more accurate and ready for analysis.&lt;/p&gt;

&lt;p&gt;Before cleaning your data, you can perform this actions to make navigation easier:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Autofit: 
When values in cells are cut off showing ###errors, you can first select all data on your workspace using the short cut &lt;em&gt;C*&lt;em&gt;TRL+A&lt;/em&gt;*&lt;/em&gt; then autofit by clicking on the home tab, then on the cells group click format, then click autofit width length as shown below.
&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%2Fod0ozlzr5ii12ccaytpo.png" alt="Autofit" width="800" height="390"&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;2.Freezing Panes:&lt;br&gt;
Freezing panes helps to lock specific rows or columns so that they remain visible as you scroll. This makes it easier to work on the data especially when dealing with a large data set.&lt;br&gt;
Click on the view tab the freeze panes the choose what you intend to freeze, then click ok.&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%2Fgtgnundz9r903bzf5dro.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%2Fgtgnundz9r903bzf5dro.png" alt="Freezing panes" width="799" height="221"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Removing Duplicates:
&lt;/h3&gt;

&lt;p&gt;To remove duplicates,&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Select your complete dataset by clicking the &lt;strong&gt;&lt;em&gt;ctrl+A&lt;/em&gt;&lt;/strong&gt; shortcut.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Go to the Data tab and select remove duplicates. See illustration below.&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%2F2pi0i2bnhugczje69fpf.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%2F2pi0i2bnhugczje69fpf.png" alt="Removing duplicates" width="800" height="151"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In the dialog box, check the columns to consider. Often it is wiser to check all. Then click ok.&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%2F43cspt9umr6shjkwtocx.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%2F43cspt9umr6shjkwtocx.png" alt="Remove duplicates dialog box" width="674" height="554"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Number Formatting:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Number formatting changes how numerical values appear on a spreadsheet without changing the actual data stored in the cell.&lt;/li&gt;
&lt;li&gt;To format number, &lt;/li&gt;
&lt;li&gt;You can select cells then right click to return a dropdown box with a format cells option.
&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%2Flog1pdp0nrskydxeqq1p.png" alt=" " width="800" height="565"&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Select cells then under the home tab go to number group and click on number format bar. These data types are used to show prices(currency), percentages(percentages/%)and dates.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Conditional Formatting:
&lt;/h3&gt;

&lt;p&gt;Conditional Formatting is used to highlight cells that follow a rule that you have set, making it easier to search for a particular value and also spot trends.&lt;br&gt;
To conditional format:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Select cells.&lt;/li&gt;
&lt;li&gt;Go to home bar, under styles group click on conditional formatting.&lt;/li&gt;
&lt;li&gt;Choose the rule you wish to apply. Click ok
&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%2Flnimsw0mx7kzcy3tbvo4.png" alt="Conditional formatting rules" width="696" height="494"&gt;
&lt;/li&gt;
&lt;li&gt;Enter the value you want to highlight then click ok.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Text Functions
&lt;/h3&gt;

&lt;p&gt;Text functions can be used to clean data by addressing issues such as extra spaces, inconsistent text formats, unwanted symbols, or multiple text strings combined in a single cell.&lt;br&gt;
Below are the different text functions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;UPPER&lt;/strong&gt;-Changes all text in selected cell to upper case- Example: If cell k5 contents is "&lt;strong&gt;&lt;em&gt;Grace&lt;/em&gt;&lt;/strong&gt;", when you use the upper function &lt;em&gt;&lt;strong&gt;=UPPER(K5)&lt;/strong&gt;&lt;/em&gt; and run it &lt;strong&gt;&lt;em&gt;GRACE&lt;/em&gt;&lt;/strong&gt; will be displayed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;LOWER&lt;/strong&gt;-Changes all text in selected cell to lower case- Example: If cell k5 contents is "&lt;strong&gt;&lt;em&gt;Grace&lt;/em&gt;&lt;/strong&gt;", when you use the lower function &lt;em&gt;&lt;strong&gt;=LOWER(K5)&lt;/strong&gt;&lt;/em&gt; and run it &lt;strong&gt;&lt;em&gt;grace&lt;/em&gt;&lt;/strong&gt; will be displayed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PROPER&lt;/strong&gt;-Capitalizes the first letter of each word in a cell.If cell k5 contents is "&lt;strong&gt;&lt;em&gt;grace kamau&lt;/em&gt;&lt;/strong&gt;" when you use the proper function &lt;em&gt;&lt;strong&gt;=PROPER(K5)&lt;/strong&gt;&lt;/em&gt; then "&lt;em&gt;&lt;strong&gt;Grcae Kamau&lt;/strong&gt;&lt;/em&gt;" will be displayed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TRIM&lt;/strong&gt;-Removes extra spaces within text. If you &lt;strong&gt;&lt;em&gt;=TRIM( " Grace Kamau "&lt;/em&gt;&lt;/strong&gt; then &lt;strong&gt;&lt;em&gt;"Grace Kamau"&lt;/em&gt;&lt;/strong&gt; will be displayed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;LEFT&lt;/strong&gt;-Extracts leftmost characters. If you =LEFT("Grace,2) then "Gr" will be displayed. Similar to the &lt;strong&gt;RIGHT&lt;/strong&gt; function where if you &lt;strong&gt;&lt;em&gt;=RIGHT("Grace",2)&lt;/em&gt;&lt;/strong&gt; it will display &lt;em&gt;&lt;strong&gt;"ce"&lt;/strong&gt;&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MID&lt;/strong&gt;-Extracts characters from the middle. if you &lt;em&gt;&lt;strong&gt;=MID("Grace", 1)&lt;/strong&gt;&lt;/em&gt; then &lt;strong&gt;&lt;em&gt;"a"&lt;/em&gt;&lt;/strong&gt; is displayed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;LEN&lt;/strong&gt;-Calculates length of text. If you &lt;em&gt;&lt;strong&gt;=LEN("Grace")&lt;/strong&gt;&lt;/em&gt; then &lt;strong&gt;"5"&lt;/strong&gt; is displayed. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;FIND&lt;/strong&gt;-Finds position of a substring. If you &lt;strong&gt;&lt;em&gt;=FIND("a","Grace")&lt;/em&gt;&lt;/strong&gt; the &lt;strong&gt;&lt;em&gt;"3"&lt;/em&gt;&lt;/strong&gt; is displayed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CONCAT&lt;/strong&gt;-Combine two texts from different cells into one. If Grace(k5) and  Kamau(L5) are in different cells you can &lt;strong&gt;&lt;em&gt;=CONCAT(K2," ",L2)&lt;/em&gt;&lt;/strong&gt; then &lt;strong&gt;&lt;em&gt;"Grace Kamau"&lt;/em&gt;&lt;/strong&gt; will be displayed. the &lt;em&gt;" "&lt;/em&gt; on the function is for when you want a single space between the two texts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SUBSTITUTE&lt;/strong&gt;-Replaces a text within a string. If you &lt;strong&gt;&lt;em&gt;=SUBSTITUTE("Grace kamau","  kamau"," Mutua")&lt;/em&gt;&lt;/strong&gt; it will display &lt;strong&gt;&lt;em&gt;"Grace Mutua"&lt;/em&gt;&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Other functions include&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Aggregate functions: &lt;em&gt;SUM, PRODUCT, POWER, MODE, MEDIAN, MAX, MIN, SQRT&lt;/em&gt;
etc.
Statistical functions: &lt;em&gt;COUNT, COUNTA, COUNTBLANK&lt;/em&gt; etc.
Conditional: &lt;em&gt;COUNTIF,SUMIF&lt;/em&gt;....etc.
Date and Time: &lt;em&gt;TODAY,NOW,DAY,MONTH,YEAR,DATEDIF,NETWORKDAYS&lt;/em&gt; etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Formulas.
&lt;/h3&gt;

&lt;p&gt;A formula is an expression in a cell that performs calculations. It must always start with the = sign.&lt;br&gt;
It can include&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cell references(M20)&lt;/li&gt;
&lt;li&gt;Operators(*,+)&lt;/li&gt;
&lt;li&gt;Numbers(45)&lt;/li&gt;
&lt;li&gt;Functions(SUM)
An example: &lt;em&gt;=78+22&lt;/em&gt; which will return &lt;em&gt;100&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;This article has explained the basics of Mircosoft excel including components and the different ways to you can use it to clean data(Sorting and filtering, Data validation, removing duplicates, number formatting). Moreover, you can practice on ai generated unclean date and explore other articles to deepen your skills.&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>analytics</category>
      <category>datascience</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>My First GitHub Project: From a Local Folder to GitHub Using Git and SSH</title>
      <dc:creator>Wendy Adika</dc:creator>
      <pubDate>Thu, 20 Aug 2026 12:20:47 +0000</pubDate>
      <link>https://dev.to/wendy_adika_e0949a228a269/my-first-github-project-from-a-local-folder-to-github-using-git-and-ssh-3bbg</link>
      <guid>https://dev.to/wendy_adika_e0949a228a269/my-first-github-project-from-a-local-folder-to-github-using-git-and-ssh-3bbg</guid>
      <description>&lt;p&gt;This tutorial guides on how to push your local projects to Github using Git and SSH.&lt;/p&gt;

&lt;p&gt;The prerequisite steps are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Installed and configured Git using your user name and email.&lt;/li&gt;
&lt;li&gt;Set up your Github account.&lt;/li&gt;
&lt;li&gt;Generated and added your public ssh key to your Github.&lt;/li&gt;
&lt;li&gt;Tested your ssh connected and make sure it is successful.&lt;/li&gt;
&lt;li&gt;Created a local project with Readme file, data ,scripts and notebooks where applicable.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 1: Project Initialization With Git
&lt;/h2&gt;

&lt;p&gt;Open gitbash terminal. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Before initialization, ensure your location(which is at the end of the path) is the project folder you intend to push.&lt;br&gt;
Run: &lt;br&gt;
&lt;code&gt;pwd&lt;/code&gt; which stands for print working directory. Working directory is the folder you are currently in.&lt;br&gt;
You can move to intended directory using the &lt;code&gt;cd&lt;/code&gt; command.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;To initialize the folder as a Git repo(repository) run:&lt;br&gt;
&lt;code&gt;git init&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This will appear:&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%2F6rbk293lkokn3w42lgwo.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%2F6rbk293lkokn3w42lgwo.png" alt="git innit command" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Also check for git's hidden files by running: &lt;code&gt;ls -la&lt;/code&gt;
You should see &lt;strong&gt;&lt;em&gt;.git&lt;/em&gt;&lt;/strong&gt; among files. &lt;strong&gt;&lt;em&gt;.git&lt;/em&gt;&lt;/strong&gt; folder acts as the git memory.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 2: Check Status
&lt;/h2&gt;

&lt;p&gt;To check the current status of your working directory and staging area run: &lt;br&gt;
&lt;code&gt;git status&lt;/code&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%2Fffxqkuzrd2gf3rp2gjpl.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%2Fffxqkuzrd2gf3rp2gjpl.png" alt="git status command" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Because it is a new project, the files are untracked.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Add
&lt;/h2&gt;

&lt;p&gt;To prepare our project files for the next commit you run:&lt;br&gt;
&lt;code&gt;git add .&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Commit
&lt;/h2&gt;

&lt;p&gt;To save any changes to your project files run: &lt;br&gt;
&lt;code&gt;git commit -m "----"&lt;/code&gt;&lt;br&gt;
Inside the quotes, write a message that explains what was saved.&lt;br&gt;
See example:&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%2Fy6vik4nhc95row8bsh2k.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%2Fy6vik4nhc95row8bsh2k.png" alt="git commit command" width="629" height="63"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Always ensure that the branch is main.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: Pushing to Github
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Create a New Github Repo
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Sign in to your github account.&lt;/li&gt;
&lt;li&gt;Create a new repo- should be empty.&lt;/li&gt;
&lt;li&gt;Fill in new repo form then click on create(Repo name, description and choosing either public or private, the rest you can skip).&lt;/li&gt;
&lt;li&gt;Click on ssh then copy ssh address. &lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Go Back To Gitbash
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Ensure location is still project folder.&lt;/li&gt;
&lt;li&gt;To link your local git repository to  your github repository run:
&lt;code&gt;git remote add origin **the_copied_ssh_address**&lt;/code&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%2Fp63zode8kxczcnglqobp.png" alt="git remote add origin command" width="" height=""&gt;
&lt;/li&gt;
&lt;li&gt;To confirm that Git can send and receive information from the correct github repo run:
&lt;code&gt;git remote -v&lt;/code&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%2Fwnc5svx68kd5qk8nh8xb.png" alt="git remote -v command" width="565" height="61"&gt;
.&lt;/li&gt;
&lt;li&gt;To push your project run:
&lt;code&gt;git push -u origin main&lt;/code&gt;
This means that git has sent any commited changes to your github repository.&lt;/li&gt;
&lt;li&gt;Confirm your project has been pushed to github by refreshing the page.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>git</category>
      <category>githubactions</category>
      <category>ssh</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
