Getting Error Msg: Must declare the scalar variable - sql-server

I used this code in SQL Server:
CREATE TYPE ExampleType AS TABLE (Number INT)
GO
CREATE FUNCTION GetExampleTableType(#InputNumber INT)
RETURNS ExampleType
AS
BEGIN
DECLARE #OutputTable ExampleType;
INSERT INTO OutputTable
VALUES (#InputNumber);
RETURN(#OutputTable);
END;
GO
But I got an error:
Must declare the scalar variable "#OutputTable"
I have declared #OutputTable but it cannot be a scalar value, it must be a table.
What is wrong?

You are trying to return table variable from scalar valued User defined function. You need to convert the function as given below to store the values into the table valued parameter.
Also, read this StackOverFlow Post, where you cannot return UDT from table valued function.
CREATE TYPE ExampleType AS TABLE (Number int)
GO
CREATE Function GetExampleTableType(#InputNumber int)
RETURNS Table
AS
RETURN
(SELECT #InputNumber AS int);
DECLARE #OutputTable ExampleType
INSERT INTO #OutputTable
SELECT * FROM dbo.GetExampleTableType (1);

Actually you don't need to create a user-defined table type. You can directly give table instead of that.
Query
CREATE Function GetExampleTableType(#InputNumber int)
RETURNS #OutputTable TABLE
(
Number int
)
AS
BEGIN
INSERT INTO #OutputTable VALUES (#InputNumber);
RETURN;
END;

As per my understanding we can use tabletype variables to pass as arguments to functions and stored procedures but not used in multistatemnet table valued functions like you mentioned in the question. But in your example you try to access tabletype variable in returns clause which is syntactically incorrect.
This is what i have as sample code here to use tabletype variables in functions context.. please let me know if any thing i missed to understand your question...
CREATE TYPE TableType
AS TABLE (LocationName VARCHAR(50))
GO
CREATE FUNCTION Example( #TableName TableType READONLY)
RETURNS VARCHAR(50)
AS
BEGIN
DECLARE #name VARCHAR(50)
SELECT #name = LocationName FROM #TableName
RETURN #name
END
DECLARE #myTable TableType
INSERT INTO #myTable(LocationName) VALUES('aaa')
SELECT dbo.Example(#myTable)

Table-valued parameters have the following restrictions:
SQL Server does not maintain statistics on columns of table-valued parameters.
Table-valued parameters must be passed as input READONLY parameters to Transact-SQL routines. You cannot perform DML operations such as UPDATE, DELETE, or INSERT on a table-valued parameter in the body of a routine.
You cannot use a table-valued parameter as target of a SELECT INTO or INSERT EXEC statement. A table-valued parameter can be in the FROM clause of SELECT INTO or in the INSERT EXEC string or stored procedure.
Reference: https://learn.microsoft.com/en-us/sql/relational-databases/tables/use-table-valued-parameters-database-engine?view=sql-server-2017

Related

SQL Server stored procedure: Must declare the scalar variable

DECLARE #occurrences TABLE (Occurrences int)
BEGIN
SET #occurrences = (SELECT Occurrences FROM [Data])
END
Why this is not possible to execute? I want to read into a table all the columns of a given table within my stored procedure so I can update later another table.
Is this fundamentally wrong?
The exact error that SQL Server throws is:
Must declare the scalar variable "#occurrences"
Table variables are different than scalar variables. So you need
DECLARE #occurrences TABLE (Occurrences int)
BEGIN
insert #occurrences
SELECT Occurrences FROM [Data]
END

Pass test data to table-valued parameter within SQL

Is it possible, and if so how, to pass data to a table-valued parameter of a stored function using SQL EXEC?
I know how to pass in data from C#. One of my four stored procs using table-valued parameters is not producing the expected results. I'd like to execute my proc from SQL server management studio for debugging purposes, but I am unable to find the correct syntax for doing so, if such a syntax even exists. I haven't found anything relevant in the docs.
My type table:
CREATE TYPE [MyNameSpace].[MyTypeTable] AS TABLE(
//... all my fields
)
My stored proc:
//... bunch of stuff
ALTER PROCEDURE [MyNameSpace].[MyStoredProc]
#MyTypeTableVar MyTypeTable READONLY
AS
BEGIN
//Do a bunch of stuff
//Want to test the stuff in here
END
I have tried:
IF OBJECT_ID('tempdb.dbo.#MyTempTable') IS NOT NULL DROP TABLE tempdb.dbo.#MyTempTable;
select top 0 *
into #MyTempTable
//existing table with structure that matches the table-valued param
from MyNameSpace.MyTable;
//...Long insert statement assigning test data to #MyTempTable
EXECUTE MyNameSpace.MyStoredProc #MyTypeTableVar = #MyTempTable;
which throws:
Operand type clash: nvarchar is incompatible with MyTypeTable
You can't use a temp table - you have to use a table variable:
declare #t [MyNameSpace].[MyTypeTable]
insert into #t (/*columns*/) values
(/* first row */),
(/* second row */)
EXECUTE MyNameSpace.MyStoredProc #MyTypeTableVar = #t;
(You can populate it with either INSERT ... VALUES as shown above or INSERT ... SELECT if you have an existing table containing the data you care about)
Here's a working example:
-- Declare a table parameter
DECLARE #registryUpdates AS typ_KeyValuePairStringTable;
-- Insert one row
INSERT INTO #registryUpdates
VALUES ('Hello', 'World');
-- Call Stored Procedure
EXEC prc_UpdateRegistry #registryUpdates

What is the mandatory nature of User Defined Tables in Stored Procedures

At the company I work there are a range of stored procedures which take a user-defined table as an input parameter and is it happens this is not always needed for the procedure being used. In SSMS if write an Execute statement without defining the UDT I get the error line with a tooltip telling me the procedure expects the table to be provided, but if I try to run without providing the table it works just fine.
This makes me assume these are optional parameters even though they don't have a clear default like other input parameters would need? If that's the case how can you force them to be non-optional?
As it is for my company procedures the non-optional nature is preferable but I'd like to know why this is as a learning point and how to get around it please.
This SQL demonstrates my question:
CREATE TYPE Dummy_Table AS TABLE (ID INT, Name VARCHAR(50));
GO
CREATE PROCEDURE Dummy_Procedure #Mode VARCHAR(50), #Dummy_Table Dummy_Table READONLY
AS
BEGIN
SELECT #Mode
SELECT * FROM #Dummy_Table
END
GO
EXEC Dummy_Procedure #Mode = 'Dummy_Mode'
TVPs are optional, and they can produce some weird behavior if you are expecting records and don't get any. You could include some logic to check if there are any records in the table.
This article also helps:
https://msdn.microsoft.com/en-us/library/bb510489.aspx
CREATE TYPE Dummy_Table AS TABLE (ID INT, Name VARCHAR(50));
GO
ALTER PROCEDURE Dummy_Procedure #Mode VARCHAR(50), #Dummy_Table Dummy_Table READONLY
AS
BEGIN
SELECT #Mode
declare #test int
SELECT #test = COUNT(*) FROM #Dummy_Table
if #test = 0
select 'stop'
else
select 'continue'
END
GO

TSQLT Returning Results from a Stored Procedure

In TSQLT, I'm trying to return a result from a stored procedure and add it to a variable so that I can assert if it matches my expected result.
I've seen loads of examples of returning results from functions but none where a stored procedure is called.
Does anybody have examples that they could share?
Thanks in advance
If you want to get a variable back from a stored procedure one way to do this is to use an out parameter
CREATE PROC MyTest
(#myVar int output)
AS
BEGIN
SET #myVar = 10
END
GO
DECLARE #x int
EXEC MyTest #myVar=#x output
SELECT #x
If you are getting a result set back from the stored procedure, here is an example from a tSQLt test that I wrote. I haven't bothered with the whole test because this should give you what you need.
CREATE TABLE #Actual (SortOrder int identity(1,1),LastName varchar(100), FirstName varchar(100), OrderDate datetime, TotalQuantity int)
-- Act
INSERT #Actual (LastName, FirstName, OrderDate, TotalQuantity)
EXEC Report_BulkBuyers #CurrentDate=#CurrentDate
The trick here is that you have to create the #actual table first. It should contain the same columns as what is returned from the stored procedure.
Just as an aside, you may have noticed I have a SortOrder column in the #actual table. This is because I was interested in testing the order of the data returned for this specific report. EXEC tSQLt.AssertEqualsTable will match rows like for like, but does not match the order in which the rows appear in the expected and actual so the way to ensure the order is to add a SortOrder column (which is an identity column) to both the #expected and #actual
Have a look here:
http://technet.microsoft.com/en-us/library/ms188655.aspx
Lots of examples about returning values from a stored procedure. At the bottom of the page there is also an example about evaluating a return code.
its actually really simple.
declare #variable int
exec #variable = _Stored_Procedure

sql user defined function

for a table valued function in sql why cant we write sql statements inside begin and end tags like-
create function dbo.emptable()
returns Table
as
BEGIN --it throws an error
return (select id, name, salary from employee)
END
go
while in scalar valued function we can use these tags like
create function dbo.countemp()
returns int
as
begin
return (select count(*) from employee)
end
go
is there any specific rule where we should use BEGIN & END tags
The multi-statement table-valued
function is slightly more complicated
than the other two types of functions
because it uses multiple statements to
build the table that is returned to
the calling statement. Unlike the
inline table-valued function, a table
variable must be explicitly declared
and defined. The following example
shows how to implement a
multi-statement table-valued function
that populates and returns a table
variable.
USE Northwind
go
CREATE FUNCTION fx_OrdersByDateRangeAndCount
( #OrderDateStart smalldatetime,
#OrderDateEnd smalldatetime,
#OrderCount smallint )
RETURNS #OrdersByDateRange TABLE
( CustomerID nchar(5),
CompanyName nvarchar(40),
OrderCount smallint,
Ranking char(1) )
AS
BEGIN
// statements that does some processing ....
END
From the above, I guess BEGIN and END denotes the intent/use of multiple statements & hence it requires the table variable to be defined as shown in the code above.
from http://www.sqlteam.com/article/intro-to-user-defined-functions-updated
In an INLINE TVF (like your first example), the BEGIN and END would try to force it to be procedural code, and therefore it would no longer be an Inline TVF. Scalar functions are only available in a procedural form (which is lousy). Therefore, Scalar functions should generally be avoided in the current versions of SQL Server.

Resources