Prepare Data · Topic 5 of 7
Clean, Convert and Filter Data
Find and fix duplicates, missing data and nulls, convert data types and filter rows in Fabric with T-SQL, PySpark and Power Query in Dataflow Gen2.
- 5 min
- Power Query profiling uses the top 1,000 rows unless you switch to the entire data set.
ROW_NUMBER() OVER (PARTITION BY ... ORDER BY ...)keeps a chosen row per key;DISTINCTremoves only exact duplicates.COALESCEandISNULLreplace nulls in T-SQL;fillnaanddropnado it in PySpark.
What it is
Raw data is rarely clean. The same customer appears twice, a region is empty, a date arrives as text in a regional format, and test orders sit next to real ones.
Cleaning fixes these problems before the data reaches a star schema or a semantic model. The DP-600 exam expects you to recognise each problem and pick the right fix in T-SQL, PySpark or Power Query (Dataflow Gen2).
How it works
Profile the data first
Power Query in Dataflow Gen2 and Power BI Desktop shows data profiling on the View tab:
| Option | Shows |
|---|---|
| Column quality | Percentage of valid, error and empty values |
| Column distribution | Count of distinct and unique values |
| Column profile | Statistics and a value distribution for one column |
By default the profile uses only the top 1,000 rows. Switch it to the entire data set from the status bar before you trust it.
Duplicates
| Tool | Remove exact duplicates | Keep one row per key |
|---|---|---|
| T-SQL | SELECT DISTINCT | ROW_NUMBER() OVER (PARTITION BY key ORDER BY ...) and keep row 1 |
| PySpark | df.dropDuplicates() | df.dropDuplicates(["CustomerID"]) |
| Power Query | Remove duplicates on all columns | Remove duplicates on the key columns |
When you must keep a specific row, such as the latest version, rank the rows:
WITH ranked AS (
SELECT *,
ROW_NUMBER() OVER (
PARTITION BY CustomerID
ORDER BY ModifiedDate DESC) AS rn
FROM stg.Customer
)
SELECT CustomerID, CustomerName, Region, ModifiedDate
FROM ranked
WHERE rn = 1;
dropDuplicates on a key keeps one row per key, but you do not control which one. Use a window function when the choice matters.
Missing data and nulls
SELECT OrderID,
COALESCE(Region, 'Unknown') AS Region,
ISNULL(Discount, 0) AS Discount
FROM stg.Orders
WHERE OrderID IS NOT NULL;
clean = (df
.dropna(subset=["OrderID"])
.fillna({"Region": "Unknown", "Discount": 0}))
In Power Query, use Replace values to turn null into a default, Fill down when a value is only written on the first row of a group, Remove rows > Remove blank rows, and Replace errors for cells that failed a conversion.
Decide per column whether a null means "unknown", "zero" or "drop the row". Replacing a missing sales amount with 0 changes averages, so it is a business decision, not only a technical one.
Converting data types
| Tool | Example |
|---|---|
| T-SQL | CAST(Amount AS decimal(18,2)); TRY_CAST(Amount AS decimal(18,2)) returns NULL instead of failing |
| PySpark | F.col("Amount").cast("decimal(18,2)"); F.to_date("OrderDate", "dd/MM/yyyy") |
| Power Query | Table.TransformColumnTypes or Change type, with Using locale for regional formats |
Table.TransformColumnTypes(Source, {{"OrderDate", type date}, {"Amount", type number}}, "en-GB")
The culture argument "en-GB" makes Power Query read 03/04/2026 as 3 April, not 4 March. Wrong types also hurt later: a key stored as text in one table and as an integer in another does not relate cleanly in a semantic model, so give both key columns the same type.
Filtering
Table.SelectRows(Source, each [Status] <> "Cancelled" and [OrderDate] >= #date(2024, 1, 1))
from pyspark.sql import functions as F
orders = df.filter((F.col("Status") != "Cancelled") & (F.col("OrderDate") >= "2024-01-01"))
Filter as early as possible. In Power Query, early filters on a database source usually fold, which means they are sent to the source as part of its query, so less data is transferred.
A worked example
A customer file loaded into a lakehouse has 5% duplicate customers, blank regions, dates as dd/MM/yyyy text and test accounts whose names start with "TEST".
- Profile the file on the full data set to measure each problem.
- Rank rows per
CustomerIDbyModifiedDateand keep the newest one. - Replace blank regions with
Unknown. - Convert the date with
to_date(..., "dd/MM/yyyy")or with Change type using theen-GBlocale. - Filter out rows whose name starts with "TEST", then write the clean table.
When a question says "keep the most recent record for each customer", the answer is a window function such as ROW_NUMBER(), not DISTINCT.
How the exam asks about this
- "A conversion must not fail when some values are not numbers."
TRY_CAST, which returns NULL for bad values. - "Dates such as 03/04/2026 load as the wrong month." Change type using locale with the right culture.
- "Only the first row of each group has the category filled in." Fill down in Power Query.
What to remember for the exam
- Power Query profiling uses the top 1,000 rows unless you switch to the entire data set.
ROW_NUMBER() OVER (PARTITION BY ... ORDER BY ...)keeps a chosen row per key;DISTINCTremoves only exact duplicates.COALESCEandISNULLreplace nulls in T-SQL;fillnaanddropnado it in PySpark.TRY_CASTreturns NULL instead of an error; Using locale fixes regional date and number formats.- Filter early so Power Query can fold the filter to the source.
In SQL, WHERE Region = NULL returns no rows. Test for missing values with IS NULL or IS NOT NULL.
Common mistakes
Trusting a profile of 1,000 rows. Problems further down the table stay hidden. Profile the entire data set for a real picture.
Replacing every null with zero. A missing value and a real zero mean different things. Choose per column, and use Unknown for missing attributes.
Changing types without the right locale. The conversion succeeds but swaps day and month. Set the culture to the format the source uses.
Check yourself
How do you keep only the newest row for each customer in T-SQL?
Number the rows with
ROW_NUMBER() OVER (PARTITION BY CustomerID ORDER BY ModifiedDate DESC)and keep the rows where the number is 1.What does
TRY_CASTreturn when a value cannot be converted?NULL, instead of failing the whole query.
Why can a Power Query profile miss errors?
By default it profiles only the top 1,000 rows. Switch it to the entire data set.
Topic 5 of 7 in Prepare Data
Test yourself on Prepare Data
The full Microsoft DP-600 question bank has 648 questions, with timed practice exams and an explanation for every answer.
This study guide is independent and is not affiliated with, endorsed by, or sponsored by Microsoft. Vendor names, certification names and exam codes are trademarks of their respective owners and are used for identification only.