Use aggregate functions in create function - sql-server

I use below code to create function but when i want to execute it occur error
CREATE FUNCTION getFactorPriceFunction
(
#factorCode BIGINT
)
RETURNS bigint
AS BEGIN
RETURN
(
select SUM(price*coun) as total from CustomerFactor inner join CustomerFactorDetails
on CustomerFactor.code=CustomerFactorDetails.factorCode inner join ProductDetails on
ProductDetails.code=CustomerFactorDetails.productDetailsCode
where factorCode=#factorCode AND final=1
)
END
execute:
select total from getFactorPriceFunction(100)
error:
Invalid object name 'getFactorPriceFunction'

It's called dbo.getFactorPriceFunction.
The invocation is goes like this:
select dbo.getFactorPriceFunction(100) as total

Since it is a scalar value function ,it should be executed like
select dbo.getFactorPriceFunction(100)
If you are returning a table then it should be
select total from dbo.getFactorPriceFunction(100)

Related

Unable to find User-defined Function

I have a UDF defined as follows:
Create Or Replace Function Minder_Mvp.Sprint4.Get_Customer_Key(Store_Key VARCHAR)
Returns Table (Customer_Key BIGINT)
AS
'Select Customer_Key From CustomerBrand
Where CustomerBrand.Brand_Key = 1'
;
And then I attempt to call it like this:
Select Minder_Mvp.Sprint4.Get_Customer_Key('457');
When I do so, I get the following error:
Unknown user-define function Minder_MVP.SPRINT4.GET_CUSTOMER_KEY
Must be something obvious but I am not seeing it.
It is an user defined table function:
A UDTF can be accessed in the FROM clause of a query.
Select Minder_Mvp.Sprint4.Get_Customer_Key('457');
=>
SELECT *
FROM TABLE(Minder_Mvp.Sprint4.Get_Customer_Key('457')) s;

How to create a function in sql server for finding if data exists or not?

Need to know the syntax for creating function and the difference between inline table value function and multi statement tabled value function.
SCALAR FUNCTION
returns only a scalar/single value. We can use Scalar function in SELECT statement, WHERE, GROUP BY, HAVING clause. We have to mention data type of that single data value in RETURNS clause of the function definition.
E.g. Below function taking a date as input in 'dd/mm/yyyy' format and returning day and month from it. This is not mandatory that function always take an input parameter but it must always return a value.
create function GetDateDaynMonth(#date varchar(20))
returns varchar(20)
as
begin
declare #DaynMonth varchar (20)
SELECT #DaynMonth = FORMAT (convert(datetime, #date, 103), 'dd MMMM')
return #DaynMonth;
end
go
** - To execute Function **
select dbo.GetDateDaynMonth('25/06/2018')
TABLE VALUED FUNCTION
A table-valued user defined function returns a result set/row set instead of a single/scalar value. It can be invoked in FROM or JOIN clause of a SELECT query.
For more details with multiple examples
https://learn.microsoft.com/en-us/sql/t-sql/statements/create-function-transact-sql?view=sql-server-2017
INLINE TABLE VALUED FUNCTION
An inline table valued function definition specifies only RETURNS TABLE and not the table definition. The entire query batch or code or select query inside the function is a single RETURN statement
CREATE FUNCTION CustomerProductDetails (#CustomerID NCHAR(5))
RETURNS TABLE
AS
RETURN (
-- Select statement
)
GO
MULTI STATEMENT TABLE VALUED FUNCTION
Multi-statement table valued function definition specifies RETURNS along with the definition of TABLE VARIABLE. The function body might consists of multiple statements and one of which will populate this TABLE VARIABLE. And the scope/life of this TABLE VARIABLE is limited to only this function - outside of this function it is not available.
CREATE FUNCTION CustomerOrderDetails (#CustomerID NCHAR(5))
RETURNS #CustomerOrders TABLE (
CustomerID NCHAR(5)
,CompanyName NVARCHAR(40)
,OrderID INT
,OrderDate DATETIME
)
AS
BEGIN
INSERT INTO #CustomerOrders
SELECT C.CustomerID
,C.CompanyName
,O.OrderID
,O.OrderDate
FROM Customers C
INNER JOIN Orders O ON C.CustomerID = C.CustomerID
WHERE C.CustomerID = #CustomerID
RETURN
END
GO

How to pass user-defined table type to inline function

I have some complex function that I want to use in number of queries. It gets some list of values and return aggregate value.
For example (I simplify it, it is more complex in deed):
CREATE FUNCTION Mean(#N Numbers READONLY)
RETURNS TABLE AS RETURN (
SELECT mean = SUM(n.value) / COUNT(*) FROM #N n
)
and I want to use it in query:
SELECT d.DepartmentName, MeanRate = m.mean
FROM Departments d
CROSS APPLY Mean(
(
SELECT value = e.Rate
FROM Employees e
WHERE e.DepatmentId = d.DepatmentId
)
) m
But I get an error:
Operand type clash: float is incompatible with Numbers
I know that I can use cursor or pass values as XML, but I think this ways are slower than inline function and table variables.
How can I pass a list of values to inline function?
First you should create a table variable using the table type(Number) used in the Inline function.
Insert the required rows into table variable and pass the table variable o Inline function
You need to do something like this
declare #Numbers Numbers
Insert into #Numbers
select e.Rate
From Employees E join
Departments d on e.DepatmentId = d.DepatmentId
select * from Mean(#Numbers)
Update : Based on your comments
Create a new table type.
CREATE TYPE Dept_number AS TABLE
(
DepatmentId INT ,value numeric(22,6)
);
Alter the function
ALTER FUNCTION Mean(#dept_number DEPT_NUMBER readonly)
returns TABLE
AS
RETURN
(SELECT depatmentid,
mean = Sum(n.value) / Count(*)
FROM #dept_number n
GROUP BY depatmentid)
Calling the function
DECLARE #dept_number DEPT_NUMBER
INSERT INTO #dept_number
(depatmentid,
value)
SELECT d.depatmentid,
e.rate
FROM employees E
JOIN departments d
ON e.depatmentid = d.depatmentid
SELECT *
FROM Mean(#dept_number)

Calling User-Defined Function in select statement returning xml data

I created a user-defined function in SQL Server 2012 that returns XML. I would like to call the function in a SELECT statement. Is this possible?
When I try doing it, I get the error:
The FOR XML clause is not allowed in a ASSIGNMENT statement.
I want the SELECT statement to return a set of these named methods that have dependencies of other named methods within their logic.
In the main CTE, I get the latest versions of methods that have dependencies. The UDF goes thru the logic of each method and returns any methods called within it. So, I want to call the UDF in the SELECT statement and return XML of the dependent method names.
The function works and returns XML data. This is the function:
ALTER FUNCTION [dbo].[GetCalledMLMs]
(
-- Add the parameters for the function here
#MLM_Txt nvarchar(MAX)
)
RETURNS XML
AS
BEGIN
-- Declare the return variable here
DECLARE #CalledMLMs XML
Declare #MLMTbl table (pos int, endpos int, CalledMLM nvarchar(200))
--Logic to get the data...
Select #CalledMLMs = CalledMLM from #MLMTbl FOR XML PATH
-- Return the result of the function
RETURN #CalledMLMs
END
This is the CTE that calls the UDF.
;with cte as
(
select distinct Name, max(ID) as LatestVersion
from MLM_T
where Logic like '%:= MLM %' and Logic not like '%standard_libs := mlm%'
group by Name
)
select MLM2.Name, LatestVersion,
dbo.GetCalledMLMs(MLM2.Logic) as CalledMLMs
from cte join MLM_T MLM2 on cte.Name = MLM2.Name
and cte.LatestVersion = MLM2.ID
and MLM2.Active = 1 and MLM2.Status in (3, 4)
When running this query I get the error that XML is not allowed to be used in assignment statement.
Is there any way to call a function in the SELECT statment that returns an XML data type?
If you want to set a variable to a value you have to use SET and a scalar value on the right side.
The syntax SELECT #SomeVariable=SomeColumn FROM SomeTable is not possible with FOR XML (and rather dangerous anyway...), because the XML is not a column of the SELECT but something after the process of selecting.
Your problem is situated here:
Select #CalledMLMs = CalledMLM from #MLMTbl FOR XML PATH
Try to change this to
SET #CalledMLMs = (SELECT CalledMLM FROM #MLMTbl FRO XML PATH);
I solved the problem by changing the function to return a table, not XML.
So it looks like this:
FUNCTION [dbo].[GetCalledMLMsTbl]
(
-- Add the parameters for the function here
#MLM_Txt nvarchar(MAX)
)
--RETURNS XML
RETURNS #MLMTbl TABLE
(
pos int,
endpos int,
CalledMLM nvarchar(200)
)
AS
BEGIN
--logic here
insert into #MLMTbl (pos, endpos, CalledMLM) Values (#startpos, #endpos, #MLM_name)
RETURN
END
Then I called the function in the 'from' clause in the select
;with cte as
(
select distinct Name, max(ID) as LatestVersion
from CV3MLM
where Logic like '%:= MLM %' and Logic not like '%standard_libs := mlm%'
--and Name not like '%V61_CCC'
group by Name
)
select MLM2.Name, LatestVersion, C.CalledMLM
from cte join MLM_tbl MLM2 on cte.Name = MLM2.Name and cte.LatestVersion = MLM2.ID
and MLM2.Active = 1 and MLM2.Status in (3, 4)
cross apply dbo.GetCalledMLMsTbl(MLM2.Logic) C
order by MLM2.Name, LatestVersion

sqlmetal fails to extract udf with full-text

Error message:
Warning : SQM1014: Unable to extract function 'dbo.ProductFamilyIndex_EN' from SqlServer. Null or empty full-text predicate.
function defined as:
CREATE FUNCTION [dbo].[ProductFamilyIndex_EN]
(
#topn int,
#keywords nvarchar(4000)
)
RETURNS TABLE
AS
RETURN
(
select top (#topn) ProductFamilyID
from (
select pf.ProductFamilyID, t.[RANK] as _rank
from containstable(ProductFamily, (Name_EN), #keywords, LANGUAGE 'English', #topn) t
inner join ProductFamily pf on(pf.ProductFamilyID=t.[KEY])
union all
select p.ProductID as ProductFamilyID, t.[RANK] as _rank
from containstable(Product, (LongDescription_EN, ShortDescription_EN), #keywords, LANGUAGE 'English', #topn) t
inner join Product p on(p.ProductID=t.[KEY] and p.ProductFamilyID is null and p.Deleted is null)
) t
group by ProductFamilyID
order by max(_rank) desc
)
don't get confused by the union inside - that just means that a product without a family is a family on its own.
tried to give default values to the parameters:
#topn int = 1000,
#keywords nvarchar(4000) = 'test'
with the same result.
Using .NET 3.5 and sql2008.
As you mentioned, SQLMetal needs a return type.
Another way to solve this, is to explicitly set your default inside the stored procedure:
SET #topn = COALESCE(#topn, 1000)
Throw that before the SELECT statement to insure that any NULL parameters will return a valid value.
This is useful not only for SQLMetal, but for anyone who uses this function.
Reposting my own answer properly so I can close this thread.
Problem solved.
Apparently sqlmetal runs the function to figure out the return type, but insists on supplying null parameter instead of default, which seems like sqlmetal's bug.
Way to work around it is to declare return type explicitly:
alter function [dbo].[ProductFamilyIndex_EN] (#topn int, #keywords nvarchar(4000))
returns #t table (ProductFamilyID int not null)
as begin
...
return end

Resources