I want to modify my inline function so that it can handle two variables as input. With just one it worked just fine.
FUNCTION [dbo].[TBL_UDF_HowOften]
(
-- Add the parameters for the function here
#membername as varchar(15),
#tablename as varchar(15)
)
RETURNS #ergebnis TABLE
(
participated float,
percent float,
WonWen1 float,
WonWen2 float,
WonWen3 float
)
AS
BEGIN
DECLARE #wintimes float
DECLARE a lot of other stuff...
SELECT #wintimes = COUNT(DidWin)
FROM #tablename
WHERE DidWin = 1 AND membername = #membername
... and so on
Well, #membername is recognized but #tablename is marked with "Must declare the table variable "#tablename"."
You can't use a scalar variable as the table name in a 'from' clause. You would need to use dynamic sql, which I do not think can be done inside a function.
Related
I have the following SQL function:
create function [dbo].[LookUpAnonymiseString](#string varchar(500), #tableSize int)
returns varchar(500)
as
begin
DECLARE #output varchar(500)
SELECT #output = Value FROM AnonymisationLookup.dbo.Forename WHERE AnonymisationLookup.dbo.Forename.ID = ABS(CHECKSUM(#string)) % #tableSize
return #output
end
go
I believe this function works fine, it takes an input string and int representing the size of a look up table (containing all available strings). I then hash the input string into an index to look up the table, returning the value at that index for an output string.
I want to generalise the function so the name of the table can be passed in and used in the query, rather than the hardcoded "Forename" table.
I've tried the following, but SQL complains and says "Only functions and some extended stored procedures can be executed from within a function."
create function [dbo].[LookUpAnonymiseString](#string varchar(500), #tableName varchar(128), #tableSize int)
returns varchar(500)
as
begin
declare #output varchar(500)
declare #sql nvarchar(max)
set #sql = N'select #output = Value from AnonymisationLookup.dbo.'+quotename(#tableName)+' where AnonymisationLookup.dbo.'+quotename(#tableName)+'.ID = abs(checksum(#string)) % #tableSize'
exec sp_executesql #sql, N'#output nvarchar(max) out', #output out
return #output
end
go
Your first query "sort of" works. It only works if there are no gaps in the ids -- and it is pretty easy for ids to have gaps (even identity columns). So a safer method is:
DECLARE #output varchar(500);
SELECT TOP 1 #output = Value
FROM AnonymisationLookup.dbo.Forename f
WHERE F.ID >= ABS(CHECKSUM(#string)) % #tableSize
ORDER BY F.ID;
return #output;
Then, your goal to pass in the table cannot be done in a function (except in a really complicated, abstruse way). Hence, you really cannot do what you want to do. You can use dynamic SQL in a stored procedure, but that cannot be used directly in a function.
I have defined a table-valued function X with 11 parameters. Their types are nvarchar(30), nvarchar(30), datetime, datetime, nvarchar(15), nvarchar(4), xml, nvarchar(8), nvarchar(80), bit, and bit respectively. This is for Microsoft SQL Server 2012. When I call the function with
select * from
X('A','B','2014-01-01','2014-12-31',null,null,'<C><D>E</D></C>',null,null,1,0)
I run into this error:
Parameters were not supplied for the function X
It is apparently different from the following two:
An insufficient number of arguments were supplied for the procedure or function X
Procedure or function X has too many arguments specified.
Is this related to two of the intended parameter values being null? How can I overcome the problem and define/call a table-valued function such as this one with 11 parameters, some of which may carry null?
UPDATE The problem remains if I pass in arbitrary strings instead of null. So there must be another (perhaps stupid) mistake.
The correct way to define a function like the one you describe is the following:
CREATE FUNCTION X
(
-- Add the parameters for the function here
#a nvarchar(30),
#b nvarchar(30),
#c datetime,
#d datetime,
#e nvarchar(15),
#f nvarchar(4),
#g xml,
#h nvarchar(8),
#i nvarchar(80),
#j bit,
#k bit
)
RETURNS
#output TABLE
(
-- Add the column definitions for the TABLE variable here
data nvarchar(250)
)
AS
BEGIN
INSERT INTO #output (data)
VALUES (#a + #b)
RETURN
END
GO
Given the above definition, this:
select * from
X('A','B','2014-01-01','2014-12-31',null,null,'<C><D>E</D></C>',null,null,1,0)
yields the following result:
data
----
AB
If your function does not need any parameters, but you are still getting this error:
Parameters were not supplied for the function
select * from [dbo].[myfunction]
Try adding () after the function call:
select * from [dbo].[myfunction]()
I create a function to execute dynamic SQL and return a value. I am getting "Only functions and some extended stored procedures can be executed from within a function." as an error.
The function:
Create Function fn_GetPrePopValue(#paramterValue nvarchar(100))
returns int as
begin
declare #value nvarchar(500);
Set #SQLString = 'Select Grant_Nr From Grant_Master where grant_id=' + #paramterValue
exec sp_executesql
#query = #SQLString,
#value = #value output
return #value
end
The execution:
Select dbo.fn_GetPrePopValue('10002618') from Questions Where QuestionID=114
and:
Select fn_GetPrePopValue('10002618') from Questions Where QuestionID=114
Is the function being called properly or is the function incorrect?
You cannot use dynamic SQL from a function, neither can you call
stored procedures.
Create proc GetPrePopValue(#paramterValue nvarchar(100))
as
begin
declare #value nvarchar(500),
#SQLString nvarchar(4000)
Set #SQLString = 'Select #value = Grant_Nr From Grant_Master where grant_id = #paramterValue'
exec sp_executesql #SQLString, N'#paramterValue nvarchar(100)',
#paramterValue,
#value = #value output
return #value
end
Functions are limited in what they can use, so that you can use them in a query without accidentally make something that would give horrible performance. Using dynamic queries is one of those things, as that would cause a query planning for each execution, and also would keep the function from being able to be part of a query plan.
You don't need the dynamic query at all in this case, just return the value:
Create Function fn_GetPrePopValue(#paramterValue nvarchar(100))
returns int as
begin
return (select Grant_Nr From Grant_Master where grant_id = #paramterValue)
end
I don't think you can use dynamic SQL from a function, nor do I think you need to in your case. Looks like you want something closer to this:
Create Function dbo.fn_GetPrePopValue(#paramterValue nvarchar(100))
returns int as
begin
declare #value int
declare #SQLString varchar(MAX)
Select #value=Grant_Nr From Grant_Master where grant_id=#paramterValue
return #value
end
SQL Fiddle Demo
Also, please check your data types to make sure you're fields are correct. Seems odd to pass in a varchar for the id and return an int for the other field. Either way, this should help you get going in the right direction.
Environment sql server 2005 sp3
I have a stored proc that takes an INT as input. I want to CAST a CHAR to an INT during the call to the stored proc. it seems I cannot do that. I get a syntax error before #foo. I do not see it can someone help me find it please.
CREATE PROCEDURE testme
#test AS INT
AS
BEGIN
SELECT #TEST
END
DECLARE #foo AS CHAR(6)
set #foo = '11test'
EXEC testMe #test = CAST(Substring(#foo,1,2) as int)
first off all, you can't cast '11test' as an int
second, if the value can be converted to an int, you don't need to cast, an implicit cast will happen
DECLARE #foo AS CHAR(6)
set #foo = '2'
EXEC testMe #test =#foo
If you want to test if it can be converted to an int, grab the IsInt function from here: IsNumeric, IsInt, IsNumber and use that to test before making the proc call
EDIT
here is how you can do it
DECLARE #foo AS CHAR(6)
set #foo = '11test'
SET #foo = CAST(Substring(#foo,1,2) as int)
EXEC testMe #test = #foo
you can't pass functions to procs, this is why GETDATE() doesn't work either, either use an intermediate variable or cast back to the same variable
You cannot convert a char field to int when it contains non-numeric characters.
I would suggest creating a function that loops through the chars and removes any that are non-numeric.
I have a sql function and i need to declare few variables in that function. Please advise how can i achieve this.
For example i need to put -->
Declare #ClientResult TABLE(
RowIndex int identity(1,1),
SplitText varchar(50)
)
in the below function.
create FUNCTION [dbo].CLIENT_SHIPPINGREPORTDATA_Function_Test
(
#CLIENTPK_NEW TABLE,
#CGNEEPK TABLE
#type varchar(100)
)
RETURNS TABLE
AS
RETURN
SELECT distinct
OP_PartNum,
OP_PK
FROM Client_whsPallet pallet
I am using sql server 2005
Thanks
What you are after is a multi-statement table function
e.g.
CREATE FUNCTION dbo.fxnExample (#Param INTEGER)
RETURNS #Results TABLE(FieldA VARCHAR(50))
AS
BEGIN
INSERT #Results
SELECT SomeField
FROM Somewhere
WHERE ParamField = #Param
RETURN
END
This is different to your current function which is called an "inline table valued function" and you should be aware of the differences as this could cause performance issues if you switch to the multi-statement approach. My advice would be to try and use inline table valued functions wherever possible. I recommend you checking out these articles which go into detail:
Multi-statement Table Valued Function vs Inline Table Valued Function
Link
http://sqlbits.com/Agenda/event6/High_performance_functions/default.aspx
In SQL Server you can't declare variables inside of an inline table-Valued function. You'll need to create a multi-statement table valued function if you really need to declare variables in it. You would do something like this:
CREATE FUNCTION [dbo].CLIENT_SHIPPINGREPORTDATA_Function_Test
(
#CLIENTPK_NEW TABLE, #CGNEEPK TABLE #type varchar(100)
)
RETURNS #output TABLE (OP_PartNum int, OP_PK int)
AS BEGIN
Declare #ClientResult TABLE( RowIndex int identity(1,1), SplitText varchar(50) )
/* more code here */
RETURN
END
Not knowing what exactly it is you are trying to do, I would see if there is away around using a multi-statement function though as you will see performance decrease.
Compare these equivalent code samples. They show the syntax differences between inline and multistatement table-valued functions.
CREATE FUNCTION [dbo].Inline (#type varchar(100))
RETURNS TABLE
AS
RETURN
SELECT distinct name
FROM sysobjects
WHERE type = #type
GO
CREATE FUNCTION [dbo].Multistatement (#type varchar(100))
RETURNS #results TABLE (name sysname)
AS
BEGIN
INSERT #results (name)
SELECT distinct name
FROM sysobjects
WHERE type = #type
RETURN
END
As suggested by AdaTheDev you can create a multi-statement function for returning a table from a function.
Otherwise if you need to create a table inside the function you can create a new temporary table prefixing its name with an #
create table #TableNAme (FieldA Varchar(5))