Convert scalar function to table function - sql-server

I have a scalar function that returns a value from a select statement if it returns a value for the appropriate variables. If there is no return value, the scalar function returns one of the input parameters as the result.
How can I solve this in a table function?
Can I may be use this:
WITH Param
AS (
SELECT ID
,Data
FROM Configuration
WHERE NAME = 'NameOfConfiguration'
UNION ALL
SELECT NULL
,'Default Value'
)
SELECT TOP 1 Data
FROM Param
ORDER BY ID DESC
instead of this:
IF (LEN(ISNULL(#returnvalue, '')) = 0)
BEGIN
RETURN #thisvalue
END
RETURN #returnvalue

Table valued function and scalar valued functions are entirely different.
https://msdn.microsoft.com/en-us/library/ms191320.aspx?f=255&MSPPError=-2147217396
This link would give you how to create table valued and scalar functions.
Please feel to revert back if you have need more clarification :)

Related

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

SQL function to return two values and assign to two variable in stored procedure

I want to get back two values from the the function and first value assign to one variable and second value assign to another variable write now i get by calling the function two time by passing return type parameter for example #retType 1 then return first value if #retType 2 then return second value
but i need to call fuinction two time but my intension is to call only one time and get two values to two variable is it possible ?...
Stored procedure:
DECLARE #policy_effitive_st DATE -- policy Period Start From
DECLARE #policy_effitive_end DATE -- calculated date
SELECT
#policy_effitive_end = policydatecalc(memberid) --assign first column column1
, #policy_effitive_end = policydatecalc(memberid) --assign second column column2
FROM
member
Function:
CREATE FUNCTION [owner].[policydatecalc]
(#parm1 <datatpe> = <default>)
RETURNS TABLE
AS RETURN
(
DECLARE #col1,#col2 date
--- calulation for dates logic here
SELECT #col1,#col2 )
You need to create a table-valued function like this (see the details of exactly how to define a table-valued function in the official MSDN or Technet documentation - they are really good and extensive!):
CREATE FUNCTION dbo.policydatecalc
(#NumberOfMonths INT = 1)
RETURNS #OutputTbl TABLE (DateValStart DATE, DateValEnd DATE)
AS
BEGIN
INSERT INTO #OutputTbl (DateValStart, DateValEnd)
VALUES (SYSDATETIME(), DATEADD(MONTH, #NumberOfMonths, SYSDATETIME()));
RETURN
END
and then you can call it and assign its values in the stored procedure like this:
CREATE PROCEDURE dbo.SomeProcedure
AS
BEGIN
DECLARE #Start DATE, #End DATE
SELECT
#Start = DateValStart,
#End = DateValEnd
FROM
dbo.policydatecalc(4)
END
The function declaration defines a table type (and a variable of that type) that gets returned - and that's what you'll get back in the stored procedure when you call the function. This is like any other table - you can select from it and assign the values to internal variables in the stored procedure.

How do sql can understand or convert a nvarchar is name of a table in sql server

I Waint run code in SQL SERVER
ALTER FUNCTION return_table (#table nvarchar(250))
RETURNS TABLE
AS
RETURN
(
SELECT * FROM #table
)
none using PROCEDURE . THANK FOR HELP
The only way to make this work is truly horrible for both aesthetic and (probably) performance reasons. It also assumes that all tables that might be passed as parameters have the same structure:
ALTER FUNCTION return_table (#table sysname)
RETURNS TABLE
AS
RETURN
(
SELECT * FROM TableA where #table = 'TableA'
UNION ALL
SELECT * FROM TableB where #table = 'TableB'
UNION ALL
SELECT * FROM TableC where #table = 'TableC'
/* add more UNIONs and SELECTs for each table that you want to use */
)
A function requires an explicit definition of the return value type, e.g. the columns being returned. The SQL statement you provided will not work in such a manner for the following reasons:
ALTER FUNCTION return_table (#table nvarchar(250)) -- You have declared a parameter of type table, this is not the right way of doing this
RETURNS TABLE -- you haven't defined the structure of the table being returned, this needs explicitly defining
AS
RETURN
(
SELECT * FROM #table -- using SELECT * is bad practice as the structure of the table may change and then conflict with the structure of the table being returned
)
The first part of the problem is declaring a parameter of type TABLE; this question has good examples on how to get around doing this. Quick summary: you need to declare the table as a type before passing in the type as the parameter to your function:
CREATE TYPE MyTableParameterDefinition AS TABLE (
[ColumnName] NVARCHAR(250) NULL
)
This type can then be passed as a parameter to your function:
CREATE FUNCTION myFunctionName (
#TableVariable MyTableParameterDefinition READONLY
)...--INSERT CODE HERE--
I'm uncertain whether you can use a similar method for the return type and would suggest against this given the implication of the contract defined by the function. Better practice would be to define the structure of the table being returned and explicitly select the columns from the table:
ALTER FUNCTION return_table (
#table MyTableParameterDefinition
)
RETURNS TABLE
(
-- Explicitly define columns returned by the function
[ColumnName] NVARCHAR(250) NULL
)
AS
RETURN
(
SELECT
[ColumnName]
FROM
#table
)

Using return next and return query in the same Postgres function

I am a newbie in PostgreSQL (using v9.0) and wanted to know if using return next and Return query in the same function is possible without exiting the function before attaching the results in the resultset?
CREATE TYPE return_type AS
(paramname character varying,
value character varying);
CREATE OR REPLACE FUNCTION myfuntion(param1 character varying)
RETURNS SETOF return_type AS
declare
r return_type;
message varchar;
status integer;
$BODY$
BEGIN
o_call_status := 0;
o_call_message := '';
Return query Select 'mystatus' as paramName, status::varchar as value;
Return query Select 'mymessage' as paramName, message as value;
for r in SELECT 'mycolumnname1' as paramName,mycolumn1 as value FROM tb1
WHERE column1 = val
UNION ALL
SELECT 'mycolumnname2' as paramName,mycolumn2 as value FROM tb1
WHERE column1 = val
UNION ALL
SELECT 'mycolumnname3' as paramName,mycolumn3 as value FROM tb2
WHERE column1 = val1 AND
column4 = val4 loop
return next r;
end loop;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
Returning from a plpgsql function
You can mix RETURN NEXT and RETURN QUERY freely and repeatedly. The underlying principle is that plpgsql builds the table locally and does not return until the function is finished:
Per documentation:
Note: The current implementation of RETURN NEXT and RETURN QUERY
stores the entire result set before returning from the function, as discussed above.
That means you can even raise en exception to abort the operation if you are unsatisfied with the results so far and the client won't see a thing. We also included an example in the manual demonstrating this, just above said quote.
Cross tabulation
As for what you are trying do achieve, consider the crosstab() function for the tablefunc extension. Related answer with sample details:
PostgreSQL Crosstab Query
I'm unsure if you can mix the two (try it…).
That said, it'll be much more efficient in you use-case to write a single query with a union all clauses that returns all rows directly:
return query
select 'mystatus' as paramName, status::varchar as value
union all
select 'mymessage' as paramName, message as value
union all
SELECT 'mycolumnname1' as paramName,mycolumn1 as value
FROM tb1
WHERE column1 = val
union all
…
You might also find this contrib module helpful, btw:
http://www.postgresql.org/docs/current/static/tablefunc.html
And, if possible, revisit your schema or the way you use it, so you don't need this kind of function to begin with — set returning functions that return potentially large sets can be particularly inefficient. In your case, it seems like you want three columns. Why not simple use?
select col1, col2, col3 from tbl

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