Passing multiple values to a parameter of a function in SQL - sql

There is function Getfunctionname(userid, startdate, enddate) to return a table
My question is can I pass a variable with multiple values?
i.e.
getfunctionname(#userid, startdate, enddate)
Where the value of variable #userid is like
1
2
3
4
5
(actually using split function splitting the values from being 1,2,3,4,5 )
If I can please let me know

One way of doing that which I prefer is to make a new user-defined table data type.
CREATE TYPE [dbo].[IdList] AS TABLE(
[Id] [int] NULL
)
Then you can use that data type as one of the parameters
CREATE FUNCTION Getfunctionname
(
#UserIDs dbo.IdList READONLY,
#startdate INT,
#endtdate INT
)
RETURNS #ReturnTable TABLE
(
-- ReturnTable
)
AS
BEGIN
-- Query
RETURN
END

Use the concept of CSV
CREATE FUNCTION [dbo].[uspGetNumbers]
userid,startdate,enddate // define your paramters the way you want
AS
BEGIN
// your code
JOIN dbo.fnSplit(#UserIDs, ',')
END
GO
Example function:
SELECT [dbo].[uspGetNumbers] '1,2,3,4,5', '', ''

I just ran into this, and I used the CROSS APPLY solution from this post:
SQL Server: run function for each row based on the provided row value
To use CROSS APPLY, you would need to first select your values, and then CROSS APPLY. I have not used the split function before, so I don't have the exact syntax,
but if you use it something like:
select #userid, F1.* from split(1,2,3,4,5),
CROSS APPLY getfunctionname(#userid, startdate, enddate) F1

Related

What is the simplest way to put pass an array of values into a parameter of TVF

Objective:
I would like to have a parameter in my function to allow the user to input a list of values. Ideally, the simplest solution ... Note: I dont have permissions to create tables in dbs.
Situation:
CREATE FUNCTION dbo.fnExample
(
#StartDate AS Date -- Parameter 1
#ParameterArray AS ... -- This would be the parameter that accepts a list of values
)
RETURNS TABLE
AS
RETURN
...code...
GO
Not sure how to pass several parameters in a TVF but this is how I would view the solution
SELECT *
FROM dbo.fnExample ('2019-01-01') and ([list of values])
Using a table type parameter, you can do something like the following:
CREATE TYPE dbo.SomeArray AS TABLE (SomeInt int); --Create the TYPE
GO
--Now the Function
CREATE FUNCTION dbo.Example (#StartDate date, #Array dbo.SomeArray READONLY)
RETURNS TABLE
AS RETURN
SELECT DATEADD(DAY, SomeInt, #StartDate) AS NewDate
FROM #Array
GO
--Now to test
--Declare the TYPE
DECLARE #Array dbo.SomeArray;
--Insert the data
INSERT INTO #Array (SomeInt)
VALUES(7),(1654),(13);
--Test the function
SELECT *
FROM dbo.Example(GETDATE(), #Array) E;
GO
--Clean up
DROP FUNCTION dbo.Example;
DROP TYPE dbo.SomeArray;
How to JOIN:
FROM dbo.YourTable YT
JOIN #Array A ON YT.SomeInt = A.SomeInt
How to use EXISTS:
WHERE EXISTS (SELECT 1 FROM #Array A WHERE YT.SomeInt = A.SomeInt)
If you're on SQL Server 2016+ the simplest way is to use JSON:
CREATE FUNCTION dbo.fnExample
(
#StartDate AS Date -- Parameter 1
#ParameterArray AS NVARCHAR(MAX) -- pass JSON Array like '[1,2,3,4,5]'
)
RETURNS TABLE
AS
RETURN
SELECT TRY_CONVERT(INT,j.value) AS [ID] FROM OPENJSON(#ParameterArray) j;
GO

To Create a Function to split dates into Year, Month, Date into a separate column in SQL

Trying to create a function to split dateformat of "2018-05-21" to 2018 | 05 | 21 | as three separate columns. Tried creating the function as below but gives me error on "month", "Day". Error says "incorrect syntax near 'month'. Expecting '(' or Select."
CREATE FUNCTION [dbo].[functionname]
(
-- Add the parameters for the function here
#DateFormat AS DATETIME
)
RETURNS VARCHAR (MAX)
AS
BEGIN
RETURN DATEPART(YEAR,#DateFormat),
DATEPART(Month,#DateFormat),
DATEPART(Day,#DateFormat)
END
GO
The problem with your current SQL is that a scalar only returns a single value. You need to use a table value function to get multiple columns.
This is a TVF version which will provide three columns
CREATE FUNCTION [dbo].[FunctionName]
(
#DateFormat AS DATETIME
)
RETURNS TABLE AS RETURN
(
SELECT DATEPART(YEAR,#DateFormat) AS [Year],
DATEPART(Month,#DateFormat) AS [Month],
DATEPART(Day,#DateFormat) AS [Day]
)
Example usage:
DECLARE #dates TABLE (SomeDate DATE)
INSERT INTO #dates SELECT '01/25/2018'
INSERT INTO #dates SELECT '10/01/2008'
SELECT d.*,fn.* FROM #dates d
CROSS APPLY [dbo].[FunctionName](d.SomeDate) fn
And some documentation.
That said, I personally don't like this implementation. I would simply expect the DATEPART statements in the SELECT portion of the SQL. I think the TVF makes it more complicated and doesn't provide any tangible benefits.

multiple selects from a function into a temp table

I have a function helper_function which I want to reuse
Passing a parameter to another function f_union_helper_functions where a string id_string with ids is passed
Split this string and iterate through all ids
calling the function and adding result to a temp table
return select from this table
Pseudo code:
create function f_union_helper_functions
(
#id_string varchar,
...
return table as
return
(
...
foreach id in #id_string
begin
select * from helper_function(id) into #tmp
end
select #tmp
)
This code above is far from being complete/correct. I just want to combine the concepts of iterating and union into a temp table and return it. How can I achieve that?
Here is the way I solved it:
ALTER FUNCTION [dbo].[f_union_helper_functions]
(
#id_string NVARCHAR(1024)
)
RETURNS TABLE
AS
RETURN
(
SELECT * FROM [dbo].[fnSplit](#id_string, ',') c CROSS APPLY [dbo].[helper_function](c.item)
)
If you got SQLServer >= 2016 you can use STRING_SPLIT instead of [fnSplit], which I got from here https://kishsharma.wordpress.com/2013/08/20/sql-server-user-defined-function-to-split-the-string-by-special-char/

sql insert into table which uses newid in user defined function [duplicate]

I have to insert a fake column at the result of a query, which is the return value of a table-value function. This column data type must be unique-identifier. The best way (I think...) is to use newid() function. The problem is, I can't use newid() inside this type of function:
Invalid use of side-effecting or time-dependent operator in 'newid()' within a function.
here's a clever solution:
create view getNewID as select newid() as new_id
create function myfunction ()
returns uniqueidentifier
as begin
return (select new_id from getNewID)
end
that i can't take credit for. i found it here:
http://omnibuzz-sql.blogspot.com/2006/07/accessing-non-deterministic-functions.html
-don
You can pass NEWID() as a parameter to your function.
CREATE FUNCTION SOMEIDFUNCTION
(
#NEWID1 as varchar(36), #NEWID2 as varchar(36)
)
RETURNS varchar(18)
AS
BEGIN
-- Do something --
DECLARE #SFID varchar(18)
SELECT #SFID = 'DYN0000000' + LOWER(LEFT(#NEWID1,4)) + LEFT(#NEWID2,4)
RETURN #SFID
END
GO
Call the function like this;
SELECT dbo.SOMEIDFUNCTION(NewID(),NewID())
use it as a default instead
create table test(id uniqueidentifier default newsequentialid(),id2 int)
insert test(id2) values(1)
select * from test
NB I used newsequentialid() instead of newid() since newid() will cause pagesplits since it is not sequential, see here: Some Simple Code To Show The Difference Between Newid And Newsequentialid
You could use ROW_NUMBER function:
SELECT
(ROW_NUMBER() OVER (ORDER BY recordID) ) as RowNumber ,
recordID,
fieldBla1
FROM tableName
Find more information at http://msdn.microsoft.com/pt-br/library/ms186734.aspx

T-SQL Foreach Loop

Scenario
I have a stored procedure written in T-Sql using SQL Server 2005.
"SEL_ValuesByAssetName"
It accepts a unique string "AssetName".
It returns a table of values.
Question
Instead of calling the stored procedure multiple times and having to make a database call everytime I do this, I want to create another stored procedure that accepts a list of all the "AssetNames", and calls the stored procedure "SEL_ValueByAssetName" for each assetname in the list, and then returns the ENTIRE TABLE OF VALUES.
Pseudo Code
foreach(value in #AllAssetsList)
{
#AssetName = value
SEL_ValueByAssetName(#AssetName)
UPDATE #TempTable
}
How would I go about doing this?
It will look quite crippled with using Stored Procedures. But can you use Table-Valued Functions instead?
In case of Table-Valued functions it would look something like:
SELECT al.Value AS AssetName, av.* FROM #AllAssetsList AS al
CROSS APPLY SEL_ValuesByAssetName(al.Value) AS av
Sample implementation:
First of all, we need to create a Table-Valued Parameter type:
CREATE TYPE [dbo].[tvpStringTable] AS TABLE(Value varchar(max) NOT NULL)
Then, we need a function to get a value of a specific asset:
CREATE FUNCTION [dbo].[tvfGetAssetValue]
(
#assetName varchar(max)
)
RETURNS TABLE
AS
RETURN
(
-- Add the SELECT statement with parameter references here
SELECT 0 AS AssetValue
UNION
SELECT 5 AS AssetValue
UNION
SELECT 7 AS AssetValue
)
Next, a function to return a list AssetName, AssetValue for assets list:
CREATE FUNCTION [dbo].[tvfGetAllAssets]
(
#assetsList tvpStringTable READONLY
)
RETURNS TABLE
AS
RETURN
(
-- Add the SELECT statement with parameter references here
SELECT al.Value AS AssetName, av.AssetValue FROM #assetsList al
CROSS APPLY tvfGetAssetValue(al.Value) AS av
)
Finally, we can test it:
DECLARE #names tvpStringTable
INSERT INTO #names VALUES ('name1'), ('name2'), ('name3')
SELECT * FROM [Test].[dbo].[tvfGetAllAssets] (#names)
In MSSQL 2000 I would make #allAssetsList a Varchar comma separated values list. (and keep in mind that maximum length is 8000)
I would create a temporary table in the memory, parse this string and insert into that table, then do a simple query with the condition where assetName in (select assetName from #tempTable)
I wrote about MSSQL 2000 because I am not sure whether MSSQL 2005 has some new data type like an array that can be passed as a literal to the SP.