What is Power Query?
Power Query is Microsoft's data transformation and preparation tool built into Excel and Power BI. It lets you connect to data sources, clean and transform data, and automate the entire process - all without writing complex formulas.
# Power Query Workflow
┌─────────────────────────────────────────────────────────────────┐
│ POWER QUERY PROCESS │
├─────────────────────────────────────────────────────────────────┤
│ │
│ DATA SOURCES TRANSFORM OUTPUT │
│ ┌───────────┐ ┌─────────┐ ┌─────────┐ │
│ │ Excel │ │ Clean │ │ Excel │ │
│ │ CSV │ ──────────► │ Shape │ ──────────► │ Table │ │
│ │ SQL │ CONNECT │ Merge │ LOAD │ or │ │
│ │ Web │ │ Filter │ │Power BI │ │
│ │ JSON │ │ Group │ │ Model │ │
│ └───────────┘ └─────────┘ └─────────┘ │
│ │
│ All steps are RECORDED and can be REFRESHED automatically! │
└─────────────────────────────────────────────────────────────────┘
Why Use Power Query?
- No coding required: Point-and-click interface for most tasks
- Repeatable: Steps are recorded and can be refreshed with new data
- Multiple sources: Connect to 100+ data sources
- Powerful: Handle millions of rows efficiently
- Integrated: Built into Excel and Power BI
Getting Started
In Excel
Opening Power Query in Excel:
1. Go to: Data tab → Get Data
2. Or: Data tab → Get & Transform Data section
Quick Access:
• From Table: Select data → Data → From Table/Range
• From File: Data → Get Data → From File → From Workbook/CSV
• From Database: Data → Get Data → From Database → From SQL Server
In Power BI
Opening Power Query in Power BI:
1. Home tab → Transform Data
2. Or: When you load data, click "Transform Data" instead of "Load"
The Power Query Editor opens with your data ready to transform.
The Power Query Editor
Power Query Editor Layout:
┌─────────────────────────────────────────────────────────────────┐
│ File Home Transform Add Column View Help │
├──────────┬──────────────────────────────────────┬───────────────┤
│ │ │ │
│ QUERIES │ DATA PREVIEW │ QUERY │
│ │ │ SETTINGS │
│ □ Sales │ ┌────┬────────┬────────┬────────┐ │ │
│ □ Products│ │ ID │ Name │ Price │ Date │ │ Properties │
│ □ Region │ ├────┼────────┼────────┼────────┤ │ Name: Sales │
│ │ │ 1 │ Widget │ $10.00 │ 1/1/24 │ │ │
│ │ │ 2 │ Gadget │ $25.00 │ 1/2/24 │ │ APPLIED │
│ │ │ 3 │ Tool │ $15.00 │ 1/3/24 │ │ STEPS │
│ │ └────┴────────┴────────┴────────┘ │ │
│ │ │ ○ Source │
│ │ │ ○ Changed Type│
│ │ │ ○ Removed Cols│
│ │ │ ○ Filtered │
└──────────┴──────────────────────────────────────┴───────────────┘
Key Areas:
• Queries Pane (left): List of all your queries
• Data Preview (center): See your data and changes
• Query Settings (right): Properties and Applied Steps
• Formula Bar (top): Shows M code for current step
Common Transformations
1. Remove Columns
Remove unwanted columns:
UI Method:
• Right-click column header → Remove
• Select multiple columns → Right-click → Remove Columns
• Home → Remove Columns → Remove Other Columns (keep selected only)
M Code:
= Table.RemoveColumns(PreviousStep, {"Column1", "Column2"})
= Table.SelectColumns(PreviousStep, {"Name", "Price", "Date"})
2. Filter Rows
Filter data:
UI Method:
• Click dropdown arrow on column header
• Uncheck values to exclude
• Use filters: Text Filters, Number Filters, Date Filters
Common Filters:
• Equals, Does Not Equal
• Contains, Does Not Contain
• Begins With, Ends With
• Greater Than, Less Than
• Between
• Top N, Bottom N
M Code:
= Table.SelectRows(Source, each [Price] > 100)
= Table.SelectRows(Source, each Text.Contains([Name], "Widget"))
= Table.SelectRows(Source, each [Date] >= #date(2024, 1, 1))
3. Change Data Types
Set correct data types:
UI Method:
• Click icon left of column name
• Select: Text, Whole Number, Decimal, Date, etc.
• Or: Transform → Data Type
Common Types:
• ABC → Text
• 123 → Whole Number
• 1.2 → Decimal Number
• 📅 → Date
• 🕐 → Date/Time
• ✓/✗ → True/False
M Code:
= Table.TransformColumnTypes(Source, {
{"Price", type number},
{"Date", type date},
{"Quantity", Int64.Type}
})
4. Split Columns
Split one column into multiple:
Example: "John Smith" → "John" and "Smith"
UI Method:
• Select column → Transform → Split Column
• By Delimiter: comma, space, tab, custom
• By Number of Characters
• By Positions
Split "John Smith, Manager" by comma:
┌───────────────────┐ ┌──────────────┬───────────┐
│ Full Name │ ──► │ Name │ Title │
├───────────────────┤ ├──────────────┼───────────┤
│ John Smith, Mgr │ │ John Smith │ Mgr │
│ Jane Doe, Director│ │ Jane Doe │ Director │
└───────────────────┘ └──────────────┴───────────┘
M Code:
= Table.SplitColumn(Source, "FullName",
Splitter.SplitTextByDelimiter(", "),
{"Name", "Title"})
5. Merge Columns
Combine multiple columns:
UI Method:
• Select columns (Ctrl+click)
• Transform → Merge Columns
• Choose separator
Example:
┌──────────┬───────────┐ ┌─────────────────────┐
│ First │ Last │ ──► │ Full Name │
├──────────┼───────────┤ ├─────────────────────┤
│ John │ Smith │ │ John Smith │
│ Jane │ Doe │ │ Jane Doe │
└──────────┴───────────┘ └─────────────────────┘
M Code:
= Table.CombineColumns(Source,
{"First", "Last"},
Combiner.CombineTextByDelimiter(" "),
"Full Name")
6. Replace Values
Replace or clean values:
UI Method:
• Select column → Transform → Replace Values
• Enter value to find and replacement
Common Uses:
• Fix typos: "Recieved" → "Received"
• Standardize: "USA", "US" → "United States"
• Remove characters: Replace "$" with ""
• Handle nulls: Replace null with 0
M Code:
= Table.ReplaceValue(Source, "USA", "United States",
Replacer.ReplaceText, {"Country"})
= Table.ReplaceValue(Source, null, 0,
Replacer.ReplaceValue, {"Quantity"})
7. Group By (Aggregate)
Summarize data by groups:
UI Method:
• Transform → Group By
• Select grouping columns
• Add aggregations: Sum, Average, Count, Min, Max
Example: Sales by Region
┌─────────┬────────┬───────┐ ┌─────────┬─────────────┐
│ Region │Product │ Sales │ │ Region │ Total Sales │
├─────────┼────────┼───────┤ ├─────────┼─────────────┤
│ North │ A │ 100 │ │ North │ 350 │
│ North │ B │ 250 │ ──► │ South │ 500 │
│ South │ A │ 300 │ │ East │ 200 │
│ South │ B │ 200 │ └─────────┴─────────────┘
│ East │ A │ 200 │
└─────────┴────────┴───────┘
M Code:
= Table.Group(Source, {"Region"}, {
{"Total Sales", each List.Sum([Sales]), type number},
{"Order Count", each Table.RowCount(_), Int64.Type},
{"Avg Sale", each List.Average([Sales]), type number}
})
Merging Queries (JOINs)
Combine data from multiple tables:
Merge Queries (like SQL JOIN):
UI Method:
• Home → Merge Queries
• Select tables and matching columns
• Choose join type
Join Types:
┌────────────────────────────────────────────────────────────────┐
│ Type │ Description │
├────────────────────────────────────────────────────────────────┤
│ Left Outer │ All from left + matches from right │
│ Right Outer │ All from right + matches from left │
│ Full Outer │ All from both tables │
│ Inner │ Only matching rows │
│ Left Anti │ Left rows with NO match in right │
│ Right Anti │ Right rows with NO match in left │
└────────────────────────────────────────────────────────────────┘
Example: Add Product Names to Sales
Sales Table: Products Table:
┌──────────┬──────────┐ ┌──────────┬────────────┐
│ProductID │ Quantity │ │ProductID │ Name │
├──────────┼──────────┤ ├──────────┼────────────┤
│ 101 │ 5 │ │ 101 │ Widget │
│ 102 │ 3 │ │ 102 │ Gadget │
└──────────┴──────────┘ └──────────┴────────────┘
Result (Left Outer Join on ProductID):
┌──────────┬──────────┬────────────┐
│ProductID │ Quantity │ Name │
├──────────┼──────────┼────────────┤
│ 101 │ 5 │ Widget │
│ 102 │ 3 │ Gadget │
└──────────┴──────────┴────────────┘
M Code:
= Table.NestedJoin(Sales, {"ProductID"},
Products, {"ProductID"},
"Products", JoinKind.LeftOuter)
Appending Queries (UNION)
Stack tables on top of each other:
UI Method:
• Home → Append Queries
• Select tables to combine
Example: Combine monthly sales files
January: February:
┌──────┬───────┐ ┌──────┬───────┐
│ Date │ Sales │ │ Date │ Sales │
├──────┼───────┤ ├──────┼───────┤
│ 1/1 │ 100 │ │ 2/1 │ 150 │
│ 1/2 │ 120 │ │ 2/2 │ 180 │
└──────┴───────┘ └──────┴───────┘
Result (Append):
┌──────┬───────┐
│ Date │ Sales │
├──────┼───────┤
│ 1/1 │ 100 │
│ 1/2 │ 120 │
│ 2/1 │ 150 │
│ 2/2 │ 180 │
└──────┴───────┘
M Code:
= Table.Combine({January, February, March})
Unpivot & Pivot
Unpivot (Wide to Long)
Transform columns into rows (normalize data):
Before (Wide format - hard to analyze):
┌─────────┬─────────┬─────────┬─────────┐
│ Product │ Jan │ Feb │ Mar │
├─────────┼─────────┼─────────┼─────────┤
│ Widget │ 100 │ 150 │ 200 │
│ Gadget │ 80 │ 90 │ 120 │
└─────────┴─────────┴─────────┴─────────┘
After Unpivot (Long format - easy to analyze):
┌─────────┬─────────┬─────────┐
│ Product │ Month │ Sales │
├─────────┼─────────┼─────────┤
│ Widget │ Jan │ 100 │
│ Widget │ Feb │ 150 │
│ Widget │ Mar │ 200 │
│ Gadget │ Jan │ 80 │
│ Gadget │ Feb │ 90 │
│ Gadget │ Mar │ 120 │
└─────────┴─────────┴─────────┘
UI Method:
• Select columns to unpivot (Jan, Feb, Mar)
• Transform → Unpivot Columns
M Code:
= Table.UnpivotOtherColumns(Source, {"Product"},
"Month", "Sales")
Pivot (Long to Wide)
Transform rows into columns (summarize):
UI Method:
• Select column to pivot (e.g., Month)
• Transform → Pivot Column
• Choose values column and aggregation
M Code:
= Table.Pivot(Source,
List.Distinct(Source[Month]),
"Month", "Sales", List.Sum)
Custom Columns
Add calculated columns:
UI Method:
• Add Column → Custom Column
• Enter formula using M language
Common Examples:
// Concatenate text
[FirstName] & " " & [LastName]
// Math calculations
[Price] * [Quantity]
[Sales] * 0.1 // 10% commission
// Conditional logic
if [Amount] > 1000 then "High" else "Low"
if [Status] = "Active" then 1
else if [Status] = "Pending" then 2
else 0
// Date calculations
Date.Year([OrderDate])
Date.Month([OrderDate])
Date.DayOfWeek([OrderDate])
Duration.Days(DateTime.LocalNow() - [OrderDate])
// Text functions
Text.Upper([Name])
Text.Start([Code], 3) // First 3 characters
Text.Contains([Description], "urgent")
// Null handling
if [Value] = null then 0 else [Value]
Parameters
Make your queries dynamic:
Creating Parameters:
UI Method:
• Home → Manage Parameters → New Parameter
• Set Name, Type, and Default Value
Example: Date Range Parameter
1. Create parameters:
- StartDate (Date) = 1/1/2024
- EndDate (Date) = 12/31/2024
2. Use in filter:
= Table.SelectRows(Source, each
[OrderDate] >= StartDate and
[OrderDate] <= EndDate
)
3. Change parameters to refresh with different dates!
Use Cases:
• File paths (change source location)
• Date ranges (reporting periods)
• Filter values (specific regions, products)
• Connection strings (dev vs prod databases)
M Language Basics
Power Query uses M (Power Query Formula Language) behind the scenes:
M Language Fundamentals:
// Structure of a query
let
Source = Excel.CurrentWorkbook(){[Name="Table1"]}[Content],
Step2 = Table.TransformColumnTypes(Source, {{"Date", type date}}),
Step3 = Table.SelectRows(Step2, each [Amount] > 100),
Final = Table.RemoveColumns(Step3, {"TempColumn"})
in
Final
Key Concepts:
// Variables (steps)
StepName = expression,
// each keyword (row-by-row operation)
each [ColumnName] > 100
// _ refers to current row
each _[Price] * _[Quantity]
// Accessing columns
[ColumnName] // Current table
TableName[ColumnName] // Specific table
// Common functions
Text.Upper([Name])
Number.Round([Price], 2)
Date.Year([Date])
List.Sum({1, 2, 3})
Table.RowCount(Source)
// Conditional
if condition then value1 else value2
// Try-otherwise (error handling)
try [Value] otherwise 0
Practical Example: Monthly Report Automation
Scenario: Automate monthly sales report
Steps:
1. Connect to source files
2. Combine all files from folder
3. Clean and transform data
4. Add calculated columns
5. Load to Excel/Power BI
let
// Step 1: Get all CSV files from folder
Source = Folder.Files("C:\Sales Data\"),
// Step 2: Filter for CSV files only
FilteredFiles = Table.SelectRows(Source, each
Text.EndsWith([Name], ".csv")),
// Step 3: Add custom column to read each file
AddContent = Table.AddColumn(FilteredFiles, "Data", each
Csv.Document([Content])),
// Step 4: Expand the data
ExpandedData = Table.ExpandTableColumn(AddContent, "Data",
{"Date", "Product", "Region", "Sales", "Quantity"}),
// Step 5: Set data types
TypedData = Table.TransformColumnTypes(ExpandedData, {
{"Date", type date},
{"Sales", type number},
{"Quantity", Int64.Type}
}),
// Step 6: Remove unnecessary columns
CleanData = Table.SelectColumns(TypedData,
{"Date", "Product", "Region", "Sales", "Quantity"}),
// Step 7: Add calculated columns
WithCalculations = Table.AddColumn(CleanData, "Revenue",
each [Sales] * [Quantity], type number),
// Step 8: Add Month column for grouping
WithMonth = Table.AddColumn(WithCalculations, "Month",
each Date.ToText([Date], "yyyy-MM"), type text),
// Step 9: Filter out invalid data
ValidData = Table.SelectRows(WithMonth, each
[Sales] > 0 and [Quantity] > 0)
in
ValidData
// Now just click REFRESH to update with new monthly files!
Best Practices
- Name your steps clearly: Rename "Changed Type" to "Set Column Types"
- Remove unnecessary columns early: Improves performance
- Set data types explicitly: Don't rely on auto-detection
- Use parameters: For file paths, dates, filters
- Document with comments: Add step descriptions
- Handle errors: Use try-otherwise for robust queries
- Test with sample data: Before running on full dataset
Master Data Analytics
Our Data Analytics program covers Power Query, Power BI, and advanced data transformation techniques.
Explore Data Analytics Program