How to Clean Messy Sales Data in Power BI Power Query
You download an orders file, load it into Power BI and build a chart. The total looks fine, so you send it. Next morning someone asks why one order is counted twice, why the first row of the table says "Blinkit Maharashtra orders export", and why the sales column will not add up. The chart was never the problem. The data was. In this chapter you clean a messy orders file in Power Query before any visual touches it, and you learn the one rule that decides which rows you may delete and which you must keep.
What you'll learn in this chapter
- Load a CSV with Get data › Text/CSV › Transform Data
- Remove Top Rows and Use First Row as Headers
- ID columns vs metric columns: what to delete
- Remove blank and duplicate order IDs
- Replace NA with null, not 0
- Extract the number before "$"
- Set Whole Number, Decimal and Date types
- Check the row count after Close & Apply
Practice files: blinkit-orders-small-raw.csv (the 12 rows used on this page) and blinkit-orders-raw.csv (315 rows with the same kinds of mess, for the practice task).
Made-up data: every order, product, store and number here is fictional practice data. The file imitates an export from a quick-commerce app such as Blinkit in Maharashtra cities, but no real order, shop or person is used. Amounts are in ₹ and dates are written DD-MM-YYYY.
1. The problem
Here is the small file opened in Notepad. It has the mess you will meet in real exports:
| Line | What you see |
|---|---|
| 1 | Blinkit Maharashtra orders export (fictional practice data),,,,,,,,,,,, – a title, not data |
| 2 | order_id,product_id,store_id,city,order_date,sales,price,revenue,stock,promo_type,promo_bin,delivery_date,Column13 – the real headers |
| 3 onwards | 12 order rows, some blank, some repeated, some with NA |
If you load this straight into a report:
- Power BI calls the columns Column1, Column2 … because the first line is a title.
- Order BLK1003 and BLK1006 are counted twice.
- "2$" is text, so the sales column cannot be summed.
- "NA" in price makes the column text, or gives errors when you change it to a number.
2. The idea in simple words
Power Query is the kitchen; the report is the dining table. You wash and cut the vegetables in the kitchen, once, and every dish served afterwards is clean. Every cleaning action you take is saved as a step, and Power BI replays the steps each time you refresh.
The one rule that decides what to delete:
| Column type | Examples | Blank / NA | Duplicates |
|---|---|---|---|
| Primary ID (one row = one of these) | order_id | delete the row | delete the extra rows |
| Foreign ID (points to another table) | product_id, store_id | delete the row | keep (one product sells many times) |
| Metric (numbers you add or average) | price, revenue, stock, sales | keep the row, replace NA with null | keep |
Why keep the row when a metric is missing? Because the order still happened. If revenue is unknown for one order, the order still counts in "Total orders", its units still count in "Sales" and its city still counts in a city chart. Deleting the row throws all of that away.
Why null and not 0? Null means "not known". Power BI's SUM and AVERAGE skip nulls. A 0 is a real number: it says the price was zero, and it pulls every average down.
Figure 1. Which rows to delete: blank or duplicate primary IDs and blank foreign IDs go; rows with a missing metric stay, with null in the empty cell (illustration).
3. The data
The 12 order rows (line 1 and the header line are not shown). The cells that need attention are in bold:
| # | order_id | product_id | store_id | city | order_date | sales | price | revenue | stock |
|---|---|---|---|---|---|---|---|---|---|
| 1 | BLK1001 | P101 | PUN01 | Pune | 05-04-2025 | 2$ | 120 | 240 | 35 |
| 2 | BLK1002 | P102 | NSK01 | Nashik | 05-04-2025 | 1$ | 450 | 450 | 12 |
| 3 | BLK1003 | P103 | SLP01 | Solapur | 18-04-2025 | 3$ | NA | 270 | 20 |
| 4 | BLK1003 | P103 | SLP01 | Solapur | 18-04-2025 | 3$ | NA | 270 | 20 |
| 5 | (blank) | P104 | PUN01 | Pune | 20-04-2025 | 1$ | 60 | 60 | 50 |
| 6 | BLK1004 | NA | KOP01 | Kolhapur | 02-05-2025 | 2$ | 80 | 160 | 18 |
| 7 | BLK1005 | P101 | PUN01 | Pune | 05-05-2025 | 4$ | 120 | NA | 33 |
| 8 | BLK1006 | P105 | NSK01 | Nashik | 05-05-2025 | 1$ | 999 | 999 | 7 |
| 9 | BLK1007 | (blank) | SLP01 | Solapur | 12-06-2025 | 2$ | 90 | 180 | 25 |
| 10 | BLK1008 | P102 | KOP01 | Kolhapur | 21-06-2025 | 2$ | 450 | 900 | 10 |
| 11 | BLK1009 | P103 | PUN01 | Pune | 05-07-2025 | 5$ | 90 | 450 | NA |
| 12 | BLK1006 | P105 | NSK01 | Nashik | 05-05-2025 | 1$ | 999 | 999 | 7 |
The file also has promo_type, promo_bin, delivery_date and an empty Column13. You will remove promo_bin and Column13 because no report needs them.
Before you click anything, predict with a pencil: which rows will survive? (Answer in section 5.)
4. Step by step
Load the file
- Open Power BI Desktop. Home › Get data › Text/CSV.
- Pick
blinkit-orders-small-raw.csvand click Open. - In the preview window click Transform Data (not Load). The Power Query Editor opens.
Fix the top of the table
- Home › Remove Rows › Remove Top Rows, type
1, OK. The title line is gone. - Home › Use First Row as Headers. The columns are now called order_id, product_id and so on.
Primary ID: order_id
- Click the filter arrow on order_id, untick (blank), OK. Row 5 goes.
- Click the order_id header to select it. Home › Remove Rows › Remove Duplicates. The second BLK1003 and the second BLK1006 go.
Foreign ID: product_id
- Click the filter arrow on product_id, untick (blank) and NA, OK. Rows 6 and 9 go.
- Do not remove duplicates here. P101, P102, P103 and P105 each sell more than once, and that is correct.
Remove columns you do not need
- Ctrl+click the promo_bin and Column13 headers, right-click › Remove Columns.
Metric columns: keep the rows, fix the values
- Right-click the sales header › Transform › Extract › Text Before Delimiter, type
$, OK. "2$" becomes "2". - Click the type icon (ABC) at the left of the sales header › Whole Number.
- Right-click the price header › Replace Values. Value To Find:
NA. Replace With: leave it empty. Open Advanced options and tick Match entire cell contents. OK. - Change the price type to Decimal Number. The empty cell now shows null.
- Do steps 13 and 14 for revenue.
- Do step 13 for stock, then set its type to Whole Number.
Dates written DD-MM-YYYY
- Right-click order_date › Change Type › Using Locale…. Data Type: Date. Locale: English (India). OK.
- Do the same for delivery_date.
Load and check
- Home › Close & Apply.
- Go to Table view (the grid icon on the left) and read the row count at the bottom of the screen.
Figure 2. The cleaning steps in order, with the row count after each one, for the 12-row file (illustration).
5. Your result should look like this
Table view shows 7 rows:
| order_id | product_id | store_id | city | order_date | sales | price | revenue | stock |
|---|---|---|---|---|---|---|---|---|
| BLK1001 | P101 | PUN01 | Pune | 05-04-2025 | 2 | 120 | 240 | 35 |
| BLK1002 | P102 | NSK01 | Nashik | 05-04-2025 | 1 | 450 | 450 | 12 |
| BLK1003 | P103 | SLP01 | Solapur | 18-04-2025 | 3 | null | 270 | 20 |
| BLK1005 | P101 | PUN01 | Pune | 05-05-2025 | 4 | 120 | null | 33 |
| BLK1006 | P105 | NSK01 | Nashik | 05-05-2025 | 1 | 999 | 999 | 7 |
| BLK1008 | P102 | KOP01 | Kolhapur | 21-06-2025 | 2 | 450 | 900 | 10 |
| BLK1009 | P103 | PUN01 | Pune | 05-07-2025 | 5 | 90 | 450 | null |
(Table view shows the dates in your computer's date format; the values are the same dates.)
Check these totals by hand from the table:
| Check | Value |
|---|---|
| Rows | 7 |
| Sum of sales (units) | 2 + 1 + 3 + 4 + 1 + 2 + 5 = 18 |
| Sum of revenue | 240 + 450 + 270 + 999 + 900 + 450 = ₹3,309 (BLK1005 is null and skipped) |
| Average price | (120 + 450 + 120 + 999 + 450 + 90) ÷ 6 = ₹371.50 |
6. What happened
The row count tells the story:
| Step | Rows left | Why |
|---|---|---|
| After headers | 12 | the title line is gone, all orders are still there |
| Blank order_id removed | 11 | a row with no order number cannot be counted as an order |
| Duplicate order_id removed | 9 | BLK1003 and BLK1006 appeared twice |
| Blank / NA product_id removed | 7 | an order line that points to no product cannot be linked to the product table |
| Metric steps (sales, price, revenue, stock) | 7 | values were fixed; no row was deleted |
The last line is the one to remember. The metric steps changed values, never the number of rows.
Classroom line
Never leave NA in an ID column. Never leave null there either.
Class मधलं वाक्य
"ID column madhe kadich NA thevayche nahit. Null thevayche nahit."
ID column मध्ये कधीच NA ठेवायचे नाहीत. Null पण ठेवायचे नाहीत.
Classroom line
Never leave NA in an ID column. Never leave null there either.
7. Explore further
- Every click is a step. Look at Applied Steps on the right: Source, Promoted Headers, Filtered Rows, Removed Duplicates and so on. Click any step to see the data at that moment. The next chapter uses this to fix an error.
- Blank cells become null on their own. When a number column has an empty cell, the type change turns it into null. Text such as "NA", "-" or "n/a" does not; you must replace it first.
- Why "Match entire cell contents"? Without it, Replace Values also replaces the letters NA inside a longer value in the same column, so a value such as "NA-12" would turn into "-12". With the box ticked, only cells that are exactly NA change.
- Why Using Locale for dates? A computer set to English (United States) reads 05-04-2025 as 4 May. Telling Power Query the file is English (India) makes it 5 April. Check one date you know after the change.
- Your computer matters for big files. Power BI Desktop runs on Windows and holds the data in memory, so large files need RAM. A hexa-core processor is one CPU with 6 cores; more cores and more RAM help refresh speed. If Power BI freezes, open Task Manager (Ctrl+Shift+Esc), and end the Power BI task only if it stays "Not responding", because unsaved work is lost.
8. Common mistakes
| Wrong result | Reason | Fix |
|---|---|---|
| Column names are Column1, Column2 … | The title line was used as the header | Remove Top Rows (1), then Use First Row as Headers |
| 6 rows instead of 7 | NA was filtered out of price with the filter arrow, which deletes BLK1003 | Delete that Filtered Rows step; use Replace Values on price |
| 5 rows instead of 7 | NA filtered out of price and revenue | Same fix for both columns |
| Average price ₹318.43 instead of ₹371.50 | NA was replaced with 0, so 2,229 is divided by 7, not 6 | Replace NA with an empty value so it becomes null |
| Product IDs P101, P102 … appear once each and orders go missing | Remove Duplicates was run on product_id | Remove duplicates only on the primary ID |
| sales still left-aligned (text) | The "$" was removed but the type was not changed | Set sales to Whole Number |
| Dates like 05-04-2025 show as 4 May | Type changed with the computer's US locale | Change Type › Using Locale › English (India) |
Classroom line
If you filter this out, the whole row goes, not just the one cell.
Class मधलं वाक्य
"Jar tumi he kadhun taklat... tar akkha row nighun jato."
जर तुम्ही हे काढून टाकलं, तर फक्त एक cell नाही, अख्खा row निघून जातो.
Classroom line
If you filter this out, the whole row goes, not just the one cell.
Ravindra Bagale's Tip
Before you click Close & Apply, write down how many rows you expect and why. If Table view shows fewer, open Applied Steps and click each step from the top until the count drops: the step where it drops is the step that deleted good rows.
Ravindra Bagale's Tip – मराठी
Close & Apply करण्याआधी किती rows यायला पाहिजेत आणि का, ते लिहून ठेवा. Table view मध्ये कमी rows दिसले, तर Applied Steps उघडा आणि वरून एक एक step वर click करा. ज्या step ला count कमी होतो, त्याच step ने चांगले rows delete केलेत.
Ravindra Bagale's Tip – हिंदी
Close & Apply करने से पहले लिखकर रखिए कि कितने rows आने चाहिए और क्यों. Table view में कम rows दिखें, तो Applied Steps खोलिए और ऊपर से एक-एक step पर click कीजिए. जिस step पर count कम होता है, उसी step ने अच्छे rows delete किए हैं.
9. Practise on your own
Practice task
Clean blinkit-orders-raw.csv (315 order rows) with the same steps.
- How many rows does Table view show?
- What is the sum of sales (units)?
- What is the sum of revenue?
- How many nulls are in price, revenue and stock?
Hints: the file has 12 blank order IDs and 15 repeated order rows. Some revenue cells are empty, not NA: they become null without any replace.
Show solution
| Step | Rows |
|---|---|
| After headers | 315 |
| Blank order_id removed | 303 |
| Duplicates removed | 288 |
| Blank / NA product_id removed | 274 |
- 274 rows.
- Sum of sales: 664 units.
- Sum of revenue: ₹1,69,509 (Power BI shows 169,509 with the default format).
- price: 18 nulls, revenue: 22 nulls (14 were NA, 8 were empty), stock: 10 nulls.
If you got 256 rows, you filtered NA out of price. If you got 234, you filtered NA out of price and revenue.
10. Think like a professional
- Business view. A missing revenue value is a question for the source team, not a reason to lose the order. Keep the row, show the null count in your notes ("22 orders have no revenue in the export") and ask the team to fix it at the source.
- Performance. Remove unwanted columns early. Fewer columns mean a smaller model and faster refresh.
- Maintenance. Rename steps you will need to find again (right-click a step › Rename, for example "Removed blank order_id"). Next month's file goes through the same steps on refresh.
- Check every refresh. Keep a row-count card on a hidden check page. A sudden drop after refresh means the export changed.
Interview questions
- Which rows do you delete when an ID is blank, and which when a metric is blank? Delete rows with a blank primary or foreign ID; keep rows with a blank metric and leave the metric as null.
- Why replace NA with null rather than 0? Null is skipped by SUM and AVERAGE; 0 is counted and makes averages wrong.
- Where do you remove duplicates? Only on the primary key, such as order_id.
- Why use Change Type with Locale? So DD-MM-YYYY dates are read as day-month, whatever the computer's region setting is.
Recap
In short
- Load with Transform Data, then Remove Top Rows and Use First Row as Headers.
- Primary ID: remove blanks and duplicates. Foreign ID: remove blanks, keep duplicates.
- Metric columns: never delete rows; replace NA with null.
- Extract the number before "$" and set the right types; use English (India) for dates.
- Check the row count: 12 → 11 → 9 → 7 for the small file.
Revision card