Inline Table-Valued Functions in SQL Server: Parameterized Views That Actually Perform

Written by

in

Inline Table-Valued Functions in SQL Server: Parameterized Views That Actually Perform

An inline TVF (iTVF) is essentially a parameterized view — a single SELECT statement wrapped in a function, returning a table. Unlike scalar functions, these get inlined into the calling query’s execution plan, which is why this lesson comes with none of the previous one’s performance warnings.

Inlined into the plan, like a viewDept: SalesDept: EngDept: HRCROSS APPLYGetEmployeesByDept()single SELECT bodyinlines = same plan as the JOINscalar / mTVFoptimizer treats it as aBLACK BOXProof, not faith: in SSMS pressCtrl+M and compare plans — a trueiTVF’s plan is IDENTICAL to the JOIN. 🔍

Writing and Using One

CREATE FUNCTION dbo.GetEmployeesByDepartment (@dept NVARCHAR(50))
RETURNS TABLE
AS
RETURN (
    SELECT employee_id, first_name, last_name, salary
    FROM dbo.Employee
    WHERE department = @dept
);
GO

SELECT * FROM dbo.GetEmployeesByDepartment('Engineering');

-- Can be joined just like a table
SELECT e.first_name, e.salary
FROM dbo.GetEmployeesByDepartment('Sales') e
WHERE e.salary > 60000;

-- Can even be CROSS APPLY'd per row of another table (covered fully in Chapter 6)
SELECT d.department_name, top_earner.first_name
FROM dbo.Department d
CROSS APPLY (SELECT TOP 1 * FROM dbo.GetEmployeesByDepartment(d.department_name) ORDER BY salary DESC) top_earner;

That last example is worth pausing on: an iTVF can take a value from the outer query as its parameter, once combined with CROSS APPLY — something a plain view can never do, since a view has no parameters at all. This is one of the most useful, distinctly-SQL-Server patterns in the whole language.

Why iTVFs Perform Well

Inline TVF Single SELECT body Optimizer sees inside it Scalar / mTVF Procedural body Optimizer treats as a black box

Because SQL Server can see straight into an iTVF’s single SELECT, it substitutes the function call with the equivalent SQL directly — conceptually similar to how a compiler inlines a small function — and produces accurate row estimates, exactly as if you’d hand-written the JOIN yourself. No separate execution step, no performance penalty, no black-box row-count guessing.

Proving the Inlining, Not Just Trusting It

-- Compare the execution plan of the function call...
SELECT * FROM dbo.GetEmployeesByDepartment('Engineering') WHERE salary > 70000;

-- ...against the hand-written equivalent. In SSMS, enable "Include Actual Execution Plan"
-- (Ctrl+M) for both and compare — for a true iTVF, the plans are identical.
SELECT employee_id, first_name, last_name, salary
FROM dbo.Employee WHERE department = 'Engineering' AND salary > 70000;
Practice tip: Run both queries above with the actual execution plan visible and confirm they’re the same shape. This is the single best way to build real trust in “iTVFs are free” instead of just accepting it as a rule to memorize.

The One Real Limitation

An iTVF’s body must be exactly one SELECT statement — no variables, no IF/ELSE, no intermediate steps. The moment your logic needs a second statement (populate a temp result, then filter it based on something computed in step one), you’ve outgrown an iTVF and need either a multi-statement TVF (next lesson) or a restructured single query using a CTE, which often accomplishes the same goal without leaving iTVF territory at all.


Enjoyed this?

Subscribe to get every new SQL Server lesson as soon as it’s published, and share it with a developer who’d find it useful.

📡 Subscribe via RSS  | 
Share on X  | 
Share on LinkedIn  | 
Share on Facebook

Want the full structured course with quizzes, projects, and 10+ exercises per chapter? Check out SQL Server for Developers & DBAs, coming soon on this site.