Create recursive scalar function in SQL - sql

I need a recursive scalar function in SQL Server 2014.
My code is this:
CREATE FUNCTION Accounting_ToppestLevelID
(
#ID numeric(6,0)
)
RETURNS numeric(6,0)
AS
BEGIN
declare #temp numeric(6,0)
select #temp = a.ParentID from Accounting_AcntAccount a where a.ID = #ID
if #temp is null
begin
return #ID
end
return Accounting_ToppestLevelID(#temp)
END
But after executing the code below error will appearance:
Msg 195, Level 15, State 10, Procedure Accounting_ToppestLevelID, Line 34
'Accounting_ToppestLevelID' is not a recognized built-in function name.
It is a logical error but how I can fix it?

Try adding the schema prefix, ie.
return dbo.Accounting_ToppestLevelID(#temp)

You should simply specify function's full name: it is implicitly created in dbo
schema if no schema is specified, so your script should be:
CREATE FUNCTION Accounting_ToppestLevelID
(
#ID numeric(6,0)
)
RETURNS numeric(6,0)
AS
BEGIN
declare #temp numeric(6,0)
select #temp = a.ParentID from Accounting_AcntAccount a where a.ID = #ID
if #temp is null
begin
return #ID
end
return dbo.Accounting_ToppestLevelID(#temp)
END

Try adding a schema explicitly. If you don't use a custom one, default is dbo:
return [dbo].[Accounting_ToppestLevelID](#temp);

Related

Trouble using created function in ms sql

I've made a SQL function. This is a simple function which gets IDs of given Gateway and Category objects by name:
USE [dev_ticketsystem]
GO
CREATE FUNCTION dbo.GetGatewayCategoryPair(#GatewayName varchar(100), #CategoryName varchar(100))
RETURNS #PairedTable TABLE
(
GatewayId uniqueidentifier,
CategoryId uniqueidentifier
)
AS
BEGIN
DECLARE #CategoryId uniqueidentifier;
DECLARE #GatewayId uniqueidentifier;
SELECT #CategoryId = [Id]
FROM [dev_ticketsystem].[dbo].[Category]
WHERE [Name] = #CategoryName;
SELECT #GatewayId = [Id]
FROM [dev_ticketsystem].[dbo].[Gateway]
WHERE [Name] = #GatewayName;
IF #GatewayId IS NOT NULL
BEGIN
IF #CategoryId IS NOT NULL
BEGIN
INSERT #PairedTable
SELECT #GatewayId, #CategoryId;
END;
END;
RETURN;
END;
GO
After executing this script it created the function, so I can see in MS SQL Management Studio.
But when I'm trying to call it with :
USE [dev_ticketsystem]
GO
INSERT INTO [dbo].[CategoryGateway]
([GatewayId]
,[CategoryId])
VALUES
(dbo.GetGatewayCategoryPair('GateName', 'CatName').GatewayId,
dbo.GetGatewayCategoryPair('GateName', 'CatName').CategoryId);
It throws exception :
Incorrect syntax near 'GetGatewayCategoryPair'.
How could this be fixed?
You have declared the function to return a table. Hence, you need to refer to it in the FROM clause:
INSERT INTO dbo.CategoryGateway(GatewayId, CategoryId)
SELECT gcp.GatewayId, gcp.CategoryId
FROM dbo.GetGatewayCategoryPair('GateName', 'CatName') gcp;
Personally, I would move away from a Multi-statement table value function; they can be very slow. Use a inline table-value function. Which should look something like this:
CREATE FUNCTION dbo.GetGatewayCategoryPair_itvf (#GatewayName varchar(100), #CategoryName varchar(100))
RETURNS TABLE
AS RETURN
SELECT G.ID AS GatewayId,
C.ID AS CategoryId
FROM (SELECT [Id]
FROM [dev_ticketsystem].[dbo].[Category]
WHERE [Name] = #CategoryName) C
CROSS APPLY (SELECT [Id]
FROM [dev_ticketsystem].[dbo].[Gateway]
WHERE [Name] = #GatewayName) G
WHERE C.ID IS NOT NULL
AND G.ID IS NOT NULL;

SQL Error: "Must declare the scalar variable" when passing a table parameter to a table-valued function

The following simple SQL example is returning an error.
Here's a table type that's passed to a table-valued function:
CREATE TYPE Ids
AS TABLE
(
Id int NOT NULL,
PRIMARY KEY( Id )
);
GO
And here is the table-valued function that fails:
CREATE FUNCTION GetIds
(
#ids -- or null
Ids READONLY
)
RETURNS
#result
TABLE
(
EachId int
)
AS
BEGIN
IF #ids IS NOT NULL
INSERT INTO #result
SELECT Id
FROM #ids;
RETURN;
END;
GO
The error returned is:
Msg 137, Level 16, State 1, Procedure GetIds, Line 28
Must declare the scalar variable "#ids".
I've read posts that say that it happens when the SQL compatibility level is too old, but the following returns 100:
SELECT compatibility_level
FROM sys.databases
WHERE name = 'TheDatabaseName';
Any suggestions would be greatly appreciated.
Let me tell you table type parameter is just like a data table.
So, if you want to put if condition on it then,
just change your if condition of function as below:
IF (select count(*) from #ids) > 0
Complete function code is:
CREATE FUNCTION GetIds
(
#ids Ids READONLY
)
RETURNS #result TABLE(EachId int)
AS
BEGIN
IF (select count(*) from #ids) > 0
INSERT INTO #result
SELECT Id FROM #ids;
RETURN;
END;
just check if you have any record in you table
if(select count(1) from #ids)>0

Microsoft t sql how to declare temporary variable within user defined function?

So how can I declare a temporary local variable with declare like:declare #tempVar varchar(max) within a user declared function?
The actual problem I'm trying to solve here is declaring and using variable within user defined stored function. I declare my function like this:
create function someFunction(#someParam varchar(100))
returns table
as
return (
declare #tempvar varchar(100)
set #tempvar = ''--Set the var to something useful
select * from sometable where somecolumn = (
select top 1 someColumn
from sometable
where somecolumn = #tempvar
)
)
Server complain about the variable being declared in wrong place. Where should I declare my variables in UDF like this?
You are creating an Inline Table-valued Function, this kind of functions must contain only a single SELECT statement.
If you want to use variables you must create a Multi-statement Table-valued Function. Your function would be declared as:
create function someFunction(#someParam varchar(100))
returns #table (field1 type, field2 type, ...)
as
begin
declare #tempvar varchar(100)
set #tempvar = ''--Set the var to something useful
insert #table
select * from sometable where somecolumn = (
select top 1 someColumn
from sometable
where somecolumn = #tempvar
)
return
end
If you wanted to keep the table function inline you could use a common table expression to define your variable(s) as shown below:
create function someFunction(#someParam varchar(100))
returns table
as
return (
WITH cte (tempvar) AS
(
SELECT '' -- Set the var to something useful
)
select * from sometable where somecolumn = (
select top 1 someColumn
from sometable
JOIN cte ON 1=1
where somecolumn = cte.tempvar
)
)

getting error while RETURN two statement - sql function

ALTER FUNCTION [dbo].[UDF_GetExpenseDetails](#EmpID nvarchar(50))
RETURNS NVARCHAR(MAX)
AS
BEGIN
DECLARE #ExpAmount nvarchar(MAX)
DECLARE #ExpName nvarchar(MAX)
IF (#EmpID <> '')
BEGIN
SELECT distinct
#ExpAmount = SE.ExpenseAmount, #ExpName = ME.ExpenseName
FROM
tbl_admin_supplierempexpense SE, tbl_master_expense ME
WHERE
SE.EmpID = #EmpID
AND SE.ExpenseName = ME.ExpenseID
AND SE.Status = 'P'
END
RETURN #ExpAmount,#ExpName
END
ERROR : Incorrect syntax near ','.
You can not return more than 1 values from a FUNCTION. If you want multiple values, create a table-valued function.
See it here http://technet.microsoft.com/en-us/library/ms191165.aspx , example included
What if you try this?
CREATE FUNCTION [owner].[UDF_GetExpenseDetails](#EmpID nvarchar(50))
RETURNS TABLE
AS
RETURN
(
SELECT <column1, column2>
FROM <table>
WHERE <condition>
);
Try this
ALTER FUNCTION [dbo].[UDF_GetExpenseDetails](#EmpID nvarchar(50))
RETURNS #table( #ExpAmount money,#ExpName varchar(100))
As
begin
IF (#EmpID <> '')
BEGIN
insert into #ExpAmount
SELECT distinct SE.ExpenseAmount,ME.ExpenseName
from tbl_admin_supplierempexpense SE, tbl_master_expense ME
where SE.EmpID = #EmpID and SE.ExpenseName=ME.ExpenseID and SE.Status='P'
END
return
END

<table-valued function> is not a recognized built-in function name

I am getting this error:
Msg 195, Level 15, State 10, Line 1
'fnParseName' is not a recognized built-in function name.
On this query:
SELECT fnParseName(DOCTORFIRSTNAME+' ' +DOCTORLASTNAME)
FROM [PracticeandPhysician]
Here's the code for fnParseName
create FUNCTION [dbo].[fnParseName]
(#FullName NVARCHAR(128))
RETURNS #FullNameParts TABLE (FirstName NVARCHAR(128),
Middle NVARCHAR(128),
LastName NVARCHAR(128))
AS
BEGIN
... function body that populates #FullNameParts ...
RETURN
END
Why am I getting this error?
It's a table-valued function. So you probably meant:
SELECT p.DOCTORFISTNAME, p.DOCTORLASTNAME, t.FirstName, t.Middle, t.LastName
FROM dbo.[PracticeandPhysician] AS p
CROSS APPLY dbo.fnParseName(p.DOCTORFIRSTNAME + ' ' + p.DOCTORLASTNAME);
Note that you can't say:
SELECT dbo.TableValueFunction('foo');
Any more than you could say:
SELECT dbo.Table;
--or
SELECT dbo.View;
You can, however, say:
SELECT * FROM dbo.fnParseName('foo bar');
--or
SELECT FirstName, Middle, LastName FROM dbo.fnParseName('foo bar');
(Not that I have validated that your function does what you think, or does so efficiently.)
Please always use the dbo. prefix as others have suggested.
You always have to prefix SQL function calls with the schema name dbo. or the schema name for that function (dbo is the default schema).
SELECT dbo.fnParseName(--etc
UDFs/Functions need to be prefixed with the schema name (most likely "dbo"). Change the call to
SELECT
dbo.fnParseName(DOCTORFIRSTNAME + ' ' + DOCTORLASTNAME)
FROM
[PracticeandPhysician]
The problem you have is similar to what I encountered too. Scalar function and Table inline functions are quite different in terms of implementation. See below for the diiferent
Create function udfCountry
(
#CountryName varchar(50)
)
returns varchar(2)
as
BEGIN
Declare #CountryID varchar(2),
#Result varchar(2)
Select #CountryID = Country from
dbo.GeoIPCountryNames where CountryName = #CountryName
set #Result = isNull(#CountryID, 'NA')
if #Result = 'NA'
set #Result = 'SD'
return #Result
End
//Implementation
select dbo.[udfCountry]('Nigeria')
// sample result
NG
// Inline table function sample
Create FUNCTION ConditionEvaluation
(
#CountrySearch varchar(50)
)
returns #CountryTable table
(
Country varchar(2),
CountryName varchar(50)
)
as
Begin
Insert into #CountryTable(Country, CountryName)
Select Country, CountryName from GeoIPCountryNames
where Country like '%'+#CountrySearch+'%'
return
end
//Implementation sample
Declare #CountrySearch varchar(50)
set #CountrySearch='a'
select * from ConditionEvaluation(#CountrySearch)
the parttern of implementating scalar is quite different inline table. I hope this helps
If you want to assign the value returned by tfn in a variable of stored procedure, you can do it this way:
select #my_local_variable_in_procedure = column_name_returned_from_tfn from dbo.my_inline_tfn (#tfn_parameter)