Stored Procedure Parameters in SQL Server: Input, Output, Default, and Table-Valued

Written by

in

Stored Procedure Parameters in SQL Server: Input, Output, Default, and Table-Valued

Four parameter patterns cover almost everything you’ll need to build — from a simple optional filter to passing an entire list of values into a procedure without ever concatenating a string.

Four ways to pass data in and outDEFAULT parameter@tier NVARCHAR(20)=’standard’omit it → default usedOUTPUT parametervalue flows caller ⇆ procneeds OUTPUT on BOTH sides ⚠️TABLE-VALUED parampass a whole list, READONLYtype-safe, multi-columnOLD WAY: CSV string‘Dana Park,Elena Petrova’breaks on embedded commasno type safety, one column onlyupgrade toNEW WAY: Table-Valued ParamCREATE TYPE … AS TABLE(…)many columns, real types, READONLYRemember: OUTPUT is required at the CALL SITE too —omit it there and SQL Server treats it as input-only.

Default Parameters (Optional Input)

CREATE PROCEDURE dbo.usp_CountCustomersByTier
    @tier NVARCHAR(20) = 'standard'
AS
BEGIN
    SET NOCOUNT ON;
    SELECT COUNT(*) AS customer_count FROM dbo.Customer WHERE tier = @tier;
END;
GO
EXEC dbo.usp_CountCustomersByTier; -- uses default
EXEC dbo.usp_CountCustomersByTier @tier = 'premium'; -- overrides it

OUTPUT Parameters (Returning Values to the Caller)

CREATE PROCEDURE dbo.usp_GetCustomerCount
    @tier NVARCHAR(20), @total INT OUTPUT
AS
BEGIN
    SET NOCOUNT ON;
    SELECT @total = COUNT(*) FROM dbo.Customer WHERE tier = @tier;
END;
GO

DECLARE @count INT;
EXEC dbo.usp_GetCustomerCount @tier = 'standard', @total = @count OUTPUT;
PRINT 'Standard customers: ' + CAST(@count AS VARCHAR(10));
Common mistake: Forgetting the OUTPUT keyword on the calling side, not just in the CREATE PROCEDURE definition. Without it at the call site too, SQL Server silently treats the parameter as input-only — your @count variable stays whatever it was before the call, with no error raised.

Table-Valued Parameters: The Modern Way to Pass a List

CREATE TYPE dbo.CustomerNameList AS TABLE (name NVARCHAR(100));
GO

CREATE PROCEDURE dbo.usp_GetCustomersByNames
    @Names dbo.CustomerNameList READONLY
AS
BEGIN
    SET NOCOUNT ON;
    SELECT c.customer_id, c.name, c.email
    FROM dbo.Customer c
    INNER JOIN @Names n ON n.name = c.name;
END;
GO

DECLARE @list dbo.CustomerNameList;
INSERT INTO @list VALUES ('Dana Park'), ('Elena Petrova');
EXEC dbo.usp_GetCustomersByNames @Names = @list;

TVPs are the correct, set-based way to pass a list into a procedure — far better than the old pattern of passing a comma-separated string and splitting it inside the procedure, which is exactly the kind of row-by-row string manipulation Chapter 1’s WHILE-loop lesson warned against. They’re always READONLY: you can read from them, never modify the caller’s table — attempting an UPDATE/DELETE/INSERT against @Names inside the procedure body is a compile error, by design.

The Old Way, for Comparison

-- The pre-TVP pattern (2005 and earlier, still seen in legacy code):
CREATE PROCEDURE dbo.usp_GetCustomersByNames_Legacy @NameCsv NVARCHAR(MAX) AS
BEGIN
    SELECT c.* FROM dbo.Customer c
    INNER JOIN STRING_SPLIT(@NameCsv, ',') s ON s.value = c.name; -- fragile: commas in names break it
END;

Beyond fragility with embedded delimiters, the string-splitting approach also loses type safety entirely (everything is text until parsed) and can’t easily pass more than one column of data per “row.” A TVP’s table type can have as many columns as you need, each with its own real data type.

Practice tip: Extend the CustomerNameList table type to include a second column (say, a minimum tier to filter by per name), and adjust the procedure and JOIN accordingly. Seeing a TVP carry more than one column per row is what makes its advantage over a comma-separated string genuinely click.

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.