Table.SelectRows()
Learn how Table.SelectRows filters a table with a per-row condition, how to combine multiple conditions, and the case-sensitivity and null-comparison mistakes that trip people up.
Table.SelectRows()
Table.SelectRows() filters a table down to the rows matching a condition — the function behind every filter arrow in the Power Query Editor.
Table.SelectRows(
table as table,
condition as function
) as tableBasic Example
#"Filtered Rows" = Table.SelectRows(
Source, each [Status] = "Active"
)Status Status
Active -> Active <- kept
Inactive Active <- kept
Activeeach [Status] = "Active" runs once per row, keeping only the rows where it evaluates to true.
Combining Multiple Conditions
#"Filtered Rows" = Table.SelectRows(
Source, each [Status] = "Active" and [Amount] > 100
)and requires both conditions true; or requires at least one. Parentheses control evaluation order exactly like any other logical expression:
#"Filtered Rows" = Table.SelectRows(
Source,
each [Status] = "Active" and ([Region] = "West" or [Region] = "East")
)Without the parentheses, and binds tighter than a bare sequence of ors might suggest — being explicit with parentheses once a condition has more than two parts avoids relying on precedence rules that aren't always obvious at a glance.
Common Mistakes
Assuming Text Comparison Is Case-Insensitive
each [Status] = "active"M's = comparison on text is case-sensitive — "Active" and "active" are not equal. A source with inconsistent casing silently drops rows that look like they should match.
Fix: normalize case explicitly when it can't be trusted.
each Text.Lower([Status]) = "active"Confusing null With an Empty String
each [Notes] = nullUnlike SQL, M's = comparison works intuitively against null — this correctly returns true for a genuinely blank cell. The real mistake is assuming every blank-looking cell is null: a source like a CSV export can produce an empty string "" instead of a true null for what looks identical in the preview grid. [Notes] = null won't match a cell that's actually "", and vice versa.
Fix: check which one is actually present — click a blank-looking cell's value, or add a quick Table.AddColumn(Source, "Check", each Value.Is([Notes], type null)) — before assuming which comparison applies.
Filtering After an Expensive Step Instead of Before
Source -> Added Custom (slow, row-by-row) -> Filtered RowsPlacing Table.SelectRows() after a slow custom column means the expensive computation runs for rows that get filtered out immediately afterward. Filtering as early as possible — ideally as the very next step after Source — reduces the row count before any later step has to process it, and keeps the query eligible for query folding if the filter itself can fold.
Referencing a Column Before It's Renamed or Created
A filter step referencing [Status] fails if it's placed before the step that creates or renames that column — M evaluates the table shape as of the step immediately before the filter, not the query's eventual final shape.
Next Steps
Getting "We cannot convert the value null to type Table"? A filter is rarely the actual cause — see that error explained for where it usually really comes from.