Table-Valued Parameters need an alias!
I’m always the one to say RTFM but this one stumped me for a while. I had problems using a Table-Valued Parameter in a Stored Procedure today.
The explanation is indeed in the documentation but it’s perhaps not as clear as it should be. Hopefully this post will be picked up better in Google for those having similar issues.
Here’s a quick outline of the problem…
Firstly, create a TVP type, just a simple list of integers…
-- Create a simple TVP CREATE TYPE dbo.ListOfIntegers AS TABLE ( id INTEGER NOT NULL PRIMARY KEY CLUSTERED ); GO |
Now let’s create a simple proc using this type.
-- Simple proc using this tvp CREATE PROCEDURE dbo.testtvp ( @table AS dbo.ListOfIntegers READONLY ) AS BEGIN SELECT * FROM @table; END GO |
Does it work?
-- Let's use it! DECLARE @table AS dbo.ListOfIntegers; INSERT INTO @table (id) VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10); EXEC dbo.testtvp @table; GO |
OK, that works, let’s try something a little more complicated…
-- OK, that works, how about this.... CREATE PROCEDURE dbo.testtvp2 ( @table AS dbo.ListOfIntegers READONLY, @table2 AS dbo.ListOfIntegers READONLY ) AS BEGIN SELECT * FROM @table INNER JOIN @table2 ON @table.id = @table2.id END GO |
This will not compile…
-- Get the following errors
Msg 137, Level 16, State 1, Procedure testtvp2, Line 12
Must declare the scalar variable @table.
Msg 137, Level 16, State 1, Procedure testtvp2, Line 12
Must declare the scalar variable @table2.
The documentation does indeed say; "When you use a table-valued parameter with a JOIN in a FROM clause, you must also alias it" but it’s perhaps not as prominent as it could be. So let’s alias the Table-Valued Parameters…
CREATE PROCEDURE dbo.testtvp3 ( @table AS dbo.ListOfIntegers READONLY, @table2 AS dbo.ListOfIntegers READONLY ) AS BEGIN SELECT * FROM @table AS t1 INNER JOIN @table2 AS t2 ON t1.id = t2.id END GO |
This will compile and function as expected…
DECLARE @table AS dbo.ListOfIntegers; INSERT INTO @table (id) VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10); DECLARE @table2 AS dbo.ListOfIntegers; INSERT INTO @table2 (id) VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10); EXEC dbo.testtvp3 @table, @table2; GO |
Happy TSQL’ing!