<?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: Bradley Okello</title>
    <description>The latest articles on DEV Community by Bradley Okello (@okbrad).</description>
    <link>https://dev.to/okbrad</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%2F1193393%2F95215c3b-6f80-4826-bb2b-cf3e2853a2a6.jpeg</url>
      <title>DEV Community: Bradley Okello</title>
      <link>https://dev.to/okbrad</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/okbrad"/>
    <language>en</language>
    <item>
      <title>Data Modelling, Relationships and Joins - PowerBI</title>
      <dc:creator>Bradley Okello</dc:creator>
      <pubDate>Sat, 26 Sep 2026 11:17:44 +0000</pubDate>
      <link>https://dev.to/okbrad/data-modelling-relationships-and-joins-powerbi-jo6</link>
      <guid>https://dev.to/okbrad/data-modelling-relationships-and-joins-powerbi-jo6</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;A Power BI report is only as good as the data model behind it. DAX calculations, visual interactions, refresh performance, and long-term maintainability all depend on how tables are structured, related, and filtered. This article explains data modelling concepts in Power BI, compares flat, star, and snowflake schemas, explains fact and dimension tables, covers relationship cardinalities and filter direction, demonstrates Power Query joins, and recommends a practical model design for real-world BI projects.&lt;/p&gt;

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

&lt;p&gt;Data modelling in Power BI means designing the tables, columns, relationships, hierarchies, and measures that form the analytical layer of a report. It is not simply loading data and dragging fields onto a canvas. A good model decides:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which tables should exist.&lt;/li&gt;
&lt;li&gt;What grain each table represents.&lt;/li&gt;
&lt;li&gt;Which columns are keys, attributes, or measures.&lt;/li&gt;
&lt;li&gt;How tables relate to one another.&lt;/li&gt;
&lt;li&gt;How filters should flow.&lt;/li&gt;
&lt;li&gt;Which calculations belong in DAX versus Power Query.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A well-designed model matters because it directly affects:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Reporting&lt;/strong&gt; - Users can slice data intuitively and consistently.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Analytics&lt;/strong&gt; - Business questions are answered with correct aggregations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DAX&lt;/strong&gt; - Measures are simpler and less error-prone.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance&lt;/strong&gt; - Fewer relationships, smaller tables, and efficient scans improve speed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scalability&lt;/strong&gt; - New facts and dimensions can be added without redesign.
Maintainability Logic is centralised and easier to audit.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;h3&gt;
  
  
  Definition
&lt;/h3&gt;

&lt;p&gt;A flat table stores all data in one wide table. Each row contains both descriptive attributes and numeric measures.&lt;/p&gt;

&lt;h3&gt;
  
  
  Structure
&lt;/h3&gt;

&lt;p&gt;All columns - customer name, product name, date, category, quantity, sales amount - live in the same table.&lt;/p&gt;

&lt;h3&gt;
  
  
  FlatSales
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;OrderDate&lt;/th&gt;
&lt;th&gt;CustomerName&lt;/th&gt;
&lt;th&gt;ProductName&lt;/th&gt;
&lt;th&gt;Category&lt;/th&gt;
&lt;th&gt;Quantity&lt;/th&gt;
&lt;th&gt;SalesAmount&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;2026-01-02&lt;/td&gt;
&lt;td&gt;Alice&lt;/td&gt;
&lt;td&gt;Bike&lt;/td&gt;
&lt;td&gt;Bikes&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;500&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2026-01-02&lt;/td&gt;
&lt;td&gt;Alice&lt;/td&gt;
&lt;td&gt;Helmet&lt;/td&gt;
&lt;td&gt;Accessory&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;80&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2026-01-03&lt;/td&gt;
&lt;td&gt;Ben&lt;/td&gt;
&lt;td&gt;Bike&lt;/td&gt;
&lt;td&gt;Bikes&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;700&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

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

&lt;ul&gt;
&lt;li&gt;Simple to create and understand.&lt;/li&gt;
&lt;li&gt;Fast for very small datasets or quick prototypes.&lt;/li&gt;
&lt;li&gt;No relationship design required.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;Heavy redundancy: customer and product details repeat on every row.&lt;/li&gt;
&lt;li&gt;Large file size and slower refresh as data grows.&lt;/li&gt;
&lt;li&gt;Difficult DAX: distinct counts and semi-additive measures become complex.&lt;/li&gt;
&lt;li&gt;Poor scalability and maintainability.&lt;/li&gt;
&lt;li&gt;Filtering is limited because there are no separate dimension tables.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  When Appropriate
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Very small personal reports.&lt;/li&gt;
&lt;li&gt;One-off analysis where the data will not grow.&lt;/li&gt;
&lt;li&gt;Initial data exploration before building a proper model.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Power BI Implications
&lt;/h3&gt;

&lt;p&gt;Power BI can query a flat table, but the model will not take advantage of columnar compression as effectively as a star schema. Report performance and DAX simplicity usually suffer.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Definition
&lt;/h3&gt;

&lt;p&gt;A star schema consists of one or more central fact tables surrounded by dimension tables. It is the most common and recommended schema for Power BI.&lt;/p&gt;

&lt;h3&gt;
  
  
  Structure
&lt;/h3&gt;

&lt;p&gt;The fact table stores business events and numeric measures. Dimension tables store descriptive attributes and connect to the fact table through keys.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sales Schema Diagram
&lt;/h3&gt;



&lt;pre data-lang="mermaid"&gt;&lt;code&gt;erDiagram
    DimDate ||--o{ FactSales : "1:*"
    DimCustomer ||--o{ FactSales : "1:*"
    DimProduct ||--o{ FactSales : "1:*"
    DimLocation ||--o{ FactSales : "1:*"&lt;/code&gt;&lt;/pre&gt;



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

&lt;h3&gt;
  
  
  FactSales
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;DateKey&lt;/th&gt;
&lt;th&gt;CustomerID&lt;/th&gt;
&lt;th&gt;ProductID&lt;/th&gt;
&lt;th&gt;LocationID&lt;/th&gt;
&lt;th&gt;Quantity&lt;/th&gt;
&lt;th&gt;SalesAmount&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;20260102&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;500&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;20260102&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;101&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;80&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;20260103&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;700&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  DimCustomer
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;CustomerID&lt;/th&gt;
&lt;th&gt;CustomerName&lt;/th&gt;
&lt;th&gt;City&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Alice&lt;/td&gt;
&lt;td&gt;Nairobi&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Ben&lt;/td&gt;
&lt;td&gt;Mombasa&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  DimProduct
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ProductID&lt;/th&gt;
&lt;th&gt;ProductName&lt;/th&gt;
&lt;th&gt;Category&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;td&gt;Bike&lt;/td&gt;
&lt;td&gt;Bikes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;101&lt;/td&gt;
&lt;td&gt;Helmet&lt;/td&gt;
&lt;td&gt;Accessory&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

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

&lt;ul&gt;
&lt;li&gt;Excellent Power BI performance due to columnar compression and simple relationships.&lt;/li&gt;
&lt;li&gt;Simple DAX: measures aggregate the fact table and filters flow from dimensions.&lt;/li&gt;
&lt;li&gt;Intuitive for report authors and business users.&lt;/li&gt;
&lt;li&gt;Scalable: new facts and dimensions can be added with minimal disruption.&lt;/li&gt;
&lt;li&gt;Supports conformed dimensions shared across multiple fact tables.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;Requires ETL work to separate facts and dimensions.&lt;/li&gt;
&lt;li&gt;Some redundancy remains in dimension tables, which is usually acceptable.&lt;/li&gt;
&lt;li&gt;Poorly designed dimensions can still cause performance issues.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  When Appropriate
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Most business intelligence projects.&lt;/li&gt;
&lt;li&gt;Any model with multiple business questions, multiple facts, or growth expectations.&lt;/li&gt;
&lt;li&gt;Models using DAX heavily.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Power BI Implications
&lt;/h3&gt;

&lt;p&gt;Power BI’s VertiPaq engine is optimised for star schemas. Relationships are simple, filter propagation is predictable, and DAX is easier to write and tune.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Definition
&lt;/h3&gt;

&lt;p&gt;A snowflake schema is a star schema where dimension tables are normalised into additional related tables.&lt;/p&gt;

&lt;h3&gt;
  
  
  Structure
&lt;/h3&gt;

&lt;p&gt;Instead of one wide DimProduct, product category and department are stored in separate tables.&lt;/p&gt;

&lt;h3&gt;
  
  
  Product Hierarchy Snowflake Schema
&lt;/h3&gt;



&lt;pre data-lang="mermaid"&gt;&lt;code&gt;erDiagram
    FactSales }o--|| DimProduct : "*:1"
    DimProduct }o--|| DimCategory : "*:1"
    DimCategory }o--|| DimDepartment : "*:1"&lt;/code&gt;&lt;/pre&gt;



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

&lt;h3&gt;
  
  
  DimProduct
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ProductID&lt;/th&gt;
&lt;th&gt;ProductName&lt;/th&gt;
&lt;th&gt;CategoryID&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;td&gt;Bike&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;101&lt;/td&gt;
&lt;td&gt;Helmet&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  DimCategory
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;CategoryID&lt;/th&gt;
&lt;th&gt;CategoryName&lt;/th&gt;
&lt;th&gt;DepartmentID&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Bikes&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Accessories&lt;/td&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  DimDepartment
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;DepartmentID&lt;/th&gt;
&lt;th&gt;DepartmentName&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;Outdoor&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;td&gt;Safety&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

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

&lt;ul&gt;
&lt;li&gt;Reduces redundancy in dimension data.&lt;/li&gt;
&lt;li&gt;Can simplify governance when dimensions are very large and shared.&lt;/li&gt;
&lt;li&gt;Useful when source systems are already normalised.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;More tables and relationships increase model complexity.&lt;/li&gt;
&lt;li&gt;DAX may require more relationship navigation.&lt;/li&gt;
&lt;li&gt;Performance can degrade if too many small joins are introduced.&lt;/li&gt;
&lt;li&gt;Report authors may find it harder to locate fields.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  When Appropriate
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Very large dimensions where normalisation saves significant space.&lt;/li&gt;
&lt;li&gt;Enterprise models with shared conformed dimensions.&lt;/li&gt;
&lt;li&gt;Source systems that already provide normalised dimension tables.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Power BI Implications
&lt;/h3&gt;

&lt;p&gt;Power BI can handle snowflake schemas, but the star schema is generally preferred. Snowflake dimensions should be used selectively, and the reporting layer should still feel like a star.&lt;/p&gt;

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

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

&lt;p&gt;Fact tables store numeric business events and foreign keys. They are usually tall and narrow.&lt;/p&gt;

&lt;p&gt;Typical fact table columns:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Foreign keys to dimensions: DateKey, CustomerID, ProductID, LocationID.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Degenerate dimensions: OrderNumber, InvoiceNumber.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Measures: Quantity, SalesAmount, CostAmount, DiscountAmount.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;FactSales&lt;/li&gt;
&lt;li&gt;FactOrders&lt;/li&gt;
&lt;li&gt;FactTransactions&lt;/li&gt;
&lt;li&gt;FactInventory&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Dimension Tables
&lt;/h3&gt;

&lt;p&gt;Dimension tables store descriptive attributes used for slicing and grouping. They are usually shorter and wider.&lt;/p&gt;

&lt;p&gt;Typical dimension table columns:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Primary key: CustomerID, ProductID, DateKey.&lt;/li&gt;
&lt;li&gt;Descriptive attributes: CustomerName, City, Country, ProductName, Category, Year, Month.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;DimCustomer&lt;/li&gt;
&lt;li&gt;DimProduct&lt;/li&gt;
&lt;li&gt;DimDate&lt;/li&gt;
&lt;li&gt;DimLocation&lt;/li&gt;
&lt;li&gt;DimEmployee&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Measures vs Attributes
&lt;/h3&gt;

&lt;p&gt;A measure is a numeric value that can be aggregated, such as SalesAmount. An attribute is a descriptive field used for filtering or grouping, such as ProductCategory or CustomerCity.&lt;/p&gt;

&lt;h3&gt;
  
  
  Grain of a Fact Table
&lt;/h3&gt;

&lt;p&gt;The grain defines what one row in the fact table represents. For example:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;FactSales grain: one row per product per sales order line.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If a row represents an entire order, then quantity and sales amount cannot be analysed by product. Grain must be defined before modelling because it determines which dimensions can relate to the fact table.&lt;/p&gt;

&lt;h3&gt;
  
  
  Practical Star Schema Example
&lt;/h3&gt;

&lt;p&gt;A retail company wants to analyse sales by date, customer, product, and location.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sales Star Schema Diagram
&lt;/h3&gt;



&lt;pre data-lang="mermaid"&gt;&lt;code&gt;erDiagram
    DimCustomer ||--o{ FactSales : "connects to"
    DimProduct ||--o{ FactSales : "connects to"
    DimDate ||--o{ FactSales : "connects to"
    DimLocation ||--o{ FactSales : "connects to"&lt;/code&gt;&lt;/pre&gt;



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

&lt;ul&gt;
&lt;li&gt;DateKey&lt;/li&gt;
&lt;li&gt;CustomerID&lt;/li&gt;
&lt;li&gt;ProductID&lt;/li&gt;
&lt;li&gt;LocationID&lt;/li&gt;
&lt;li&gt;Quantity&lt;/li&gt;
&lt;li&gt;SalesAmount&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;DateKey&lt;/li&gt;
&lt;li&gt;Date&lt;/li&gt;
&lt;li&gt;Year&lt;/li&gt;
&lt;li&gt;Quarter&lt;/li&gt;
&lt;li&gt;Month&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;CustomerID&lt;/li&gt;
&lt;li&gt;CustomerName&lt;/li&gt;
&lt;li&gt;City&lt;/li&gt;
&lt;li&gt;Country&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;ProductID&lt;/li&gt;
&lt;li&gt;ProductName&lt;/li&gt;
&lt;li&gt;Category&lt;/li&gt;
&lt;li&gt;Subcategory&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;DimLocation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;LocationID&lt;/li&gt;
&lt;li&gt;StoreName&lt;/li&gt;
&lt;li&gt;Region&lt;/li&gt;
&lt;li&gt;Country&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This design allows a user to slice SalesAmount by Year, Customer City, Product Category, or Store Region with simple, fast DAX.&lt;/p&gt;

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

&lt;p&gt;A relationship in Power BI connects two tables using common columns, usually a primary key in one table and a foreign key in another. Relationships are necessary because data is distributed across multiple tables. They allow filters to propagate and enable DAX to aggregate related data correctly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Relationship Cardinalities
&lt;/h3&gt;

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

&lt;p&gt;This is the most common relationship.&lt;/p&gt;

&lt;p&gt;How it works:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;One row in the dimension table relates to many rows in the fact table.&lt;/li&gt;
&lt;li&gt;The dimension side contains unique values.&lt;/li&gt;
&lt;li&gt;The fact side can contain repeated values.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;DimCustomer[CustomerID] 1 → * FactSales[CustomerID]&lt;/li&gt;
&lt;li&gt;CustomerID is unique in DimCustomer but appears many times in FactSales.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Customer to Sales Relationship
&lt;/h3&gt;



&lt;pre data-lang="mermaid"&gt;&lt;code&gt;erDiagram
    DimCustomer ||--o{ FactSales : "1:*"

    DimCustomer {
        int CustomerID PK
    }
    FactSales {
        int CustomerID FK
    }&lt;/code&gt;&lt;/pre&gt;



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

&lt;ul&gt;
&lt;li&gt;Almost always between dimensions and facts.&lt;/li&gt;
&lt;li&gt;It is the foundation of a star schema.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When not to use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Avoid if the “one” side is not unique.&lt;/li&gt;
&lt;li&gt;Avoid if the relationship creates ambiguous filter paths.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;How it works:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;One row in each table relates to exactly one row in the other.&lt;/li&gt;
&lt;li&gt;Both sides contain unique values.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;DimEmployee[EmployeeID] 1 ↔ 1 DimEmployeeDetails[EmployeeID]&lt;/p&gt;

&lt;h3&gt;
  
  
  Employee 1-to-1 Relationship
&lt;/h3&gt;



&lt;pre data-lang="mermaid"&gt;&lt;code&gt;erDiagram
    DimEmployee ||--|| DimEmployeeDetails : "1:1"&lt;/code&gt;&lt;/pre&gt;



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

&lt;ul&gt;
&lt;li&gt;Separating optional or sensitive attributes.&lt;/li&gt;
&lt;li&gt;Merging two tables with the same grain when a relationship is preferred over a merge.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When not to use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If the tables can be merged cleanly.&lt;/li&gt;
&lt;li&gt;If it adds complexity without analytical benefit.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;How it works:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Many rows in one table relate to many rows in another.&lt;/li&gt;
&lt;li&gt;Usually implemented through a bridge table.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;Students and Courses. A student takes many courses, and a course has many students.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Student-Course Many-to-Many Relationship
&lt;/h3&gt;



&lt;pre data-lang="mermaid"&gt;&lt;code&gt;erDiagram
    DimStudent ||--o{ BridgeEnrollment : "1:*"
    DimCourse ||--o{ BridgeEnrollment : "1:*"&lt;/code&gt;&lt;/pre&gt;



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

&lt;ul&gt;
&lt;li&gt;True many-to-many business relationships.&lt;/li&gt;
&lt;li&gt;Bridge tables with measures or weighting factors.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When not to use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Avoid direct many-to-many relationships unless necessary.&lt;/li&gt;
&lt;li&gt;They can produce unexpected results and complicated DAX.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Key Concepts
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Primary Key&lt;/strong&gt; - Unique identifier in a dimension table, e.g. DimCustomer[CustomerID].&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Foreign Key&lt;/strong&gt; -Column in a fact table that references a dimension, e.g. FactSales[CustomerID].&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Unique Values&lt;/strong&gt; - Required on the “one” side of a 1:* relationship.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cardinality&lt;/strong&gt; - The number of rows that can relate: 1:*, 1:1, :.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Referential Integrity&lt;/strong&gt; - Every foreign key value should exist in the related primary key table. If not, Power BI may show blank rows.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Active Relationship&lt;/strong&gt; - The default relationship used for filter propagation and DAX.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inactive Relationship&lt;/strong&gt; - A relationship that exists but is not active by default. Used with USERELATIONSHIP in DAX.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example: CustomerID contains unique values in DimCustomer because each customer appears once. It appears multiple times in FactSales because one customer can place many orders. This is a classic 1:* relationship.&lt;/p&gt;

&lt;p&gt;Active and inactive relationships are common with dates. FactSales may have OrderDateKey, ShipDateKey, and DeliveryDateKey. Only one can be active at a time. A measure can use USERELATIONSHIP to activate another date relationship for specific calculations.&lt;/p&gt;

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

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

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

&lt;p&gt;Filters flow from the “one” side to the “many” side.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;DimProduct[Category] filters FactSales.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If a user selects Category = Bikes, Power BI filters DimProduct to Bikes, and that filter propagates to FactSales, showing only bike sales.&lt;/p&gt;

&lt;h3&gt;
  
  
  Product to Sales Relationship (Single Filter Direction)
&lt;/h3&gt;



&lt;pre data-lang="mermaid"&gt;&lt;code&gt;erDiagram
    DimProduct ||--o{ FactSales : "Filters ──&amp;gt;"&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;Single-direction filtering is the default and recommended approach for most star schemas.&lt;/p&gt;

&lt;h4&gt;
  
  
  Both / Bidirectional Filtering
&lt;/h4&gt;

&lt;p&gt;Filters can flow in both directions.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;DimProduct filters FactSales, and FactSales can filter DimProduct.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Bidirectional filtering is sometimes used for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Many-to-many bridge tables.&lt;/li&gt;
&lt;li&gt;Dimension-to-dimension filtering.&lt;/li&gt;
&lt;li&gt;Certain DAX patterns.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;However, it should be used carefully because it can cause:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ambiguous filter paths.&lt;/li&gt;
&lt;li&gt;Unexpected results.&lt;/li&gt;
&lt;li&gt;Slower performance.&lt;/li&gt;
&lt;li&gt;Circular relationship issues.&lt;/li&gt;
&lt;li&gt;Unnecessary model complexity.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example of ambiguity: If DimCustomer and DimProduct both filter FactSales, and FactSales filters both back, Power BI may not know which path should influence the other. This can produce incorrect totals or require complex DAX overrides.&lt;/p&gt;

&lt;p&gt;Best practice: Use single-direction filtering by default. Use bidirectional only when a specific analytical requirement cannot be met otherwise, and document it clearly.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Joins in Power Query
&lt;/h3&gt;

&lt;p&gt;A join combines rows from two tables based on matching column values. In Power BI, joins are performed in Power Query using Merge Queries.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Customers
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;CustID&lt;/th&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;City&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Alice&lt;/td&gt;
&lt;td&gt;Nairobi&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Ben&lt;/td&gt;
&lt;td&gt;Mombasa&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Carol&lt;/td&gt;
&lt;td&gt;Kisumu&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;David&lt;/td&gt;
&lt;td&gt;Eldoret&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Orders
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;OrderID&lt;/th&gt;
&lt;th&gt;CustID&lt;/th&gt;
&lt;th&gt;Amount&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;101&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;500&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;102&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;300&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;103&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;700&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;104&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;105&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;900&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

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

&lt;p&gt;How it works:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Returns all rows from the left table.&lt;/li&gt;
&lt;li&gt;Returns matching rows from the right table.&lt;/li&gt;
&lt;li&gt;Unmatched right columns become null.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Records retained:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;All Customers.&lt;/li&gt;
&lt;li&gt;Matching Orders.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Expected output:&lt;/p&gt;

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

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;CustID&lt;/th&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;OrderID&lt;/th&gt;
&lt;th&gt;Amount&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Alice&lt;/td&gt;
&lt;td&gt;101&lt;/td&gt;
&lt;td&gt;500&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Alice&lt;/td&gt;
&lt;td&gt;102&lt;/td&gt;
&lt;td&gt;300&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Ben&lt;/td&gt;
&lt;td&gt;103&lt;/td&gt;
&lt;td&gt;700&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Carol&lt;/td&gt;
&lt;td&gt;&lt;em&gt;null&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;null&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;David&lt;/td&gt;
&lt;td&gt;104&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Order 105 is excluded because there is no matching customer.&lt;/p&gt;

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

&lt;p&gt;How it works:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Returns all rows from the right table.&lt;/li&gt;
&lt;li&gt;Returns matching rows from the left table.&lt;/li&gt;
&lt;li&gt;Unmatched left columns become null.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Records retained:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;All Orders.&lt;/li&gt;
&lt;li&gt;Matching Customers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Expected output:&lt;/p&gt;

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

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;CustID&lt;/th&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;OrderID&lt;/th&gt;
&lt;th&gt;Amount&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Alice&lt;/td&gt;
&lt;td&gt;101&lt;/td&gt;
&lt;td&gt;500&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Alice&lt;/td&gt;
&lt;td&gt;102&lt;/td&gt;
&lt;td&gt;300&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Ben&lt;/td&gt;
&lt;td&gt;103&lt;/td&gt;
&lt;td&gt;700&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;David&lt;/td&gt;
&lt;td&gt;104&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;em&gt;null&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;null&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;105&lt;/td&gt;
&lt;td&gt;900&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Carol is excluded because she has no order.&lt;/p&gt;

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

&lt;p&gt;How it works:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Returns all rows from both tables.&lt;/li&gt;
&lt;li&gt;Matches where possible.&lt;/li&gt;
&lt;li&gt;Unmatched columns become null.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Records retained:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;All Customers and all Orders.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Expected output:&lt;/p&gt;

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

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;CustID&lt;/th&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;OrderID&lt;/th&gt;
&lt;th&gt;Amount&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Alice&lt;/td&gt;
&lt;td&gt;101&lt;/td&gt;
&lt;td&gt;500&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Alice&lt;/td&gt;
&lt;td&gt;102&lt;/td&gt;
&lt;td&gt;300&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Ben&lt;/td&gt;
&lt;td&gt;103&lt;/td&gt;
&lt;td&gt;700&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Carol&lt;/td&gt;
&lt;td&gt;&lt;em&gt;null&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;null&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;David&lt;/td&gt;
&lt;td&gt;104&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;em&gt;null&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;null&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;105&lt;/td&gt;
&lt;td&gt;900&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h4&gt;
  
  
  Inner Join
&lt;/h4&gt;

&lt;p&gt;How it works:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Returns only rows that match in both tables.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Records retained:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Only matching Customers and Orders.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Expected output:&lt;/p&gt;

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

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;CustID&lt;/th&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;OrderID&lt;/th&gt;
&lt;th&gt;Amount&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Alice&lt;/td&gt;
&lt;td&gt;101&lt;/td&gt;
&lt;td&gt;500&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Alice&lt;/td&gt;
&lt;td&gt;102&lt;/td&gt;
&lt;td&gt;300&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Ben&lt;/td&gt;
&lt;td&gt;103&lt;/td&gt;
&lt;td&gt;700&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;David&lt;/td&gt;
&lt;td&gt;104&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Carol and Order 105 are excluded.&lt;/p&gt;

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

&lt;p&gt;How it works:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Returns rows from the left table that have no match in the right table.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Records retained:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Customers without Orders.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Expected output:&lt;/p&gt;

&lt;h3&gt;
  
  
  Unmatched Customers (Left Anti Join Result)
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;CustID&lt;/th&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;City&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Carol&lt;/td&gt;
&lt;td&gt;Kisumu&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

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

&lt;p&gt;How it works:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Returns rows from the right table that have no match in the left table.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Records retained:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Orders without Customers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Expected output:&lt;/p&gt;

&lt;h3&gt;
  
  
  Orphan Orders (Right Anti Join Result)
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;OrderID&lt;/th&gt;
&lt;th&gt;CustID&lt;/th&gt;
&lt;th&gt;Amount&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;105&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;900&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

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

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

&lt;p&gt;&lt;em&gt;Keeps all customers; unmatched customers get null order details.&lt;/em&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ID&lt;/th&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;OrderID&lt;/th&gt;
&lt;th&gt;CustID&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Alice&lt;/td&gt;
&lt;td&gt;101&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Alice&lt;/td&gt;
&lt;td&gt;102&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Ben&lt;/td&gt;
&lt;td&gt;103&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Carol&lt;/td&gt;
&lt;td&gt;&lt;em&gt;null&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;null&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;David&lt;/td&gt;
&lt;td&gt;104&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

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

&lt;p&gt;&lt;em&gt;Keeps all orders; orphan orders get null customer details.&lt;/em&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ID&lt;/th&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;OrderID&lt;/th&gt;
&lt;th&gt;CustID&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Alice&lt;/td&gt;
&lt;td&gt;101&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Alice&lt;/td&gt;
&lt;td&gt;102&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Ben&lt;/td&gt;
&lt;td&gt;103&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;David&lt;/td&gt;
&lt;td&gt;104&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;em&gt;null&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;null&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;105&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

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

&lt;p&gt;&lt;em&gt;Keeps everything from both tables, filling in nulls where there are no matches.&lt;/em&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ID&lt;/th&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;OrderID&lt;/th&gt;
&lt;th&gt;CustID&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Alice&lt;/td&gt;
&lt;td&gt;101&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Alice&lt;/td&gt;
&lt;td&gt;102&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Ben&lt;/td&gt;
&lt;td&gt;103&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Carol&lt;/td&gt;
&lt;td&gt;&lt;em&gt;null&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;null&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;David&lt;/td&gt;
&lt;td&gt;104&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;em&gt;null&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;null&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;105&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

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

&lt;p&gt;&lt;em&gt;Only returns exact matches between both tables.&lt;/em&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ID&lt;/th&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;OrderID&lt;/th&gt;
&lt;th&gt;CustID&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Alice&lt;/td&gt;
&lt;td&gt;101&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Alice&lt;/td&gt;
&lt;td&gt;102&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Ben&lt;/td&gt;
&lt;td&gt;103&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;David&lt;/td&gt;
&lt;td&gt;104&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

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

&lt;p&gt;&lt;em&gt;Isolates customers who have never placed an order.&lt;/em&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ID&lt;/th&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Carol&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

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

&lt;p&gt;&lt;em&gt;Isolates orphan orders that don't match any customer.&lt;/em&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;OrderID&lt;/th&gt;
&lt;th&gt;CustID&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;105&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;In Power Query: Home → Merge Queries → select matching columns → choose join kind → expand the new table column.&lt;/p&gt;

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

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspect&lt;/th&gt;
&lt;th&gt;Power Query Merge&lt;/th&gt;
&lt;th&gt;Power BI Relationship&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Stage&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Before data is loaded&lt;/td&gt;
&lt;td&gt;After data is loaded, in the model&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Effect&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Physically combines columns/rows into a new query&lt;/td&gt;
&lt;td&gt;Creates metadata linking tables&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Grain&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Can change or duplicate rows&lt;/td&gt;
&lt;td&gt;Preserves table grain&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Storage&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Creates wider tables&lt;/td&gt;
&lt;td&gt;Keeps tables separate&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Filtering&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Not a model filter; it is a transformation&lt;/td&gt;
&lt;td&gt;Enables filter propagation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;DAX&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Not directly used by DAX relationships&lt;/td&gt;
&lt;td&gt;Essential for DAX and visuals&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Use case&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Cleaning, enriching, lookup, creating bridge tables&lt;/td&gt;
&lt;td&gt;Analytical modelling and slicing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Risk&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Excessive merging creates wide, redundant models&lt;/td&gt;
&lt;td&gt;Excessive relationships can create ambiguity&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A Power Query merge physically combines columns from tables. A Power BI relationship does not combine tables; it tells the model how tables are related.&lt;/p&gt;

&lt;p&gt;You would choose a merge when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You need to add lookup columns during ETL.&lt;/li&gt;
&lt;li&gt;You need to create a bridge table.&lt;/li&gt;
&lt;li&gt;You need to flatten a small dimension for a specific report.&lt;/li&gt;
&lt;li&gt;You need to perform anti-join validation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You would choose a relationship when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You want filter propagation.&lt;/li&gt;
&lt;li&gt;You want to keep fact and dimension tables separate.&lt;/li&gt;
&lt;li&gt;You want simple DAX and good performance.&lt;/li&gt;
&lt;li&gt;You want a reusable star schema.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Excessive merging can destroy a good model. It creates wide tables, duplicates data, increases refresh time, and makes DAX harder. Keeping fact and dimension tables separate is usually preferable because it supports a clean star schema, improves compression, and simplifies reporting.&lt;/p&gt;

&lt;h3&gt;
  
  
  7. Recommended Power BI Model
&lt;/h3&gt;

&lt;p&gt;For a typical business intelligence project, I recommend a star schema with conformed dimensions and single-direction relationships.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sales Star Schema Diagram
&lt;/h3&gt;



&lt;pre data-lang="mermaid"&gt;&lt;code&gt;erDiagram
    DimCustomer ||--o{ FactSales : "filters"
    DimProduct ||--o{ FactSales : "filters"
    DimDate ||--o{ FactSales : "filters"
    DimLocation ||--o{ FactSales : "filters"&lt;/code&gt;&lt;/pre&gt;



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

&lt;ul&gt;
&lt;li&gt;DimDate[DateKey] 1 → * FactSales[DateKey]&lt;/li&gt;
&lt;li&gt;DimCustomer[CustomerID] 1 → * FactSales[CustomerID]&lt;/li&gt;
&lt;li&gt;DimProduct[ProductID] 1 → * FactSales[ProductID]&lt;/li&gt;
&lt;li&gt;DimLocation[LocationID] 1 → * FactSales[LocationID]&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Filter direction:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Single-direction from each dimension to the fact table.&lt;/li&gt;
&lt;li&gt;Avoid bidirectional filtering unless a specific many-to-many requirement demands it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Additional practices:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Mark DimDate as a date table.&lt;/li&gt;
&lt;li&gt;Hide primary and foreign keys from report view.&lt;/li&gt;
&lt;li&gt;Use explicit measures instead of implicit aggregations.&lt;/li&gt;
&lt;li&gt;Create bridge tables for many-to-many relationships.&lt;/li&gt;
&lt;li&gt;Use inactive relationships and USERELATIONSHIP for role-playing dimensions such as Order Date and Ship Date.&lt;/li&gt;
&lt;li&gt;Use Power Query merges in staging queries, not as a replacement for the model.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Justification
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Factor&lt;/th&gt;
&lt;th&gt;Star Schema Benefit&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Query and report performance&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Columnar compression and simple relationships scan faster.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;DAX simplicity&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Measures aggregate a single fact table with predictable filters.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Model readability&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Fact and dimension roles are obvious.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Scalability&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;New facts and dimensions can be added easily.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Data redundancy&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Dimension attributes are stored once per dimension.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Maintainability&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;ETL and model logic are easier to audit.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Ease of reporting&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Users see familiar business entities.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Filter propagation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Single-direction filters are predictable.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Model complexity&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Fewer relationships than snowflake, simpler than flat.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A flat table is acceptable only for very small or temporary solutions. A snowflake schema may be useful when dimensions are extremely large or already normalised, but it should be used selectively. The star schema remains the best balance of performance, simplicity, and scalability for Power BI.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Data modelling, relationships, and joins are not isolated technical topics. They are the foundation of a reliable Power BI solution. A flat table is easy but does not scale. A star schema is the standard because it balances performance, DAX simplicity, and maintainability. A snowflake schema can reduce redundancy but adds complexity. Fact tables store measurable events at a defined grain, while dimension tables provide descriptive context. Relationships connect these tables, with 1:* single-direction filtering being the default best practice. Power Query joins are transformation tools, while Power BI relationships are analytical tools. By choosing a star schema, keeping facts and dimensions separate, and using relationships carefully, you create a model that is faster, clearer, and easier to maintain.&lt;/p&gt;

</description>
      <category>datascience</category>
      <category>powerbi</category>
      <category>datamodelling</category>
      <category>data</category>
    </item>
    <item>
      <title>Building an Interactive Excel Dashboard for E-commerce Product Analysis: A Case Study of Jumia Products</title>
      <dc:creator>Bradley Okello</dc:creator>
      <pubDate>Sat, 05 Sep 2026 14:01:29 +0000</pubDate>
      <link>https://dev.to/okbrad/building-an-interactive-excel-dashboard-for-e-commerce-product-analysis-a-case-study-of-jumia-3ab</link>
      <guid>https://dev.to/okbrad/building-an-interactive-excel-dashboard-for-e-commerce-product-analysis-a-case-study-of-jumia-3ab</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In one of my previous articles: &lt;a href="https://dev.to/okbrad/getting-started-with-excel-for-data-analytics-from-basics-to-data-cleaning-202c"&gt;Getting Started with Excel for Data Analytics: From Basics to Data Cleaning&lt;/a&gt; I gave the basics to getting started with excel. This article walks through an end-to-end project: building an interactive Excel dashboard to analyze product performance on Jumia. By analyzing product data, we can understand how discounts, customer reviews, and ratings influence online shopping trends.&lt;/p&gt;

&lt;p&gt;The final deliverable is a professional dashboard that turns raw data into actionable pricing, promotion, and customer-engagement insights, all within Microsoft Excel.&lt;/p&gt;

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

&lt;p&gt;The primary goal is to build &lt;strong&gt;a professional, interactive Excel dashboard&lt;/strong&gt; that transforms raw Jumia product data into useful business intelligence. By the end of this project, stakeholders should be able to answer five core questions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Does a larger discount drive more customer reviews (engagement)&lt;/strong&gt;?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Are highly rated products associated with stronger engagement&lt;/strong&gt;?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;How do price and rating move together&lt;/strong&gt;?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Which products are the best performers based on ratings and reviews&lt;/strong&gt;?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Which products may need a different pricing or marketing strategy&lt;/strong&gt;?&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is not merely a chart-building exercise; it is an analysis project. Every cleaning decision must be traceable, calculations validated, and recommendations grounded in evidence from the workbook.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Dataset and Business Questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Dataset Overview
&lt;/h3&gt;

&lt;p&gt;The dataset (&lt;code&gt;Excel_jumia_dataset.xlsx&lt;/code&gt;) contains &lt;strong&gt;115 product rows&lt;/strong&gt; with the following columns:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Column&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Product&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Product name (text)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Current price&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Selling price in KSh; may include ranges (e.g., &lt;code&gt;"KSh 1,620 - KSh 1,980"&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;old price&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Original price; may also include ranges&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Discount&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Numeric discount fraction (e.g., &lt;code&gt;0.38&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Review&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Number of reviews (stored as negative integers; blanks possible)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Ratingd&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Star rating as text (e.g., &lt;code&gt;"4.5 out of 5"&lt;/code&gt;); blanks possible&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Business Questions
&lt;/h3&gt;

&lt;p&gt;The dashboard is designed to answer the five questions above, each addressing a different aspect of product performance:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Discount vs. Reviews&lt;/strong&gt;: Are price cuts effective at driving customer engagement?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rating vs. Reviews&lt;/strong&gt;: Do better products naturally attract more attention?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Price vs. Rating&lt;/strong&gt;: Is there a relationship between what customers pay and how they perceive quality?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Top/Bottom Performers&lt;/strong&gt;: Which products deserve promotion, and which need improvement?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Strategy Recommendations&lt;/strong&gt;: Which products require pricing or marketing adjustments?&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  3. Initial Data-Quality Audit
&lt;/h2&gt;

&lt;p&gt;Before any analysis, a thorough data-quality audit is essential. As one guide notes, &lt;em&gt;"Most failures start before design: messy source data, unclear metrics, and too many visuals on one sheet"&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Identified Issues
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Issue&lt;/th&gt;
&lt;th&gt;Details&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Price formats&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Current price and old price contain text (&lt;code&gt;"KSh 950"&lt;/code&gt;) and sometimes ranges (&lt;code&gt;"KSh 1,620 - KSh 1,980"&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Review column&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;All non-blank entries are &lt;strong&gt;negative integers&lt;/strong&gt; (e.g., &lt;code&gt;-2&lt;/code&gt;, &lt;code&gt;-55&lt;/code&gt;), which is unconventional&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Rating column&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Stored as text (&lt;code&gt;"4.5 out of 5"&lt;/code&gt;) rather than numeric&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Missing values&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Several rows lack reviews or ratings entirely&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Duplicate rows&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Some products appear multiple times (e.g., "Balloon Insert" appears at least twice)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Summary Statistics (Pre-Cleaning)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Total products: 115&lt;/li&gt;
&lt;li&gt;Products with missing reviews: ~55 rows&lt;/li&gt;
&lt;li&gt;Products with missing ratings: ~55 rows&lt;/li&gt;
&lt;li&gt;Price ranges: KSh 38 to KSh 3,750+&lt;/li&gt;
&lt;li&gt;Discount range: 0.01 to 0.64&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The dataset is &lt;strong&gt;messy but analyzable&lt;/strong&gt;. A perfect sample for demonstrating Excel's data-cleaning capabilities.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. Cleaning and Preparation Decisions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Tools Used
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Power Query&lt;/strong&gt; (Get &amp;amp; Transform) for reproducible, traceable data cleaning&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Excel formulas&lt;/strong&gt; for calculated columns and validation&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Cleaning Steps
&lt;/h3&gt;

&lt;p&gt;Before everything else open a new worksheet and name it &lt;code&gt;cleaned_data&lt;/code&gt;. Copy the top raw data (headers + 116 rows of fields) and paste it into cell A1 of the new sheet created.&lt;/p&gt;

&lt;h4&gt;
  
  
  4.1 Price Columns
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Issue&lt;/strong&gt;: Text with currency symbols and commas; sometimes ranges.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution&lt;/strong&gt;: Extract the &lt;strong&gt;minimum&lt;/strong&gt; price for &lt;code&gt;Current price&lt;/code&gt; and the &lt;strong&gt;maximum&lt;/strong&gt; price for &lt;code&gt;old price&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Power Query: Extract first number from text
= Text.BeforeDelimiter([Current price], " - ")
// Then remove "KSh " and commas, convert to number

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

&lt;/div&gt;



&lt;h4&gt;
  
  
  4.2 Review Column
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Issue&lt;/strong&gt;: Negative integers or blanks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution&lt;/strong&gt;: Convert to positive integers using &lt;code&gt;=**ABS**(Review)&lt;/code&gt;. Treat blanks as &lt;code&gt;0&lt;/code&gt; (no reviews).&lt;/p&gt;

&lt;h4&gt;
  
  
  4.3 Rating Column
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Issue&lt;/strong&gt;: Text format &lt;code&gt;*4.5 out of 5*&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution&lt;/strong&gt;: Extract the numeric part.&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;code&gt;m // Power Query: Extract rating = Number.From(Text.BeforeDelimiter([Ratingd], * *))&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;h4&gt;
  
  
  4.4 Missing Values
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Reviews: Fill blanks with &lt;code&gt;0&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Ratings: Leave as &lt;code&gt;null&lt;/code&gt; (exclude from rating-based analyses)&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  4.5 Duplicates
&lt;/h4&gt;

&lt;p&gt;Remove duplicate rows using Power Query's &lt;em&gt;Remove Duplicates&lt;/em&gt; function.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cleaning Summary
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Before&lt;/th&gt;
&lt;th&gt;After&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Text prices with &lt;em&gt;KSh&lt;/em&gt;
&lt;/td&gt;
&lt;td&gt;Numeric prices (KSh)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Negative reviews&lt;/td&gt;
&lt;td&gt;Positive integers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;*4.5 out of 5*&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;4.5&lt;/code&gt; (numeric)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Blank reviews&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Duplicate rows&lt;/td&gt;
&lt;td&gt;Removed&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  5. Excel Formulas and Enrichment Fields
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Key Formulas Used
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Extract Numeric Price from Text
&lt;/h4&gt;



&lt;p&gt;&lt;code&gt;excel =**VALUE**(**SUBSTITUTE**(**LEFT**(A2, **FIND**(* *, A2)-1), *,*, ""))&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;h4&gt;
  
  
  Extract Rating
&lt;/h4&gt;



&lt;p&gt;&lt;code&gt;excel =**VALUE**(**LEFT**(Ratingd, **FIND**(* *, Ratingd)-1))&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;h4&gt;
  
  
  Convert Negative Reviews
&lt;/h4&gt;



&lt;p&gt;&lt;code&gt;excel =**ABS**(Review)&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;h4&gt;
  
  
  Validate Discount
&lt;/h4&gt;



&lt;p&gt;&lt;code&gt;excel =(old_price - current_price) / old_price&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  Enrichment Fields Added
&lt;/h3&gt;

&lt;p&gt;To enable deeper analysis, I added several calculated columns:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Enrichment Field&lt;/th&gt;
&lt;th&gt;Formula / Logic&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Price_Group&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;IF(current &amp;lt; 500, *Low*, IF(current &amp;lt; 1500, *Medium*, *High*))&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Segment by price tier&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Discount_Group&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;IF(Discount &amp;lt; 0.25, *Low*, IF(Discount &amp;lt; 0.45, *Medium*, *High*))&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Segment by discount level&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Rating_Category&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;IF(Rating &amp;lt; 3, *Poor*, IF(Rating &amp;lt; 4, *Average*, *Excellent*))&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Segment by rating quality&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Performance_Score&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;(Rating * 10) + (Reviews / MAX(Reviews) * 10)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Composite score for ranking&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Absolute_Discount&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;old_price - current_price&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Absolute discount amount&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  6. PivotTable and Analysis Workflow
&lt;/h2&gt;

&lt;h3&gt;
  
  
  PivotTable Setup
&lt;/h3&gt;

&lt;p&gt;PivotTables are the backbone of Excel dashboards as they help you slice, dice, and visualize data with no formulas needed. I created PivotTables on a separate support sheet, following the best practice of keeping them isolated from the dashboard itself.&lt;/p&gt;

&lt;h3&gt;
  
  
  Analysis Workflow
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Load Cleaned Data&lt;/strong&gt;: Power Query loads transformed data into a worksheet table.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Create PivotTables&lt;/strong&gt;: Build separate PivotTables for each analysis:

&lt;ul&gt;
&lt;li&gt;Average price, discount, rating, and total reviews (KPIs)&lt;/li&gt;
&lt;li&gt;Discount vs. Reviews (scatter data)&lt;/li&gt;
&lt;li&gt;Rating vs. Reviews (scatter data)&lt;/li&gt;
&lt;li&gt;Price vs. Rating (scatter data)&lt;/li&gt;
&lt;li&gt;Top/Bottom performers (sorted tables)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Build Charts&lt;/strong&gt;: Connect PivotCharts to each PivotTable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Assemble Dashboard&lt;/strong&gt;: Place charts, KPIs, and slicers on a single dashboard sheet.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Scatter Plot Setup
&lt;/h3&gt;

&lt;p&gt;For correlation analysis (Discount vs. Reviews, Rating vs. Reviews, Price vs. Rating), I used:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;X-axis&lt;/strong&gt;: Independent variable (Discount, Rating, or Price)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Y-axis&lt;/strong&gt;: Dependent variable (Reviews)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Trendline&lt;/strong&gt;: To visualise correlation direction&lt;/li&gt;
&lt;/ul&gt;




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

&lt;h3&gt;
  
  
  Design Principles
&lt;/h3&gt;

&lt;p&gt;Following best practices for dashboard design:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Simplicity&lt;/strong&gt;: Avoid pie charts and 3D charts; prioritise bar, line, and scatter charts&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Information hierarchy&lt;/strong&gt;: Primary KPIs at the top, charts in the middle, filters on the left&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Colour discipline&lt;/strong&gt;: Keep colours to three or fewer&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Clarity&lt;/strong&gt;: Every chart has a clear title and purpose&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Dashboard Layout
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;+----------------------------------------------------------+
|       Jumia Product Performance Dashboard                   |
|       Total: 112  |  Avg Discount: 36.8%  |  Avg Rating: 4.1 |
|       Total Reviews: 723                                    |
+----------------------------------------------------------+
|   [Slicers: Discount Group | Price Group | Rating Category] |
+----------------------------------------------------------+
| Discount vs Reviews  |  Rating vs Reviews  | Price vs Rating |
| (Scatter + Trend)    |  (Scatter + Trend)  | (Scatter + Trend) |
+----------------------------------------------------------+
| Top 10 by Rating     |  Top 10 by Reviews  | Bottom 10 by Perf. |
| (Bar Chart)          |  (Bar Chart)        | (Bar Chart)         |
+----------------------------------------------------------+
|   Key Insights:                                          |
| • No strong correlation between discount and reviews      |
| • High rating doesn't guarantee many reviews              |
| • Top performer: 137-Piece Cake Decorating (4.6, 55)     |
+----------------------------------------------------------+
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Slicer Connections
&lt;/h3&gt;

&lt;p&gt;Slicers provide interactivity, allowing users to filter the entire dashboard dynamically:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Discount Group&lt;/strong&gt; slicer (Low / Medium / High)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Price Group&lt;/strong&gt; slicer (Low / Medium / High)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rating Category&lt;/strong&gt; slicer (Poor / Average / Excellent)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All PivotTables and PivotCharts are connected to the same slicers, ensuring consistent filtering across the dashboard.&lt;/p&gt;




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

&lt;h3&gt;
  
  
  8.1 Discount vs. Reviews
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Finding&lt;/strong&gt;: There is &lt;strong&gt;no strong positive correlation&lt;/strong&gt; between discount size and review count. Products with very high discounts (&amp;gt;50%) often have &lt;strong&gt;low to moderate&lt;/strong&gt; review counts.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Product&lt;/th&gt;
&lt;th&gt;Discount&lt;/th&gt;
&lt;th&gt;Reviews&lt;/th&gt;
&lt;th&gt;Rating&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;137-Piece Cake Decorating&lt;/td&gt;
&lt;td&gt;24%&lt;/td&gt;
&lt;td&gt;55&lt;/td&gt;
&lt;td&gt;4.6&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Electronic Digital Caliper&lt;/td&gt;
&lt;td&gt;35%&lt;/td&gt;
&lt;td&gt;49&lt;/td&gt;
&lt;td&gt;4.6&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3D Waterproof Shower Curtain&lt;/td&gt;
&lt;td&gt;49%&lt;/td&gt;
&lt;td&gt;44&lt;/td&gt;
&lt;td&gt;4.6&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6-in-1 Bottle Opener&lt;/td&gt;
&lt;td&gt;64%&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;N/A&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Insight&lt;/strong&gt;: &lt;strong&gt;Price cuts alone don't guarantee engagement&lt;/strong&gt;. Medium discounts (20–40%) tend to attract more reviews than very high discounts.&lt;/p&gt;

&lt;h3&gt;
  
  
  8.2 Rating vs. Reviews
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Finding&lt;/strong&gt;: High rating does &lt;strong&gt;not guarantee&lt;/strong&gt; many reviews. Some 5-star products have only 1–2 reviews (e.g., Anti-Skid Coaster, Peacock Pillow). Conversely, lower-rated products sometimes have more reviews.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Product&lt;/th&gt;
&lt;th&gt;Rating&lt;/th&gt;
&lt;th&gt;Reviews&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Anti-Skid Coaster&lt;/td&gt;
&lt;td&gt;5.0&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Peacock Pillow&lt;/td&gt;
&lt;td&gt;5.0&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5-PCS Cooking Pot Set&lt;/td&gt;
&lt;td&gt;2.1&lt;/td&gt;
&lt;td&gt;13&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Insight&lt;/strong&gt;: Engagement is driven by factors beyond rating, product category, visibility, and promotion matter more.&lt;/p&gt;

&lt;h3&gt;
  
  
  8.3 Price vs. Rating
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Finding&lt;/strong&gt;: No clear relationship between price and rating. Products at all price points can be highly or poorly rated.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Product&lt;/th&gt;
&lt;th&gt;Price (KSh)&lt;/th&gt;
&lt;th&gt;Rating&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Classic Black Cat Pillow&lt;/td&gt;
&lt;td&gt;171&lt;/td&gt;
&lt;td&gt;5.0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LED Wall Digital Clock&lt;/td&gt;
&lt;td&gt;2,999&lt;/td&gt;
&lt;td&gt;4.6&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;VIC Wireless Vacuum&lt;/td&gt;
&lt;td&gt;1,220&lt;/td&gt;
&lt;td&gt;2.9&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Insight&lt;/strong&gt;: Price does not consistently predict quality perception.&lt;/p&gt;

&lt;h3&gt;
  
  
  8.4 Top Performers
&lt;/h3&gt;

&lt;p&gt;Based on composite scoring (rating + reviews), the top performers are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;137 Piece Cake Decorating Tool&lt;/strong&gt; (4.6, 55 reviews)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Electronic Digital Display Caliper&lt;/strong&gt; (4.6, 49 reviews)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;3D Waterproof Shower Curtain&lt;/strong&gt; (4.6, 44 reviews)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;100 Pcs Crochet Hook Set&lt;/strong&gt; (4.7, 39 reviews)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;LASA Folding Table&lt;/strong&gt; (4.8, 5 reviews)&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  8.5 Underperformers
&lt;/h3&gt;

&lt;p&gt;Products needing attention:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Product&lt;/th&gt;
&lt;th&gt;Rating&lt;/th&gt;
&lt;th&gt;Reviews&lt;/th&gt;
&lt;th&gt;Discount&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Wall-mounted Plug Fixer&lt;/td&gt;
&lt;td&gt;2.0&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;50%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5-PCS Cooking Pot Set&lt;/td&gt;
&lt;td&gt;2.1&lt;/td&gt;
&lt;td&gt;13&lt;/td&gt;
&lt;td&gt;55%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Artificial Potted Flowers&lt;/td&gt;
&lt;td&gt;2.2&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;45%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;380ML USB Blender&lt;/td&gt;
&lt;td&gt;2.3&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;50%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Observation&lt;/strong&gt;: Many underperformers have &lt;strong&gt;high discounts but poor ratings&lt;/strong&gt;, suggesting product quality issues rather than pricing problems.&lt;/p&gt;




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

&lt;h3&gt;
  
  
  For Underperforming Products (Low Rating + Low Reviews)
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Investigate product quality&lt;/strong&gt;: Poor ratings despite high discounts suggest quality issues&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Improve product listings&lt;/strong&gt;: Better images, descriptions, and specifications&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consider discontinuation&lt;/strong&gt;: If quality cannot be improved, remove the product&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  For High-Rated, Low-Review Products
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Increase visibility&lt;/strong&gt;: Use Jumia's advertising or promotional campaigns&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Encourage reviews&lt;/strong&gt;: Offer voucher rewards, loyalty points, or discount coupons for verified feedback&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Feature in curated collections&lt;/strong&gt;: Highlight high-rated products in category pages&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  For Pricing Strategy
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Avoid excessive discounts&lt;/strong&gt;: Products with &amp;gt;50% discounts don't show higher engagement&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Optimise discount ranges&lt;/strong&gt;: Medium discounts (20–40%) appear most effective&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Shift from price-driven to value-driven strategy&lt;/strong&gt;: Focus on product quality and customer experience rather than competing solely on price&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  For Overall Platform Growth
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Incentivise reviews systematically&lt;/strong&gt;: Build a review culture through rewards&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Spotlight high-rated categories&lt;/strong&gt;: Use top performers as case studies&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Build trust through reviews&lt;/strong&gt;: Transparent customer feedback drives long-term loyalty&lt;/li&gt;
&lt;/ol&gt;




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

&lt;h3&gt;
  
  
  Limitations
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Limitation&lt;/th&gt;
&lt;th&gt;Impact&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Missing data&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Several rows lack reviews or ratings, reducing sample size&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;No product categories&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Manual classification would enable deeper segmentation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Price extraction assumption&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;For ranges, we used lower bound for current and upper bound for old price&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Review count ≠ engagement quality&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Some products may be new; review counts don't capture sentiment&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Observational analysis&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Correlations do not imply causation&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Lessons Learned
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Data cleaning is the most critical step&lt;/strong&gt;: It is important to clean your data because it produces a structured dataset ready for analysis.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Power Query saves time&lt;/strong&gt;: Automating cleaning steps makes the process reproducible and traceable&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Slicers transform usability&lt;/strong&gt;: Interactive filters make dashboards far more useful than static charts&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Simplicity wins&lt;/strong&gt;: A dashboard is only useful if someone can open it, read it in under a minute, and trust the numbers&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Excel remains relevant&lt;/strong&gt;: Despite modern BI tools, Excel's flexibility and ubiquity make it an essential skill&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  11. Links to Resources
&lt;/h2&gt;

&lt;h3&gt;
  
  
  GitHub Repository
&lt;/h3&gt;

&lt;p&gt;The complete project, including the Excel workbook, cleaning scripts, and documentation, is available on GitHub:&lt;/p&gt;

&lt;p&gt;🔗 &lt;strong&gt;&lt;a href="https://github.com/OkBrad/Jumia-Product-Performance-Analysis" rel="noopener noreferrer"&gt;GitHub Repository&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Dashboard File
&lt;/h3&gt;

&lt;p&gt;Direct download link to the Excel dashboard:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/OkBrad/Jumia-Product-Performance-Analysis/blob/main/dashboard/Excel_jumia_dashboard.xlsx" rel="noopener noreferrer"&gt;Download Jumia_Product_Dashboard.xlsx&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

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

&lt;p&gt;This project demonstrates how Microsoft Excel combined with Power Query, PivotTables, and slicers can transform raw e-commerce product data into a professional, interactive dashboard. The analysis reveals that &lt;strong&gt;discounts alone do not drive engagement&lt;/strong&gt; and that &lt;strong&gt;high ratings do not guarantee many reviews&lt;/strong&gt;. Instead, product quality, visibility, and strategic pricing matter more.&lt;/p&gt;

&lt;p&gt;For Jumia and other e-commerce platforms, the path to growth lies not in price wars but in &lt;strong&gt;value-driven strategies&lt;/strong&gt;: improving product quality, spotlighting top performers, optimising discount ranges, and building trust through authentic customer reviews.&lt;/p&gt;

</description>
      <category>datascience</category>
      <category>dataanalysis</category>
      <category>ecommerce</category>
      <category>excel</category>
    </item>
    <item>
      <title>Getting Started with Excel for Data Analytics: From Basics to Data Cleaning</title>
      <dc:creator>Bradley Okello</dc:creator>
      <pubDate>Mon, 31 Aug 2026 13:11:23 +0000</pubDate>
      <link>https://dev.to/okbrad/getting-started-with-excel-for-data-analytics-from-basics-to-data-cleaning-202c</link>
      <guid>https://dev.to/okbrad/getting-started-with-excel-for-data-analytics-from-basics-to-data-cleaning-202c</guid>
      <description>&lt;h2&gt;
  
  
  Getting Started with Excel for Data Analytics: From Basics to Data Cleaning
&lt;/h2&gt;

&lt;p&gt;In today's data‑driven world, Excel is often the first analytics tool many professionals encounter as it has a low barrier to entry, is ubiquitous, and is far more powerful than most people realise. Yet many users feel overwhelmed when faced with a messy, disorganised spreadsheet and don't know where to start. This article will guide you from the most basic operations all the way to the core skills of data cleaning, helping you master Excel for analytics from the ground up.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Building a Solid Foundation:
&lt;/h2&gt;

&lt;p&gt;Before diving into analysis, it's essential to understand what analytical features Excel offers. Its built‑in capabilities cover the entire data workflow; from cleaning to visualisation, all within one application.&lt;/p&gt;

&lt;h3&gt;
  
  
  Overview of Core Features
&lt;/h3&gt;

&lt;p&gt;The key data analytics features in Excel include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Data entry and organisation – manual input and external data import, paired with find/replace, remove duplicates, etc.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Filtering and sorting – quickly filter data by criteria and sort by values or alphabetical order.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;PivotTables – one of the most powerful analytical tools, allowing rapid summarisation and cross‑tabulation of large datasets.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Charting tools – column, line, pie, and many other visualisation options.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Formulas and functions – covering statistical, financial, logical, and many other categories.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  2. Data Cleaning: Turning "Dirty Data" into Clean Data
&lt;/h2&gt;

&lt;p&gt;Data cleaning is the most important and often the most time‑consuming step in the analytics process. It is an essential step that prepares the data for analysis.&lt;/p&gt;

&lt;h3&gt;
  
  
  Core Steps of Data Cleaning
&lt;/h3&gt;

&lt;p&gt;Data cleaning typically follows these steps:&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 1: Data preparation
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Ensure your data sources are reliable; if sources have inconsistent formats, standardise them first.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use Text to Columns to convert messy formats into a consistent structure.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use Remove Duplicates to quickly eliminate duplicate records.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Step 2: Data standardisation
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Use Find and Replace to unify date formats (e.g., all dates to YYYY‑MM‑DD).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Set up Data Validation to prevent future input errors.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use the TRIM function to remove excess spaces from text.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Step 3: Handling missing values
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;If missing values are few, delete the rows with missing data.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Fill using the Fill Series feature or functions (e.g., replacing with averages).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;For time‑series data, use linear interpolation.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  7 Must‑Know Data Cleaning Functions
&lt;/h3&gt;

&lt;p&gt;Functions are indispensable for cleaning data. Here are seven of the most commonly used:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;CLEAN&lt;/strong&gt; – removes non‑printable characters&lt;br&gt;
Text imported from other applications may contain characters that are not printable in your current operating system. CLEAN removes them in one go.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;TRIM&lt;/strong&gt; – removes extra spaces&lt;br&gt;
Text copied from web pages often contains excessive spaces. &lt;br&gt;
&lt;code&gt;=TRIM(A1)&lt;/code&gt; removes all spaces except single spaces between words. This is especially important when cleaning user‑entered data.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;IFERROR&lt;/strong&gt; – replaces error values&lt;br&gt;
When functions like VLOOKUP return an error because a lookup fails, IFERROR can replace that error with a specified value (e.g., blank or "Not Found"), preventing errors from interfering with your analysis.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;REPLACE&lt;/strong&gt; – replaces characters at a specified position&lt;br&gt;
This function replaces a given value with another. It is often used to mask personal information such as phone numbers or ID numbers: &lt;code&gt;=REPLACE(C2,7,8,"****")&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;LEFT / RIGHT / MID&lt;/strong&gt; – extract characters&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code&gt;LEFT(C2,6)&lt;/code&gt; – extracts 6 characters from the left (e.g., to get an area code).&lt;/p&gt;

&lt;p&gt;&lt;code&gt;MID(C2,7,8)&lt;/code&gt; – extracts 8 characters starting at position 7 (e.g., to extract a birthdate).&lt;/p&gt;

&lt;p&gt;&lt;code&gt;RIGHT(B2,LEN(B2)-FIND(".",B2))&lt;/code&gt; – extracts a file extension.&lt;/p&gt;

&lt;p&gt;These text functions are not only useful for cleaning, but also for standardising data and converting formats. For instance, converting all text to uppercase or lowercase to ensure consistency.&lt;/p&gt;

&lt;h3&gt;
  
  
  Filtering: Quickly Spot Problem Data
&lt;/h3&gt;

&lt;p&gt;Filtering is another powerful tool for data cleaning. Click anywhere in your data range, then select Filter from the Data tab. This quickly applies filter arrows to each column.&lt;/p&gt;

&lt;p&gt;By combining multiple criteria (date ranges, amount thresholds, specific text, etc.), you can precisely locate particular records within your dataset. Combining filters with text‑based helper columns allows for even more dynamic and targeted cleaning.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Best Practices for Data Cleaning
&lt;/h3&gt;

&lt;p&gt;To wrap up, here are some golden rules for data cleaning:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Always keep a raw copy – duplicate your original data before cleaning so you can always roll back.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Standardise first, match later – before using lookup functions like VLOOKUP, ensure both sides have consistent formatting.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use helper columns liberally – break complex cleaning logic into several helper columns, tackling one step at a time.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Validate your results – after cleaning, use PivotTables or conditional formatting to check for any remaining issues.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Document your steps – get into the habit of noting what you did; it helps with review and reuse later.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;From basic operations to data cleaning, Excel offers a complete suite of tools for data analytics. Master these skills, and you will transform raw, chaotic data into clean, structured, analysis‑ready datasets. The core of Excel data analytics is simply to get your data clean first, and then ask the right questions in the right way.&lt;/p&gt;

</description>
      <category>datascience</category>
      <category>beginners</category>
      <category>data</category>
    </item>
    <item>
      <title>From Local Folder to Github - A Beginners Guide to Using Git and SSH</title>
      <dc:creator>Bradley Okello</dc:creator>
      <pubDate>Thu, 20 Aug 2026 13:41:41 +0000</pubDate>
      <link>https://dev.to/okbrad/from-local-folder-to-github-a-beginners-guide-to-using-git-and-ssh-2f3e</link>
      <guid>https://dev.to/okbrad/from-local-folder-to-github-a-beginners-guide-to-using-git-and-ssh-2f3e</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;This article covers my journey from taking a project from my local folder all the way to GitHub using git and SSH. It is a beginner-friendly guide, no prior experience with version control is required. &lt;/p&gt;

&lt;h2&gt;
  
  
  What are Git, GitHub and SSH?
&lt;/h2&gt;

&lt;p&gt;These are the key players in any project and it is essential we get a better understanding of what they are and how they interact with each other to come up with a project in the net.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Git: Your Time Machine for Code
&lt;/h3&gt;

&lt;p&gt;Git is a &lt;strong&gt;Version Control System (VCS)&lt;/strong&gt; that tracks changes in your files over time. We refer to it as a time machine for our code as it allows us to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Save snapshots of our projects at different points&lt;/li&gt;
&lt;li&gt;Experiment with new features without breaking our working code&lt;/li&gt;
&lt;li&gt;Collaborate with others without overwriting each other's work&lt;/li&gt;
&lt;li&gt;Revert to previous versions if something goes wrong&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. GitHub: Your Code's Home on the Internet
&lt;/h3&gt;

&lt;p&gt;GitHub is a cloud-based platform that hosts Git repositories. It is the equivalent of a social network for developers where we can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Store our code securely on the cloud&lt;/li&gt;
&lt;li&gt;Share our project with the world&lt;/li&gt;
&lt;li&gt;Collaborate with other developers&lt;/li&gt;
&lt;li&gt;Access our code or project remotely from anywhere&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. SSH: Your Secure Connection
&lt;/h3&gt;

&lt;p&gt;SSH (Secure Shell) is a protocol that provides a secure way to connect our local computer to GitHub. It's more of a digital fingerprint that proves it's really you without the hassle of countless authentication procedures.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding the Git Workflow
&lt;/h2&gt;

&lt;p&gt;Before we start pushing code to GitHub, we need to understand the four major stages our files go through when using Git:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Working Directory
&lt;/h3&gt;

&lt;p&gt;This is where we do our actual work. When we create, edit or delete files in our project folder, they exist in our working directory. Git sees these changes but hasn't started tracking them yet.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Staging Area (Index)
&lt;/h3&gt;

&lt;p&gt;This is the "waiting room" for our changes. When we tell Git which files we want to save, we add them to the staging area. This allows us to be selective about which changes make it into our next commit.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Commit
&lt;/h3&gt;

&lt;p&gt;A commit is a permanent snapshot of our staged changes. It's like taking a photo of our project at a specific moment. Each commit has a unique ID and includes a message describing what we changed.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Push
&lt;/h3&gt;

&lt;p&gt;This is the final step where we upload our commits from our local machine to GitHub. Once pushed, our code is safely stored in the cloud and accessible to others (or just to you from other devices).&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%2Fguzn5scczjzrrs12as18.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%2Fguzn5scczjzrrs12as18.png" alt="_Visualization of the Git workflow showing files moving from working directory to staging to commit to push_" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before we begin our journey, make sure you have:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Git installed&lt;/strong&gt; on your computer (download from &lt;a href="//git-scm.com"&gt;Git&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A GitHub account&lt;/strong&gt; (sign up at &lt;a href="//github.com"&gt;GitHub&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A terminal or command prompt&lt;/strong&gt; (Terminal on Mac/Linux, Command Prompt or PowerShell on Windows)&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Step-by-Step Guide: From Local Folder to GitHub
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 1: Initialize Git in Your Local Folder
&lt;/h3&gt;

&lt;p&gt;First, let's tell Git that our folder is special and should be tracked. Open your terminal and navigate to your project folder using the &lt;code&gt;cd&lt;/code&gt; (change directory) command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;path/to/your/project
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, initialize a new Git repository:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see a message like:&lt;code&gt;Initialized empty Git repository in /path/to/your/project/.git/&lt;/code&gt;&lt;br&gt;
We have just created a hidden &lt;code&gt;.git&lt;/code&gt; folder that contains everything Git needs to track your project.&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 2: Check Your Repository Status
&lt;/h3&gt;

&lt;p&gt;Before making any changes, it's good practice to check the status of your repository:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git status
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command will show you which files are untracked (new) or modified. Initially, you'll see all your files listed as "untracked."&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Add Files to the Staging Area
&lt;/h3&gt;

&lt;p&gt;Now, let's start tracking your files. To add all files in your current directory to the staging area:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git add &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The dot (&lt;code&gt;.&lt;/code&gt;) means "everything in the current folder." You can also add specific files:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git add index.html
git add style.css
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run &lt;code&gt;git status&lt;/code&gt; again, and you'll see your files in green, labeled as "changes to be committed."&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Create Your First Commit
&lt;/h3&gt;

&lt;p&gt;Now that your files are staged, let's create a commit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Initial commit: adding all project files"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;-m&lt;/code&gt; flag allows you to add a commit message directly in the command. Always write meaningful commit messages as they'll help you understand the history of your project later.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 5: Set Up SSH for GitHub
&lt;/h3&gt;

&lt;p&gt;To connect to GitHub securely without typing credentials each time, we need to set up SSH keys.&lt;/p&gt;

&lt;h4&gt;
  
  
  Generate an SSH Key
&lt;/h4&gt;

&lt;p&gt;In your terminal, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh-keygen &lt;span class="nt"&gt;-t&lt;/span&gt; ed25519 &lt;span class="nt"&gt;-C&lt;/span&gt; &lt;span class="s2"&gt;"your_email@example.com"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;GitHub documents Ed25519 for new SSH keys, with RSA available mainly for legacy systems that do not support Ed25519. (&lt;a href="https://docs.github.com/en/authentication/connecting-to-github-with-ssh/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent" rel="noopener noreferrer"&gt;GitHub Docs&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;Replace the email with the one associated with your GitHub account. You'll be prompted to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Choose a location to save the key (press Enter for the default)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Enter a passphrase (optional but recommended for extra security)&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Add the SSH key to the SSH agent
&lt;/h4&gt;

&lt;p&gt;The SSH agent helps manage your private SSH key and can remember its passphrase during your session. GitHub documents platform-specific agent setup steps. (&lt;a href="https://docs.github.com/en/authentication/connecting-to-github-with-ssh/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent" rel="noopener noreferrer"&gt;GitHub Docs&lt;/a&gt;)&lt;/p&gt;

&lt;h4&gt;
  
  
  Start the SSH Agent
&lt;/h4&gt;

&lt;p&gt;For the Windows method documented by GitHub, open: PowerShell as Administrator. To do that:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Click Start.&lt;/li&gt;
&lt;li&gt;Search: PowerShell&lt;/li&gt;
&lt;li&gt;Right-click PowerShell. &lt;/li&gt;
&lt;li&gt;Choose: Run as administrator&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;Get-Service&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ssh-agent&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Set-Service&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-StartupType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Manual&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;Start-Service&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ssh-agent&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These are the current commands documented by GitHub for starting the Windows OpenSSH agent. (&lt;a href="https://docs.github.com/en/authentication/connecting-to-github-with-ssh/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent" rel="noopener noreferrer"&gt;GitHub Docs&lt;/a&gt;) &lt;/p&gt;

&lt;h4&gt;
  
  
  Add Your Private SSH Key
&lt;/h4&gt;

&lt;p&gt;Now close the Administrator PowerShell window.&lt;br&gt;
Open a &lt;strong&gt;normal PowerShell window&lt;/strong&gt;.&lt;br&gt;
Run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;ssh-add&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c:/Users/YOUR_USERNAME/.ssh/id_ed25519&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replace:&lt;br&gt;
&lt;code&gt;YOUR_USERNAME&lt;/code&gt; with your actual Windows username.&lt;br&gt;
Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;ssh-add&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c:/Users/John/.ssh/id_ed25519&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you do not know your Windows username, you can run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;whoami&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You may receive something like:&lt;br&gt;
&lt;code&gt;DESKTOP-12345\John&lt;/code&gt;&lt;br&gt;
Your username in this example is:&lt;br&gt;
&lt;code&gt;John&lt;/code&gt; &lt;br&gt;
If the key has a passphrase, enter it.&lt;br&gt;
GitHub documents this Windows &lt;code&gt;ssh-add&lt;/code&gt; path format. (&lt;a href="https://docs.github.com/en/authentication/connecting-to-github-with-ssh/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent" rel="noopener noreferrer"&gt;GitHub Docs&lt;/a&gt;)&lt;/p&gt;
&lt;h4&gt;
  
  
  Avoid an SSH Agent Conflict
&lt;/h4&gt;

&lt;p&gt;Windows may have both:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Windows OpenSSH; &lt;/li&gt;
&lt;li&gt;Git for Windows' bundled SSH.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;GitHub notes that this can sometimes result in Git asking for the passphrase even though the key was added to the Windows agent. (&lt;a href="https://docs.github.com/en/authentication/connecting-to-github-with-ssh/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent" rel="noopener noreferrer"&gt;GitHub Docs&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;To ensure Git uses Windows OpenSSH, run this on git bash:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git config &lt;span class="nt"&gt;--global&lt;/span&gt; core.sshCommand&lt;span class="s2"&gt;"C:/Windows/System32/OpenSSH/ssh.exe"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You only need to configure this once. &lt;/p&gt;

&lt;h4&gt;
  
  
  Add the SSH Key to GitHub
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Copy your public key to your clipboard:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; ~/.ssh/id_ed25519.pub | clip 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The public key should now be in your clipboard.&lt;br&gt;
GitHub documents this Windows-compatible form as an alternative that avoids PowerShell's handling of the &amp;lt; operator  (&lt;a href="https://docs.github.com/articles/adding-a-new-ssh-key-to-your-github-account" rel="noopener noreferrer"&gt;GitHub Docs&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;If that does not work, display it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; ~/.ssh/id_ed25519.pub 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will see one long line similar to: &lt;br&gt;
&lt;code&gt;ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAA... johnkamau@gmail.com&lt;/code&gt;&lt;br&gt;
Copy the entire line. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Go to GitHub → Settings → SSH and GPG keys&lt;/li&gt;
&lt;li&gt;Click "New SSH Key"&lt;/li&gt;
&lt;li&gt;Paste your public key and give it a descriptive title (like "My Laptop")&lt;/li&gt;
&lt;li&gt;Click "Add SSH Key"&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;
  
  
  First Connection Warning
&lt;/h4&gt;

&lt;p&gt;On your first connection you may see a message similar to: &lt;br&gt;
&lt;code&gt;The authenticity of host 'github.com' can't be established.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;You may also see an Ed25519 fingerprint. &lt;/p&gt;

&lt;p&gt;GitHub's current documentation shows its GitHub.com Ed25519 fingerprint as:&lt;br&gt;
&lt;code&gt;SHA256:+DiY3wvvV6TuJJhbpZisF/zLDA0zPMSvHdkr4UvCOqU&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Before accepting a first-time SSH host, compare the fingerprint shown in your terminal with GitHub's published fingerprint. &lt;/p&gt;

&lt;p&gt;GitHub instructs users to verify the fingerprint before typing &lt;code&gt;yes&lt;/code&gt;.(&lt;a href="https://docs.github.com/en/authentication/connecting-to-github-with-ssh/testing-your-ssh-connection" rel="noopener noreferrer"&gt;GitHub Docs&lt;/a&gt;) &lt;/p&gt;

&lt;p&gt;If it matches, type: &lt;br&gt;
&lt;code&gt;yes&lt;/code&gt;&lt;br&gt;
and press Enter.&lt;/p&gt;
&lt;h4&gt;
  
  
  Successful SSH Connection
&lt;/h4&gt;

&lt;p&gt;If everything is correctly configured, you should get a message similar to: &lt;br&gt;
&lt;code&gt;Hi YOUR_USERNAME! You've successfully authenticated, but GitHub does not provide shell access.&lt;/code&gt;  This is a success message. &lt;/p&gt;

&lt;p&gt;GitHub documents this expected successful response.(&lt;a href="https://docs.github.com/en/authentication/connecting-to-github-with-ssh/testing-your-ssh-connection" rel="noopener noreferrer"&gt;GitHub Docs&lt;/a&gt;)&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 6: Create a Repository on GitHub
&lt;/h3&gt;

&lt;p&gt;Now it's time to create your project's home on GitHub:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Log in to &lt;a href="//GitHub.com"&gt;GitHub.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Click the "+" icon in the top-right corner and select "New repository"&lt;/li&gt;
&lt;li&gt;Give your repository a name (you can use the same name as your local project)&lt;/li&gt;
&lt;li&gt;Add an optional description&lt;/li&gt;
&lt;li&gt;Choose the repository visibility: Public (everyone can see) or Private (only you and collaborators)&lt;/li&gt;
&lt;li&gt;Don't initialize with README, .gitignore, or license files (we already have our code)&lt;/li&gt;
&lt;li&gt;Click "Create repository"&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  Step 7: Connect Your Local Repository to GitHub
&lt;/h3&gt;

&lt;p&gt;GitHub will show you instructions for connecting your existing repository. We'll use the SSH option:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git remote add origin git@github.com:yourusername/your-repository-name.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replace &lt;code&gt;yourusername&lt;/code&gt; with your GitHub username and &lt;code&gt;your-repository-name&lt;/code&gt; with your repository name.&lt;/p&gt;

&lt;p&gt;This command tells Git that the remote repository (the one on GitHub) should be referred to as "origin."&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 8: Push Your Code to GitHub
&lt;/h3&gt;

&lt;p&gt;Now for the moment of truth; uploading your code to GitHub:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git push &lt;span class="nt"&gt;-u&lt;/span&gt; origin main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's break this down:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;git push&lt;/code&gt;: Upload commits to a remote repository&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-u origin main&lt;/code&gt;: Set the upstream branch to &lt;code&gt;main&lt;/code&gt; on the &lt;code&gt;origin&lt;/code&gt; remote&lt;/li&gt;
&lt;li&gt;This is a shortcut so you can use&lt;code&gt;git push&lt;/code&gt;in the future without all the parameters&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 9: Verify Your Push
&lt;/h3&gt;

&lt;p&gt;Go to your GitHub repository page and refresh. You should see all your files there!&lt;/p&gt;

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

&lt;p&gt;We have just completed our journey from a local folder to GitHub! We have learned the essential Git workflow; from creating commits in your working directory to securely pushing them to GitHub using SSH. This is the foundation of modern software development, opening doors to collaboration, backup, and professional version control.&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>github</category>
      <category>ssh</category>
    </item>
  </channel>
</rss>
