Trouble using created function in ms sql - 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;

Related

How do I create a function to accept [[customerID]] and return CustName Please look at details

I have been asked to created a Function to accept CustomerID and return CustomerName for the CustomerID, I m a new Student/Developer Please if the question is not clear let me know so i can add more details about it, but that is what I was exactly asked.
functions in SQL are of three types.ignoring rest CLR functions ...
create table test
(
id int,
name varchar(4)
)
insert into test
select 1,'abc'
union all
select 2,'cde'
1.Scalar function takes one value and return one value
now for the above table ,you can create scalar function like below
create function dbo.test
(
#id int
)
returns varchar(4)
as
begin
declare #name varchar(4)
select #name=name from test where id =#id
return #name
End
You invoke it like:
select dbo.test(1)
2.Inline table valued functions:takes a single input same like scalar functions and returns table
create function dbo.test
(
#id int
)
as
returns TABLE
(
select * from test where id=#id)
You invoke it like:
select * from dbo.test(1)
3.Multi table valued function:
create function dbo.test
(
#id int
)
returns
#test table
(
id int,
name varchar(4)
)
as
begin
insert into #test
select * from test where id =#id
return
end
You invoke it like:
select * from dbo.test(1)
Take any one of Itzik Ben Gan books and start learning SQL the way it should be learned

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

SQL server stored procedure return a table

I have a stored procedure that takes in two parameters. I can execute it successfully in Server Management Studio. It shows me the results which are as I expect. However it also returns a Return Value.
It has added this line,
SELECT 'Return Value' = #return_value
I would like the stored procedure to return the table it shows me in the results not the return value as I am calling this stored procedure from MATLAB and all it returns is true or false.
Do I need to specify in my stored procedure what it should return? If so how do I specify a table of 4 columns (varchar(10), float, float, float)?
A procedure can't return a table as such. However you can select from a table in a procedure and direct it into a table (or table variable) like this:
create procedure p_x
as
begin
declare #t table(col1 varchar(10), col2 float, col3 float, col4 float)
insert #t values('a', 1,1,1)
insert #t values('b', 2,2,2)
select * from #t
end
go
declare #t table(col1 varchar(10), col2 float, col3 float, col4 float)
insert #t
exec p_x
select * from #t
I do this frequently using Table Types to ensure more consistency and simplify code. You can't technically return "a table", but you can return a result set and using INSERT INTO .. EXEC ... syntax, you can clearly call a PROC and store the results into a table type. In the following example I'm actually passing a table into a PROC along with another param I need to add logic, then I'm effectively "returning a table" and can then work with that as a table variable.
/****** Check if my table type and/or proc exists and drop them ******/
IF EXISTS (SELECT * FROM sys.objects WHERE type = 'P' AND name = 'returnTableTypeData')
DROP PROCEDURE returnTableTypeData
GO
IF EXISTS (SELECT * FROM sys.types WHERE is_table_type = 1 AND name = 'myTableType')
DROP TYPE myTableType
GO
/****** Create the type that I'll pass into the proc and return from it ******/
CREATE TYPE [dbo].[myTableType] AS TABLE(
[someInt] [int] NULL,
[somenVarChar] [nvarchar](100) NULL
)
GO
CREATE PROC returnTableTypeData
#someInputInt INT,
#myInputTable myTableType READONLY --Must be readonly because
AS
BEGIN
--Return the subset of data consistent with the type
SELECT
*
FROM
#myInputTable
WHERE
someInt < #someInputInt
END
GO
DECLARE #myInputTableOrig myTableType
DECLARE #myUpdatedTable myTableType
INSERT INTO #myInputTableOrig ( someInt,somenVarChar )
VALUES ( 0, N'Value 0' ), ( 1, N'Value 1' ), ( 2, N'Value 2' )
INSERT INTO #myUpdatedTable EXEC returnTableTypeData #someInputInt=1, #myInputTable=#myInputTableOrig
SELECT * FROM #myUpdatedTable
DROP PROCEDURE returnTableTypeData
GO
DROP TYPE myTableType
GO
Consider creating a function which can return a table and be used in a query.
https://msdn.microsoft.com/en-us/library/ms186755.aspx
The main difference between a function and a procedure is that a function makes no changes to any table. It only returns a value.
In this example I'm creating a query to give me the counts of all the columns in a given table which aren't null or empty.
There are probably many ways to clean this up. But it illustrates a function well.
USE Northwind
CREATE FUNCTION usp_listFields(#schema VARCHAR(50), #table VARCHAR(50))
RETURNS #query TABLE (
FieldName VARCHAR(255)
)
BEGIN
INSERT #query
SELECT
'SELECT ''' + #table+'~'+RTRIM(COLUMN_NAME)+'~''+CONVERT(VARCHAR, COUNT(*)) '+
'FROM '+#schema+'.'+#table+' '+
' WHERE isnull("'+RTRIM(COLUMN_NAME)+'",'''')<>'''' UNION'
FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = #table and TABLE_SCHEMA = #schema
RETURN
END
Then executing the function with
SELECT * FROM usp_listFields('Employees')
produces a number of rows like:
SELECT 'Employees~EmployeeID~'+CONVERT(VARCHAR, COUNT(*)) FROM dbo.Employees WHERE isnull("EmployeeID",'')<>'' UNION
SELECT 'Employees~LastName~'+CONVERT(VARCHAR, COUNT(*)) FROM dbo.Employees WHERE isnull("LastName",'')<>'' UNION
SELECT 'Employees~FirstName~'+CONVERT(VARCHAR, COUNT(*)) FROM dbo.Employees WHERE isnull("FirstName",'')<>'' UNION
You can use an out parameter instead of the return value if you want both a result set and a return value
CREATE PROCEDURE proc_name
#param int out
AS
BEGIN
SET #param = value
SELECT ... FROM [Table] WHERE Condition
END
GO
I had a similar situation and solved by using a temp table inside the procedure, with the same fields being returned by the original Stored Procedure:
CREATE PROCEDURE mynewstoredprocedure
AS
BEGIN
INSERT INTO temptable (field1, field2)
EXEC mystoredprocedure #param1, #param2
select field1, field2 from temptable
-- (mystoredprocedure returns field1, field2)
END
The Status Value being returned by a Stored Procedure can only be an INT datatype. You cannot return other datatypes in the RETURN statement.
From Lesson 2: Designing Stored Procedures:
Every stored procedure can return an integer value known as the
execution status value or return code.
If you still want a table returned from the SP, you'll either have to work the record set returned from a SELECT within the SP or tie into an OUTPUT variable that passes an XML datatype.
HTH,
John
Though this question is very old but as a new in Software Development I can't stop my self to share what I have learnt :D
Creation of Stored Procedure:
CREATE PROC usp_ValidateUSer
(
#UserName nVARCHAR(50),
#Password nVARCHAR(50)
)
AS
BEGIN
IF EXISTS(SELECT '#' FROM Users WHERE Username=#UserName AND Password=#Password)
BEGIN
SELECT u.UserId, u.Username, r.UserRole
FROM Users u
INNER JOIN UserRoles r
ON u.UserRoleId=r.UserRoleId
END
END
Execution of Stored Procedure:
(If you want to test the execution of Stored Procedure in SQL)
EXEC usp_ValidateUSer #UserName='admin', #Password='admin'
The Output:
create procedure PSaleCForms
as
begin
declare
#b varchar(9),
#c nvarchar(500),
#q nvarchar(max)
declare #T table(FY nvarchar(9),Qtr int,title nvarchar (max),invoicenumber nvarchar(max),invoicedate datetime,sp decimal 18,2),grandtotal decimal(18,2))
declare #data cursor
set #data= Cursor
forward_only static
for
select x.DBTitle,y.CurrentFinancialYear from [Accounts Manager].dbo.DBManager x inner join [Accounts Manager].dbo.Accounts y on y.DBID=x.DBID where x.cfy=1
open #data
fetch next from #data
into #c,#b
while ##FETCH_STATUS=0
begin
set #q=N'Select '''+#b+''' [fy], case cast(month(i.invoicedate)/3.1 as int) when 0 then 4 else cast(month(i.invoicedate)/3.1 as int) end [Qtr], l.title,i.invoicenumber,i.invoicedate,i.sp,i.grandtotal from ['+#c+'].dbo.invoicemain i inner join ['+#c+'].dbo.ledgermain l on l.ledgerid=i.ledgerid where (sp=0 or stocktype=''x'') and invoicetype=''DS'''
insert into #T exec [master].dbo.sp_executesql #q
fetch next from #data
into #c,#b
end
close #data
deallocate #data
select * from #T
return
end
Here's an example of a SP that both returns a table and a return value. I don't know if you need the return the "Return Value" and I have no idea about MATLAB and what it requires.
CREATE PROCEDURE test
AS
BEGIN
SELECT * FROM sys.databases
RETURN 27
END
--Use this to test
DECLARE #returnval int
EXEC #returnval = test
SELECT #returnval

SQL Table Valued Function in Select Statement

SQL is not my best thing but I have been trying to optimize this stored procedure. It had multiple scalar-valued functions that I tried to change to table-valued functions because I read in many places that it's a more efficient way of doing it. And now I have them made but not real sure how to implement or if I maybe just didn't create them correctly.
This is the function I'm calling.
Alter FUNCTION [IsNotSenateActivityTableValue]
(
#ActivityCode int,
#BillId int,
#TextToDisplay varchar(max)
)
returns #T table(result varchar(max))
as
begin
DECLARE #result varchar(max);
declare #countcodes int;
declare #ishousebill int;
select #ishousebill = count(billid)
from BillMaster
where BillID = #BillID and Chamber = 'H'
If (#ishousebill = 0)
begin
SELECT #countcodes = count([ActivityCode])
FROM [HouseCoreData].[dbo].[ActivityCode]
where ActivityDescription not like '%(H)%' and ActivityType = 'S'
and [ActivityCode] = #ActivityCode
if (#countcodes = 0)
begin
set #result = 'test'
end
else
begin
set #result = 'test2'
end
end
else
begin
set #result = #TextToDisplay
end
RETURN
END
And this is how I was trying to call them like this. I would prefer just being able to put them in the top but really anything that works would be good.
SELECT distinct
ActionDates.result as ActionDate
,ActivityDescriptions.result as ActivityDescription
FROM BillWebReporting.vwBillDetailWithSubjectIndex as vw
left outer join [BillWebReporting].[HasHouseSummary] as HasSummary on vw.BillID = HasSummary.BillID
outer APPLY dbo.IsNotSenateActivityDateTableValue(ActivityCode,vw.BillID,[ActionDate]) ActionDates
OUTER APPLY dbo.IsNotSenateActivityTableValue(ActivityCode,vw.BillID,[ActivityDescription]) as ActivityDescriptions
Getting a count just to see if at least one row exists is very expensive. You should use EXISTS instead, which can potentially short circuit without materializing the entire count.
Here is a more efficient way using an inline table-valued function instead of a multi-statement table-valued function.
ALTER FUNCTION dbo.[IsNotSenateActivityTableValue] -- always use schema prefix!
(
#ActivityCode int,
#BillId int,
#TextToDisplay varchar(max)
)
RETURNS TABLE
AS
RETURN (SELECT result = CASE WHEN EXISTS
(SELECT 1 FROM dbo.BillMaster
WHERE BillID = #BillID AND Chamber = 'H'
) THEN #TextToDisplay ELSE CASE WHEN EXISTS
(SELECT 1 FROM [HouseCoreData].[dbo].[ActivityCode]
where ActivityDescription not like '%(H)%'
and ActivityType = 'S'
and [ActivityCode] = #ActivityCode
) THEN 'test2' ELSE 'test' END
END);
GO
Of course it could also just be a scalar UDF...
ALTER FUNCTION dbo.[IsNotSenateActivityScalar] -- always use schema prefix!
(
#ActivityCode int,
#BillId int,
#TextToDisplay varchar(max)
)
RETURNS VARCHAR(MAX)
AS
BEGIN
DECLARE #result VARCHAR(MAX);
SELECT #result = CASE WHEN EXISTS
(SELECT 1 FROM dbo.BillMaster
WHERE BillID = #BillID AND Chamber = 'H'
) THEN #TextToDisplay ELSE CASE WHEN EXISTS
(SELECT 1 FROM [HouseCoreData].[dbo].[ActivityCode]
where ActivityDescription not like '%(H)%'
and ActivityType = 'S'
and [ActivityCode] = #ActivityCode
) THEN 'test2' ELSE 'test' END
END;
RETURN (#result);
END
GO
Table-valued functions return a table, in which, like any other table, rows have to be inserted.
Instead of doing set #result = ....., do:
INSERT INTO #T (result) VALUES ( ..... )
EDIT: As a side note, I don't really understand the reason for this function to be table-valued. You are essentially returning one value.
First of all UDFs generally are very non-performant. I am not sure about MySQL, but in Sql Server a UDF is recompiled every time (FOR EACH ROW OF OUTPUT) it is executed, except for what are called inline UDFs, which only have a single select statement, which is folded into the SQL of the outer query it is included in... and so is only compiled once.
MySQL does have inline table-valued functions, use it instead... in SQL Server, the syntax would be:
CREATE FUNCTION IsNotSenateActivityTableValue
(
#ActivityCode int,
#BillId int,
#TextToDisplay varchar(max)
)
RETURNS TABLE
AS
RETURN
(
Select case
When y.bilCnt + z.actCnt = 0 Then 'test'
when y.bilCnt = 0 then 'test2'
else #TextToDisplay end result
From (Select Count(billId) bilCnt
From BillMaster
Where BillID = #BillID
And Chamber = 'H') y
Full Join
(Select count([ActivityCode]) actCnt
From [HouseCoreData].[dbo].[ActivityCode]
Where ActivityDescription not like '%(H)%'
And ActivityType = 'S'
And [ActivityCode] = #ActivityCode) z
)
GO

<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)