What this quiz covers
This quiz focuses on Parameters And Functions In Power Query, giving you a quick way to practice the rules, question types, and explanations that matter most for Microsoft Power BI.
An existing query named FilteredOrders filters a table by a hard-coded date. You want to convert its logic into a reusable function that accepts both a source table and a cutoff date.
Which M definition correctly implements the function?
(SourceTable as table, CutoffDate as date) as table => let Filtered = Table.SelectRows(SourceTable, each [OrderDate] >= CutoffDate) in Filteredlet SourceTable as table, CutoffDate as date, Filtered = Table.SelectRows(SourceTable, each [OrderDate] >= CutoffDate) in Filtered(SourceTable as table, CutoffDate as date) => Table.SelectRows(FilteredOrders, each [OrderDate] >= FilteredOrders[CutoffDate])function(SourceTable, CutoffDate) as table = Table.SelectRows(SourceTable, each [OrderDate] >= CutoffDate)Microsoft Power BI Quiz
Practice Parameters And Functions In Power Query in Microsoft Power BI with focused quiz questions that help you check what you know, review explanations, and build confidence with test-style prompts.
This quiz focuses on Parameters And Functions In Power Query, giving you a quick way to practice the rules, question types, and explanations that matter most for Microsoft Power BI.
Try each quiz question before looking at the correct answer. Use the explanations to review missed ideas, then come back to similar questions until the pattern feels familiar.
An existing query named FilteredOrders filters a table by a hard-coded date. You want to convert its logic into a reusable function that accepts both a source table and a cutoff date.
Which M definition correctly implements the function?
(SourceTable as table, CutoffDate as date) as table => let Filtered = Table.SelectRows(SourceTable, each [OrderDate] >= CutoffDate) in Filtered (correct answer)let SourceTable as table, CutoffDate as date, Filtered = Table.SelectRows(SourceTable, each [OrderDate] >= CutoffDate) in Filtered(SourceTable as table, CutoffDate as date) => Table.SelectRows(FilteredOrders, each [OrderDate] >= FilteredOrders[CutoffDate])function(SourceTable, CutoffDate) as table = Table.SelectRows(SourceTable, each [OrderDate] >= CutoffDate)=>, and then the expression body.
Answer A is correct because it follows this exact pattern precisely. The parameters SourceTable and CutoffDate are declared with their types inside parentheses, as table declares the return type, and the => introduces the body. Inside, a let...in block filters using the passed-in parameters — making it fully reusable and self-contained.
Answer B wraps everything inside a let expression without a function signature at all. There are no parentheses or =>, so this defines a regular query, not a function. The type annotations inside let are also syntactically invalid in M.
Answer C uses the correct outer signature structure, but inside the body it references FilteredOrders (the original hard-coded query) instead of SourceTable, and tries to access FilteredOrders[CutoffDate] as if it were a column — completely defeating the purpose of parameterization.
Answer D uses function(...) which is not valid M syntax at all. M does not use the keyword function to declare functions, and the = assignment operator is not how function bodies are introduced — that role belongs to =>.
A helpful pattern to memorize: every M function starts with (params) =>. If you see anything else opening the definition — a let, the word function, or no arrow — it's wrong.A list query named Years contains the values 2023, 2024, and 2025. A function named fnGetYear accepts one year as a number and returns a table of transactions for that year. You need one combined transaction table.
Which expression should you use?
Table.Combine(fnGetYear(Years)) because Table.Combine automatically invokes the function once for every list item.List.Combine(List.Transform(Years, each fnGetYear(_))) because each returned table must first be combined as a list.fnGetYear(Table.FromList(Years)) because converting the list to a table creates one function call per row.Table.Combine(List.Transform(Years, each fnGetYear(_))) because the list is mapped to tables before they are combined. (correct answer)List.Transform to map each item through a function, and Table.Combine to stack the resulting tables into one. Keeping those roles distinct is the key to answering this question correctly.
List.Transform(Years, each fnGetYear(_)) iterates over each year value (2023, 2024, 2025), calls fnGetYear once per value, and returns a list of tables. Table.Combine then accepts that list of tables and stacks them vertically into a single unified table. That's exactly what option D does — and why it's correct.
Option A is tempting but wrong: Table.Combine does not automatically invoke a function. It expects a list of already-materialized tables, not a function reference. Passing fnGetYear (a function) and Years (a list) directly into Table.Combine like this would cause a type error.
Option B misuses List.Combine, which merges lists together — not tables. Even if each fnGetYear call returns a table, wrapping those tables in List.Combine produces a flat list, not a combined table. You'd lose the table structure entirely.
Option C misunderstands how Table.FromList works. Converting the list to a table doesn't automatically call fnGetYear once per row — you'd still need an explicit transformation step to invoke the function against each value.
Study tip: Memorize this two-step pattern cold — List.Transform to apply, Table.Combine to stack. It appears frequently in Power Query scenarios involving dynamic data retrieval.You use Combine Files on a folder containing monthly CSV files with identical structures. Power Query creates helper queries, including a sample-file transformation and a function. Later, a new column must be removed from every imported file before the results are appended.
Where should you make the transformation so that it is applied consistently to every file?
Content value no longer includes the unwanted CSV column.Content column represents raw file bytes), not parsed column data. You can't filter CSV columns at the binary level before parsing.
D confuses the role of the helper parameter. The parameter identifies the sample file to use for building the transformation — it doesn't accept column names or act as a filter for unwanted fields.
As a study tip, remember: in a Combine Files workflow, the sample-file transformation is your universal edit point — think of it as the template every file inherits.A reusable text-import function normally uses a comma delimiter, but some callers must specify a different delimiter. Existing calls that supply only the input binary must continue to work.
Which function design best meets the requirement?
optional with a type like nullable text. Inside the function body, you check whether the argument is null and substitute a sensible default — in this case, a comma. This means existing callers that pass only the binary input continue to work without modification, while new callers can supply a custom delimiter when needed. That's precisely what A describes, making it the correct design pattern.
B fails because making the delimiter a required argument breaks all existing calls that don't supply one — the opposite of the stated requirement. Forcing a Power Query parameter also adds unnecessary configuration overhead for every caller.
C sounds clever but is brittle in practice. Auto-detecting delimiters from the first line is unreliable (what if the first line is a header with no consistent delimiter signal?), and it removes explicit control from the caller entirely. The requirement asks for callers to specify a different delimiter, not for the function to guess.
D creates maintenance duplication. Managing two separate functions that do essentially the same job means any future changes must be applied twice, and renaming queries to switch logic is fragile and unconventional — not a scalable design.
Your study tip: whenever a Power Query question mentions "existing calls must still work," immediately think optional parameters with null substitution — that's the M-language idiom for backward-compatible function design.A folder contains 200 files. A custom function successfully transforms most files, but several malformed files cause errors. You must retain all file rows and identify which files failed, including the error details.
How should you invoke the function?
try fnTransform([Content]) otherwise null, then filter null values and infer that the omitted files were malformed.try fnTransform([Content]), then expand the resulting record to inspect HasError, Value, and Error information. (correct answer)try expression around the entire folder query so that any function error returns the untransformed folder table.try expression becomes essential.
The try keyword in Power Query M wraps an expression and returns a record with three fields: HasError (a boolean), Value (the successful result), and Error (a record describing what went wrong). When you write try fnTransform([Content]) for each row and then expand that resulting record column, you get full visibility into both successes and failures — all 200 rows remain intact. This makes C the correct approach: you retain every file's row, and you can filter or inspect based on HasError to pinpoint exactly which files failed and why.
Option A fails because Remove Errors permanently discards error rows, so you lose the malformed files entirely rather than identifying them. You'd only know how many failed, not which ones or what went wrong.
Option B uses try ... otherwise null, which collapses the rich error record into a plain null. You lose all error detail — you can only infer that something failed, not diagnose why. This violates the requirement to capture error details.
Option D wraps the entire folder query in a single try, meaning one error could suppress the whole table rather than isolating individual file failures. It provides no per-row granularity whatsoever.
As a study tip: whenever a Power BI question asks you to retain rows AND capture error details, think try without otherwise — expand the record to get HasError, Value, and Error fields per row.A function is declared as (Input as table) as table and immediately uses Table.TransformColumnTypes. A folder query invokes the function by passing [Content], which contains each file as a binary value. Every invocation returns a type error.
What is the best correction?
table to any while leaving the existing table transformation as the first function step.Table.FromList({[Content]}) before invoking the existing function.Binary.Buffer to [Content] before invocation so that the function receives a materialized table value.[Content] column — raw bytes, not tables. The critical insight here is that a function expecting a table input will always fail when handed a binary value, no matter how you adjust surrounding logic.
The correct fix, D, addresses the root cause: the function itself must be redesigned to accept a binary, use the appropriate connector (like Excel.Workbook, Csv.Document, or Pdf.Tables) to parse it into a table, and then apply Table.TransformColumnTypes. This creates a complete, self-contained transformation that correctly handles what the folder query actually provides.
Option A is tempting but misguided. Changing the parameter type to any suppresses the type error at the signature level, but Table.TransformColumnTypes still receives a binary value internally — you've just moved the crash one step later. Option B attempts to wrap the binary in a list and convert it to a table row, but Table.FromList({[Content]}) produces a table containing the binary as a cell value, not a parsed, structured table. The type mismatch persists in a different form. Option C confuses Binary.Buffer with parsing — buffering loads binary data into memory for performance reasons, but it does absolutely nothing to convert bytes into a structured table.
The key study tip: in Power BI, parsing and transformation are always separate steps. Connectors parse; transformation functions like Table.TransformColumnTypes operate on already-structured data. Never assume a function designed for tables can accept raw binary input.A semantic model uses a Power Query parameter as the server argument to Sql.Database. After publication, an administrator changes the parameter from an on-premises test server to an on-premises production server. The next refresh reports that the data source cannot be accessed.
What should the administrator do?
A query reads a large SQL table. A date parameter named StartDate determines the earliest rows required. The data source supports query folding, and minimizing transferred rows is a priority.
Which design is most likely to preserve source-side filtering while still making the date reusable?
StartDate directly in an early Table.SelectRows step and verify that the step continues to fold to SQL. (correct answer)StartDate to text, append it to every imported row, and filter the resulting text column after all transformations.StartDate, and exclude earlier rows from report visuals.StartDate directly inside Table.SelectRows at an early pipeline stage gives Power Query the best chance to fold that filter into a WHERE clause. You can confirm folding is active by right-clicking the step and checking whether "View Native Query" is available. This approach also keeps StartDate reusable as a parameter across multiple queries or refreshes.
Option A breaks folding entirely. Custom functions invoked row-by-row force Power Query to evaluate each row locally after a full table download — the opposite of what you want. Option C converts the date to text and filters a derived column, which introduces unnecessary complexity and almost certainly breaks the fold chain, since string manipulation on a non-source column can't be translated back to SQL. Option D moves filtering to DAX inside the report layer, which means the entire table has already been imported into the model — no rows were ever filtered at the source, defeating the purpose entirely.
Your study tip: whenever a Power BI question mentions "minimizing transferred rows" alongside a query folding-capable source, think early Table.SelectRows with a parameter. Late or model-layer filtering never reduces what's imported.A Power BI Desktop file is deployed to development, test, and production environments. Each environment uses the same SQL database schema but a different server name. The query transformations must remain identical across environments.
Which design provides the most maintainable way to switch environments?
Sql.Database source expression. (correct answer)Sql.Database() function call. When you need to switch environments, you update a single parameter value — your transformation steps remain completely unchanged. This separation of configuration from logic is the foundation of maintainable deployments, and it integrates natively with Power BI's deployment pipelines, which support parameter overrides per environment.
Option A misuses a What-if parameter, which is a DAX-based tool designed to drive slicer-driven scenario analysis in reports. It has no role in Power Query source configuration and cannot be referenced inside Sql.Database().
Option C is an anti-pattern. Duplicating queries for each server multiplies your maintenance burden — any transformation change must be replicated across all three copies, which defeats the purpose of keeping transformations identical and introduces human error risk.
Option D is fundamentally mismatched. DAX calculated columns exist in the semantic model layer and run after data is already loaded; they cannot influence how the data connection is established at query time.
Study tip: On Power BI exam questions involving environment management or source switching, Power Query parameters are almost always the right tool — remember they live in the M layer, not the DAX layer.A folder query returns one row per file. Each row contains a Content binary column and a Region text column. A function named fnTransform accepts a binary value and a region value, then returns a standardized table. The results from all files must be combined.
What should you do in the folder query?
Region column to one call of fnTransform, then expand the returned table.Region to a single text parameter, call fnTransform once, and merge the result with the folder query.fnTransform([Content], [Region]), expand the returned tables, and remove unneeded metadata columns. (correct answer)Content binary column first, group the rows by Region, and call fnTransform once for each group.Region value paired with its corresponding Content binary. This is a classic row-by-row function application pattern.
The right approach is C: add a custom column using fnTransform([Content], [Region]). Since fnTransform is designed to accept one binary and one region value at a time, you invoke it once per row by referencing the column names directly inside the custom column formula. This passes each row's Content and Region together, and the function returns a standardized table for that file. You then expand those nested tables into a flat result and remove metadata columns like Name, Date modified, etc., that the folder connector automatically includes.
A is wrong because fnTransform takes scalar inputs (one binary, one text value), not an entire table. Passing the whole folder table isn't how the function is designed, and Power Query doesn't auto-iterate a multi-input function across a table like that.
B is wrong because converting Region to a single text parameter loses the per-row region context entirely. You'd also only call fnTransform once, meaning all files would be processed with one region value — discarding the row-level relationship.
D is wrong because expanding a binary column doesn't make sense — binaries must be transformed, not expanded. Grouping by Region before calling fnTransform also breaks the per-file granularity the function expects.
Study tip: Whenever a custom function needs per-row inputs from multiple columns, your go-to move is always a custom column with fnFunctionName([Col1], [Col2]) — let Power Query handle the row-by-row iteration automatically.