alfardan
asked on
SQL Function Creation Error
Hello
I'm new to writing functions in SQL
What's wrong with this code (check code section below), why does it give me the following error message:
Msg 137, Level 15, State 2, Procedure TBN, Line 15
Must declare the variable '@TABLE_NAME'.
Msg 170, Level 15, State 31, Procedure TBN, Line 17
Line 17: Incorrect syntax near 'BEGIN'.
I'm new to writing functions in SQL
What's wrong with this code (check code section below), why does it give me the following error message:
Msg 137, Level 15, State 2, Procedure TBN, Line 15
Must declare the variable '@TABLE_NAME'.
Msg 170, Level 15, State 31, Procedure TBN, Line 17
Line 17: Incorrect syntax near 'BEGIN'.
CREATE FUNCTION TBN
(
@RequestTypeID int,
@RequestSerialNo int
)
RETURNS TABLE
AS
BEGIN
DECLARE @TABLE_NAME varchar(50)
set @TABLE_NAME = (select Request_Table_Name from dbo.Request_Type where Request_Type_ID=@RequestTypeID)
RETURN
(
select * from @TABLE_NAME where Request_Serial_No=@RequestSerialNo
)
END
GO
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
you have to define the structure of return table, have a look at my small article at.
http://www.sqlhub.com/2009/03/multi-statement-table-valued-function.html
http://www.sqlhub.com/2009/03/multi-statement-table-valued-function.html
Since the return table needs to be defined (you have to know what the columns will be), and I assume that the different table names that you intend to populate the @TABLE_NAME variable with will presumably have different structures, I don't think you will find your solution in such a function.
Here is an example of working function syntax, with some notes:
create table ABC (
id int not null,
abc char(3) not null)
set nocount on;
insert ABC (id, abc) values (1, 'xyz')
CREATE FUNCTION dbo.TBN (@RequestTypeID int, @RequestSerialNo int)
RETURNS @ABC TABLE (id int, abc char(3))
AS
begin
-- declare and set table variable name (just showing that you can declare the variable here
DECLARE @TABLE_NAME varchar(50); select @TABLE_NAME = Request_Table_Name from dbo.Request_Type where Request_Type_ID=@RequestTy peID
-- insert the return table. cannot use dynamic sql to insert the @ABC return table
insert @ABC (id, abc) select id, abc from ABC where 1=1
-- the return statement goes here
RETURN
end
GO
If the structure of your tables happens to be the same, you should be able to use if statements in the function to select the data you want into your return table.
Like this:
if (@TABLE_NAME = 'ABC')
begin
insert @ABC (id, abc)
select * from ABC where Request_Serial_No=@Request SerialNo
end
HTH
Here is an example of working function syntax, with some notes:
create table ABC (
id int not null,
abc char(3) not null)
set nocount on;
insert ABC (id, abc) values (1, 'xyz')
CREATE FUNCTION dbo.TBN (@RequestTypeID int, @RequestSerialNo int)
RETURNS @ABC TABLE (id int, abc char(3))
AS
begin
-- declare and set table variable name (just showing that you can declare the variable here
DECLARE @TABLE_NAME varchar(50); select @TABLE_NAME = Request_Table_Name from dbo.Request_Type where Request_Type_ID=@RequestTy
-- insert the return table. cannot use dynamic sql to insert the @ABC return table
insert @ABC (id, abc) select id, abc from ABC where 1=1
-- the return statement goes here
RETURN
end
GO
If the structure of your tables happens to be the same, you should be able to use if statements in the function to select the data you want into your return table.
Like this:
if (@TABLE_NAME = 'ABC')
begin
insert @ABC (id, abc)
select * from ABC where Request_Serial_No=@Request
end
HTH
ASKER
As a combination of [expertsoul]'s and [rrjegan17]'s comment, I have used this code, but it still gives me the following error:
Msg 170, Level 15, State 31, Procedure TBN, Line 19
Line 19: Incorrect syntax near 'BEGIN'.
GSQL & RiteshShah:
This is if you know which table you're trying to return data from, but in my case, the table name is dynamically determined at run time.
Msg 170, Level 15, State 31, Procedure TBN, Line 19
Line 19: Incorrect syntax near 'BEGIN'.
GSQL & RiteshShah:
This is if you know which table you're trying to return data from, but in my case, the table name is dynamically determined at run time.
CREATE FUNCTION TBN
(
@RequestTypeID int,
@RequestSerialNo int
)
RETURNS TABLE
AS
BEGIN
DECLARE @TABLE_NAME varchar(50)
set @TABLE_NAME = (select Request_Table_Name from dbo.Request_Type where Request_Type_ID=@RequestTypeID)
DECLARE @SQL VARCHAR(200)
SET @SQL = 'select * from ' + @TABLE_NAME + ' where Request_Serial_No=' + @RequestSerialNo;
EXEC sp_executesql @SQL
END
GO
Syntactical Mistake, Check here for more info:
http://msdn.microsoft.com/en-us/library/ms186755(SQL.90).aspx
http://msdn.microsoft.com/en-us/library/ms186755(SQL.90).aspx
CREATE FUNCTION TBN
(
@RequestTypeID int,
@RequestSerialNo int
)
RETURNS TABLE
AS
RETURN(
DECLARE @TABLE_NAME varchar(50);
DECLARE @SQL VARCHAR(200);
set @TABLE_NAME = (select Request_Table_Name from dbo.Request_Type where Request_Type_ID=@RequestTypeID);
SET @SQL = 'select * from ' + @TABLE_NAME + ' where Request_Serial_No=' + @RequestSerialNo;
EXEC sp_executesql @SQL;
);
GO
ASKER
rrjegan17
Your code gives me the following error:
Msg 156, Level 15, State 1, Procedure TBN, Line 9
Incorrect syntax near the keyword 'DECLARE'.
Msg 170, Level 15, State 1, Procedure TBN, Line 16
Line 16: Incorrect syntax near ')'.
Also, I went to the link you provided, and I saw that this is the format I need (Check code body below)
I don't have (RETURNS @return_variable TABLE < table_type_definition >) in the code I originally posted neither in the code you provided as instructed in the template below
Your code gives me the following error:
Msg 156, Level 15, State 1, Procedure TBN, Line 9
Incorrect syntax near the keyword 'DECLARE'.
Msg 170, Level 15, State 1, Procedure TBN, Line 16
Line 16: Incorrect syntax near ')'.
Also, I went to the link you provided, and I saw that this is the format I need (Check code body below)
I don't have (RETURNS @return_variable TABLE < table_type_definition >) in the code I originally posted neither in the code you provided as instructed in the template below
Multistatement Table-valued Functions
CREATE FUNCTION [ schema_name. ] function_name
( [ { @parameter_name [ AS ] [ type_schema_name. ] parameter_data_type
[ = default ] }
[ ,...n ]
]
)
RETURNS @return_variable TABLE < table_type_definition >
[ WITH <function_option> [ ,...n ] ]
[ AS ]
BEGIN
function_body
RETURN
END
[ ; ]
observe
"RETURNS @return_variable TABLE < table_type_definition >"in above template. I have already told you that you will need tabledefination, don't you have fixed table structure to return? dynamictable name will work but you have to have table defination if you wantsto return table.
"RETURNS @return_variable TABLE < table_type_definition >"in above template. I have already told you that you will need tabledefination, don't you have fixed table structure to return? dynamictable name will work but you have to have table defination if you wantsto return table.
RiteshShah,
You are correct. Function wont be able to return the result executed by sp_executesql. We have to insert the records into the temp table and then select the output from that table.
Try this one out:
You are correct. Function wont be able to return the result executed by sp_executesql. We have to insert the records into the temp table and then select the output from that table.
Try this one out:
CREATE FUNCTION TBN
(
@RequestTypeID int,
@RequestSerialNo int
)
RETURNS TABLE
AS
RETURN(
DECLARE @TABLE_NAME varchar(50),
@SQL NVARCHAR(200);
set @TABLE_NAME = (select Request_Table_Name from dbo.Request_Type where Request_Type_ID=@RequestTypeID);
-- create table #temp (all your columns)
SET @SQL = 'insert into #temp select * from ' + @TABLE_NAME + ' where Request_Serial_No=' + @RequestSerialNo;
EXEC sp_executesql @SQL;
select * from #temp;
);
GO
rrjegan17, Yes, needs to have table definition but I would like to go with predefined table definition before AS rather than TEMP table, just want to stick with syntax, no major reason.
ASKER
RiteshShah
Ok, I just made another modification to the code according to what you instrusted, and the function has been successfully created (check code below)
Now, when I try to call the function, I apply this command:
select Request_Serial_No from TBN(2,20)
When I do so, it gives me the following error:
Msg 245, Level 16, State 1, Procedure TBN, Line 18
Syntax error converting the varchar value 'select Request_Serial_No from Request2_Log where Request_Serial_No=' to a column of data type int.
Ok, I just made another modification to the code according to what you instrusted, and the function has been successfully created (check code below)
Now, when I try to call the function, I apply this command:
select Request_Serial_No from TBN(2,20)
When I do so, it gives me the following error:
Msg 245, Level 16, State 1, Procedure TBN, Line 18
Syntax error converting the varchar value 'select Request_Serial_No from Request2_Log where Request_Serial_No=' to a column of data type int.
SET QUOTED_IDENTIFIER OFF
GO
SET ANSI_NULLS OFF
GO
CREATE FUNCTION TBN
(
@RequestTypeID int,
@RequestSerialNo int
)
RETURNS
@Table_Variable_Name TABLE
(
Request_Serial_No int
)
AS
BEGIN
DECLARE @TABLE_NAME varchar(50);
DECLARE @SQL VARCHAR(200);
set @TABLE_NAME = (select Request_Table_Name from dbo.Request_Type where Request_Type_ID=@RequestTypeID);
SET @SQL = 'select Request_Serial_No from ' + @TABLE_NAME + ' where Request_Serial_No=' + @RequestSerialNo;
EXEC sp_executesql @SQL;
RETURN
END
GO
SET QUOTED_IDENTIFIER OFF
GO
SET ANSI_NULLS ON
GO
use:
convert(varchar,@RequestSe rialNo)
convert(varchar,@RequestSe
you are passing integer value in @RequestSerialNo and use it with "+" operator with varchar so compiler gets confused so while giving it there, convert it to varchar and you will be ok.
ASKER
RiteshShah
I have changed:
SET @SQL = 'select Request_Serial_No from ' + @TABLE_NAME + ' where Request_Serial_No=' + @RequestSerialNo;
to:
SET @SQL = 'select Request_Serial_No from ' + @TABLE_NAME + ' where Request_Serial_No=' + convert(varchar,@RequestSe rialNo);
Then I got the following error:
Msg 557, Level 16, State 2, Procedure TBN, Line 19
Only functions and extended stored procedures can be executed from within a function.
I have changed:
SET @SQL = 'select Request_Serial_No from ' + @TABLE_NAME + ' where Request_Serial_No=' + @RequestSerialNo;
to:
SET @SQL = 'select Request_Serial_No from ' + @TABLE_NAME + ' where Request_Serial_No=' + convert(varchar,@RequestSe
Then I got the following error:
Msg 557, Level 16, State 2, Procedure TBN, Line 19
Only functions and extended stored procedures can be executed from within a function.
Sorry, I don't have SSMs access right now so can't check sysntax but can you tell me whether you got above error at runtime or at compile time? moreover, you can declare @RequestSerialNo as varchar in your definition, that will also solve your problem
ASKER
I just changed:
CREATE FUNCTION TBN
(
@RequestTypeID int,
@RequestSerialNo int
)
to:
CREATE FUNCTION TBN
(
@RequestTypeID int,
@RequestSerialNo varchar(10)
)
and I ran this command:
select Request_Serial_No from TBN(2,'20')
I still got the same error message in my last post
Just not to go any further in any possible wrong direction, my DB is MS SQL 2005
CREATE FUNCTION TBN
(
@RequestTypeID int,
@RequestSerialNo int
)
to:
CREATE FUNCTION TBN
(
@RequestTypeID int,
@RequestSerialNo varchar(10)
)
and I ran this command:
select Request_Serial_No from TBN(2,'20')
I still got the same error message in my last post
Just not to go any further in any possible wrong direction, my DB is MS SQL 2005
I'm sorry, but no matter how hard you try you won't get dynamic SQL to work in a function in SQL 2005 - and I don't see it working in SQL 2008 either.
You'll get it to compile, but it won't run the dynamic SQL.
I suggest you consider the alternatives.
If you will always be returning the same table structure, the if condition method I posted earlier could work.
Among the possible solutions, you could use a view so that your query would look like
select ColumnList
from ViewName
where Request_Serial_No = @Request_Serial_No
You could also use a stored procedure.
But you can't use dynamic SQL in a function.
You'll get it to compile, but it won't run the dynamic SQL.
I suggest you consider the alternatives.
If you will always be returning the same table structure, the if condition method I posted earlier could work.
Among the possible solutions, you could use a view so that your query would look like
select ColumnList
from ViewName
where Request_Serial_No = @Request_Serial_No
You could also use a stored procedure.
But you can't use dynamic SQL in a function.
Here's the sample of the function solution, including some sample tables:
create table ThisTable (Request_Serial_No int not null, T1_Stuff nvarchar(50))
create table ThatTable (Request_Serial_No int not null, T2_Stuff nvarchar(50))
insert ThisTable (Request_Serial_No, T1_Stuff) values (5, 'This g')
insert ThisTable (Request_Serial_No, T1_Stuff) values (10, 'This a')
insert ThisTable (Request_Serial_No, T1_Stuff) values (20, 'This b')
insert ThatTable (Request_Serial_No, T2_Stuff) values (10, 'That a')
insert ThatTable (Request_Serial_No, T2_Stuff) values (20, 'That b')
insert ThatTable (Request_Serial_No, T2_Stuff) values (30, 'That c')
insert ThatTable (Request_Serial_No, T2_Stuff) values (40, 'That d')
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[TBN]') AND type in (N'FN', N'IF', N'TF', N'FS', N'FT'))
DROP FUNCTION [dbo].[TBN]
GO
CREATE FUNCTION dbo.TBN
(
@RequestTypeID int,
@RequestSerialNo nvarchar(10)
)
RETURNS
@Table_Variable_Name TABLE
(
Request_Serial_No int
)
AS
BEGIN
DECLARE @TABLE_NAME varchar(50), @SQL VARCHAR(200);
select @TABLE_NAME = Request_Table_Name from dbo.Request_Type where Request_Type_ID=@RequestTy peID;
if @TABLE_NAME = 'ThisTable'
begin
insert @Table_Variable_Name
select Request_Serial_No from ThisTable where Request_Serial_No = @RequestSerialNo
end
if @TABLE_NAME = 'ThatTable'
begin
insert @Table_Variable_Name
select Request_Serial_No from ThatTable where Request_Serial_No = @RequestSerialNo
end
RETURN
END
GO
create table ThisTable (Request_Serial_No int not null, T1_Stuff nvarchar(50))
create table ThatTable (Request_Serial_No int not null, T2_Stuff nvarchar(50))
insert ThisTable (Request_Serial_No, T1_Stuff) values (5, 'This g')
insert ThisTable (Request_Serial_No, T1_Stuff) values (10, 'This a')
insert ThisTable (Request_Serial_No, T1_Stuff) values (20, 'This b')
insert ThatTable (Request_Serial_No, T2_Stuff) values (10, 'That a')
insert ThatTable (Request_Serial_No, T2_Stuff) values (20, 'That b')
insert ThatTable (Request_Serial_No, T2_Stuff) values (30, 'That c')
insert ThatTable (Request_Serial_No, T2_Stuff) values (40, 'That d')
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[TBN]') AND type in (N'FN', N'IF', N'TF', N'FS', N'FT'))
DROP FUNCTION [dbo].[TBN]
GO
CREATE FUNCTION dbo.TBN
(
@RequestTypeID int,
@RequestSerialNo nvarchar(10)
)
RETURNS
@Table_Variable_Name TABLE
(
Request_Serial_No int
)
AS
BEGIN
DECLARE @TABLE_NAME varchar(50), @SQL VARCHAR(200);
select @TABLE_NAME = Request_Table_Name from dbo.Request_Type where Request_Type_ID=@RequestTy
if @TABLE_NAME = 'ThisTable'
begin
insert @Table_Variable_Name
select Request_Serial_No from ThisTable where Request_Serial_No = @RequestSerialNo
end
if @TABLE_NAME = 'ThatTable'
begin
insert @Table_Variable_Name
select Request_Serial_No from ThatTable where Request_Serial_No = @RequestSerialNo
end
RETURN
END
GO
@Table_Name is just a varchar holding name of the table, it isnt the actual table you can query. If you want to use @Table_Name to query actual table you need to use Dynamic SQL. Something like below:
Open in new window