Table.FirstN() & Table.Skip()
Learn how Table.FirstN and Table.Skip work with a row count, and why passing a condition function instead makes them stop at the first row that fails it — a "take while," not a filter over the whole table.
Table.FirstN() & Table.Skip()
Table.FirstN() returns the first N rows of a table; Table.Skip() returns everything after skipping the first N. Both also accept a condition function instead of a number — and that form works differently than it looks.
Table.FirstN(table as table, countOrCondition as any) as table
Table.Skip(table as table, countOrCondition as any) as tableBasic Example
Table.FirstN(Source, 3)Returns the first 3 rows, in whatever order the table currently has — see Table.Sort() first if the order matters.A Condition Function Is "Take While," Not a Filter
Try it live
Table.FirstN(Source, each [Amount] > 100)
| Amount |
|---|
| 150 |
| 200 |
| 50 |
| 300 |
Table.SelectRows(Source, each [Amount] > 100)
| Amount |
|---|
| 150 |
| 200 |
| 50 |
| 300 |
Passing a function instead of a number doesn't filter the whole table down to matching rows — it takes rows from the top only until the condition first fails, then stops immediately, even if a later row would satisfy it again. That's a fundamentally different operation from Table.SelectRows(), which examines every row regardless of position.
Table.FirstN(Source, each [Amount] > 100) -- stops at the first non-matching row
Table.SelectRows(Source, each [Amount] > 100) -- keeps every matching row, in any positionTable.Skip() with a condition mirrors this: it skips rows from the top while the condition holds, then returns everything from the first failure onward — including any later row where the condition happens to hold again.
Common Mistakes
Expecting Table.FirstN's Condition Form to Filter the Whole Table
As covered above — this is the single most common mix-up. If the goal is genuinely "every row matching this condition," Table.SelectRows() is the right function; Table.FirstN()'s condition form is for "the leading run of rows matching this," which silently misses any matching row that comes after the first non-match.
Assuming Row Order Doesn't Matter for the Condition Form
Since Table.FirstN()'s condition form stops at the first failure, its result depends entirely on the table's current row order — sorting first with Table.Sort() changes which rows the "take while" actually captures.
Using the Condition Form When a Plain Count Was Intended
Table.FirstN(Source, 3) and Table.FirstN(Source, each [SomeCondition]) look similar but do genuinely different things — double-check which form is actually being used, especially when the second argument was copied from elsewhere in the query.
Best Practices
- Reach for
Table.SelectRows()when the goal is every matching row; reserveTable.FirstN()'s condition form for a genuine "leading run" scenario. - Sort explicitly before using the condition form of
Table.FirstN()orTable.Skip(), since the result depends on row order. - Prefer the plain numeric form when a fixed row count is really what's needed — it's less ambiguous to read later than a condition that happens to behave like a count.
Next Steps
Table.SelectColumns() and MissingField
Learn how Table.SelectColumns keeps only the specified columns, why requesting a column that doesn't exist errors by default, and how the MissingField option (Ignore or UseNull) changes that instead of the query breaking on the next refresh.
DateTime.LocalNow() and the Desktop-vs-Service Trap
Learn why DateTime.LocalNow returns a different value in Power BI Desktop than it does during a scheduled refresh in the Service, and why DateTimeZone.UtcNow (or a fixed local time) is usually the more reliable choice.