Business Demand Overview
This project was initiated to address a clear business challenge: improve the visibility and effectiveness of sales reporting. The business raised the request for modern, visual dashboards that could replace outdated and static Excel-based reports used for budgeting in 2021.
The sales team lacked a unified view of performance across customers and products. Key decision-makers were spending excessive time manually pulling data and reconciling spreadsheets. They needed a streamlined, automated solution that would provide relevant insights at a glance and support data-informed decision-making.
To meet this need, the following tools were selected: Power BI, SQL, and the organisation’s existing CRM system.
Client Needs & User Stories
| Role | Need | Result |
|---|---|---|
| Sales Manager | High-level view of internet sales to identify top customers/products | Power BI dashboard with daily refresh and key performance metrics |
| Sales Representative | Customer-level insights for follow-ups and upselling | Filtering and drill-down functionality by customer |
| Sales Representative | Product-level visibility to track performance trends | Filters by product, subcategory, and product line |
| Sales Manager | Compare sales performance against 2021 budget | Integrated budget data with KPIs and comparison graphs |
Data cleansing & Transformation (SQL)
Data was extracted and transformed via SQL:
- Calendar (DIM): Cleaned for time intelligence (month, quarter, year).
- Customers & Products (DIM): Enriched with metadata for filtering and segmentation.
- Internet Sales (FACT): Filtered for the last two years to maintain relevance.
- Budgets (Excel): Integrated into the model for variance analysis.
SQL-based cleansing ensured a high-performance, scalable data model for Power BI.
SQL statements
Calendar Table
DIM Calendar:
--Cleansed DIM_DataTable--
SELECT
[DateKey],
[FullDateAlternateKey] AS Date,
--,[DayNumberOfWeek],
[EnglishDayNameOfWeek] AS Day,
--,[SpanishDayNameOfWeek]
--,[FrenchDayNameOfWeek]
--,[DayNumberOfMonth]
--,[DayNumberOfYear]
[WeekNumberOfYear] AS WeekNr,
[EnglishMonthName] AS Month,
LEFT([EnglishMonthName], 3) AS MonthShort,
--,[SpanishMonthName]
--,[FrenchMonthName]
[MonthNumberOfYear] AS MonthNo,
[CalendarQuarter] AS Quarter,
[CalendarYear] AS Year --,[CalendarSemester]
--,[FiscalQuarter]
--,[FiscalYear],
--,[FiscalSemester]
FROM
[AdventureWorksDW2022].[dbo].[DimDate]
WHERE
CalendarYear >= 2019
DIM Customers:
--Cleansed DIM_DataTable--
SELECT
[DateKey],
[FullDateAlternateKey] AS Date,
--,[DayNumberOfWeek],
[EnglishDayNameOfWeek] AS Day,
--,[SpanishDayNameOfWeek]
--,[FrenchDayNameOfWeek]
--,[DayNumberOfMonth]
--,[DayNumberOfYear]
[WeekNumberOfYear] AS WeekNr,
[EnglishMonthName] AS Month,
LEFT([EnglishMonthName], 3) AS MonthShort,
--,[SpanishMonthName]
--,[FrenchMonthName]
[MonthNumberOfYear] AS MonthNo,
[CalendarQuarter] AS Quarter,
[CalendarYear] AS Year --,[CalendarSemester]
--,[FiscalQuarter]
--,[FiscalYear],
--,[FiscalSemester]
FROM
[AdventureWorksDW2022].[dbo].[DimDate]
WHERE
CalendarYear >= 2019
Product table
DIM Products:
-- Cleansed DIM_Products Table --
SELECT
p.[ProductKey],
p.[ProductAlternateKey] AS ProductItemCode,
-- ,[ProductSubcategoryKey],
-- ,[WeightUnitMeasureCode]
-- ,[SizeUnitMeasureCode]
p.[EnglishProductName] AS [Product Name],
ps.EnglishProductSubcategoryName AS [Sub Category], -- Joined in from Sub Category Table
pc.EnglishProductCategoryName AS [Product Category], -- Joined in from Category Table
-- ,[SpanishProductName]
-- ,[FrenchProductName]
-- ,[StandardCost]
-- ,[FinishedGoodsFlag]
p.[Color] AS [Product Color],
-- ,[SafetyStockLevel]
-- ,[ReorderPoint]
-- ,[ListPrice]
p.[Size] AS [Product Size],
-- ,[SizeRange]
-- ,[Weight]
-- ,[DaysToManufacture]
p.[ProductLine] AS [Product Line],
-- ,[DealerPrice]
-- ,[Class]
-- ,[Style]
p.[ModelName] AS [Product Model Name],
-- ,[LargePhoto]
p.[EnglishDescription] AS [Product Description],
-- ,[FrenchDescription]
-- ,[ChineseDescription]
-- ,[ArabicDescription]
-- ,[HebrewDescription]
-- ,[ThaiDescription]
-- ,[GermanDescription]
-- ,[JapaneseDescription]
-- ,[TurkishDescription]
-- ,[StartDate],
-- ,[EndDate],
ISNULL (p.Status, 'Outdated') AS [Product Status]
FROM
[AdventureWorksDW2022].[dbo].[DimProduct] as p
LEFT JOIN dbo.DimProductSubcategory AS ps ON ps.ProductSubcategoryKey = p.ProductSubcategoryKey
LEFT JOIN dbo.DimProductCategory AS pc ON ps.ProductCategoryKey = pc.ProductCategoryKey
ORDER BY
p.ProductKey ASC
FACT_Internet Sales:
-- Cleansed FACT_InternetSales Table --
SELECT
[ProductKey],
[OrderDateKey],
[DueDateKey],
[ShipDateKey],
[CustomerKey],
-- ,[PromotionKey]
-- ,[CurrencyKey]
-- ,[SalesTerritoryKey]
[SalesOrderNumber],
-- [SalesOrderLineNumber],
-- ,[RevisionNumber]
-- ,[OrderQuantity],
-- ,[UnitPrice],
-- ,[ExtendedAmount]
-- ,[UnitPriceDiscountPct]
-- ,[DiscountAmount]
-- ,[ProductStandardCost]
-- ,[TotalProductCost]
[SalesAmount] -- ,[TaxAmt]
-- ,[Freight]
-- ,[CarrierTrackingNumber]
-- ,[CustomerPONumber]
-- ,[OrderDate]
-- ,[DueDate]
-- ,[ShipDate]
FROM
[AdventureWorksDW2022].[dbo].[FactInternetSales]
WHERE
LEFT (OrderDateKey, 4) >= YEAR(GETDATE()) -2 -- Ensures we always only bring two years of date from extraction. As per requested.
ORDER BY
OrderDateKey ASC
Customer table
-- Cleansed DIM_Customers Table --
SELECT
c.customerkey AS CustomerKey,
-- ,[GeographyKey]
-- ,[CustomerAlternateKey]
-- ,[Title]
c.firstname AS [First Name],
-- ,[MiddleName]
c.lastname AS [Last Name],
c.firstname + ' ' + c.lastname AS [Full Name],
-- Combined First and Last Name
-- ,[NameStyle]
-- ,[BirthDate]
-- ,[MaritalStatus]
-- ,[Suffix]
CASE c.gender WHEN 'M' THEN 'Male' WHEN 'F' THEN 'Female' END AS Gender,
-- ,[EmailAddress]
-- ,[YearlyIncome]
-- ,[TotalChildren]
-- ,[NumberChildrenAtHome]
-- ,[EnglishEducation]
-- ,[SpanishEducation]
-- ,[FrenchEducation]
-- ,[EnglishOccupation]
-- ,[SpanishOccupation]
-- ,[FrenchOccupation]
-- ,[HouseOwnerFlag]
-- ,[NumberCarsOwned]
-- ,[AddressLine1]
-- ,[AddressLine2]
-- ,[Phone]
c.datefirstpurchase AS DateFirstPurchase,
-- ,[CommuteDistance]
g.city AS [Customer City] -- Joined in Customer City from Geography Table
FROM
dbo.DimCustomer AS c
LEFT JOIN dbo.dimgeography AS g ON g.geographykey = c.geographykey
ORDER BY
CustomerKey ASC -- Ordered List by CustomerKey
Dashboard Delivery
Two dashboards were built:
- Customer Insights: Drill-down by customer for sales trends and potential upsell.
- Product Insights: Real-time KPIs, best customers/products. Performance by product line, category, and seasonality.
Each dashboard is interactive, auto-refreshed daily, and aligned with user needs.





