SQL - create function that will take a table variable as an input - sql

I'm having trouble writing a function that will take a table variable as an input and return the total number of rows in that table.
Here is my try:
CREATE FUNCTION fTableRows( #table TABLE )
RETURNS INT AS
BEGIN
RETURN( SELECT COUNT(*) FROM #table )
END

If you do this in SQL server 2008 + you have use user defined data type - table.
Good explanation can be found here: Pass table as parameter into SQL Udf

CREATE FUNCTION getTableRows
(
#TableName VARCHAR(30)
)
RETURNS INT AS
BEGIN
RETURN( SELECT COUNT(*) FROM #TableName)
END

Related

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/

Multiple values in a single parameter of a scalar function

Is there a way to input multiple values in a single parameter of a scalar-valued function in SQL Server 2008 R2 and have it filter data by that parameter using both values?
For example I would like to do the following
SET #Salesperson='BILL' OR 'MOSES'
SELECT Sum(SalesDollars)
FROM Invoices
WHERE Invoices.Salesperson = #Salesperson
I attempted to use the following as the WHERE clause, but this didnt work either.
SET #Salesperson='BILL','MOSES'
SELECT Sum(SalesDollars)
FROM Invoices
WHERE Invoices.Salesperson IN (#Salesperson)
Would it be easier if i were dealing with integers as opposed to varchar values?
Any help would be absolutely appreciated!
You need to use table-valued parameters. Look it up on technet or msdn
Best part of it that your table-valued parameters can have multiple columns.
Note however that you have to define TVP parameter as readonly. So if you want to return similar set from your function you will need to create another variable inside your function.
Example:
CREATE TYPE Names AS TABLE
( Name VARCHAR(50));
GO
/* Create a procedure to receive data for the table-valued parameter. */
CREATE PROCEDURE dbo.mySP
#n Names READONLY
AS
SELECT Sum(SalesDollars)
FROM
WHERE Invoices.Salesperson in (select Name from #n)
GO
CREATE FUNCTION dbo.myFun(#n Names READONLY) returns int
AS
SELECT Sum(SalesDollars)
FROM
WHERE Invoices.Salesperson in (select Name from #n)
GO
/* Declare a variable that references the type. */
DECLARE #names AS Names;
/* Add data to the table variable. */
INSERT INTO #names (Name)
VALUES ('BILL'),('MOSES')
-- using stored procedure with TVP
EXEC dbo.mySP #names
-- using function with TVP
select dbo.myFun(#names)
GO
This could be done this way:
SET #Salesperson='BILL,MOSES'
SELECT *
FROM YourTable
WHERE Invoices.Salesperson IN (SELECT * FROM dbo.split(#Salesperson,','))
This is how you split the values.
I would typically do this using a user defined table type: SQL Fiddle Example.
CREATE TYPE <schema>.SalespersonList AS TABLE
(
Name varchar(32)
)
You may have to grant execute permissions on the type:
GRANT EXECUTE ON TYPE::<schema>.SalespersonList TO <user>
Then you can create a function to use it:
CREATE FUNCTION <schema>.fnGetTotalSales
(
#nameList <schema>.SalespersonList READONLY
)
RETURNS INT
AS
BEGIN
DECLARE #ret INT
SELECT #ret = Sum(SalesDollars)
FROM Invoices i
INNER JOIN #nameList nl ON nl.Name = i.Salesperson
RETURN #ret
END
Then you would just insert your list into the type and call the function:
DECLARE #salesPersonList <schema>.SalespersonList
INSERT INTO #salesPersonList (Name)
SELECT 'Bill'
UNION
SELECT 'Moses'
SELECT <schema>.fnGetTotalSales(#salesPersonList)

Returning a table from a function with parameters in SQL

As far as I know, we can return a table as a result of a db function:
CREATE FUNCTION MyFunction(#Value varchar(100))
RETURNS table
AS RETURN (select * from MyTable where ColumnName = '#Value')
in this example we can make the column name as a parameter for the function. My question is, can we write the column name and table name as a parameter for the function? hence we can write a more generic function something like:
CREATE FUNCTION MyGenericSearchFunction(#TableName varchar(100), #ColumnName varchar(100), #Value varchar(100))
RETURNS table
AS RETURN (select * from #TableName where #ColumnName = '#Value')
No, you can't.
This would then be a dynamic query.
For dynamic queries in SQL Server, one has to use exec() or sp_executesql() functions, which are not allowed in functions.

Returning or outputting a #tableVariable in SQL

Is it possible to return or output a #tableVariable in SQL Server?
For example for the following stored procedure, how do I return the #TSV table variable?
ALTER PROCEDURE MyStoredProdecure
#Parameter1 INT,
#Parameter2 INT
AS
BEGIN
DECLARE #TSV TABLE
(
Transition_Set_Variable_ID INT,
Passed BIT
)
INSERT INTO #TSV
{ some data }
END
You cannot do it directly. Table variables are valid for READONLY input.
If you have no other data being returned from the stored procedure, you can select from the #TSV at the end and have the caller capture the output, e.g.
ALTER PROCEDURE MyStoredProdecure
#Parameter1 INT,
#Parameter2 INT
AS
BEGIN
DECLARE #TSV TABLE
(
Transition_Set_Variable_ID INT,
Passed BIT
)
INSERT INTO #TSV
{ some data }
SELECT * FROM #TSV
END
Caller
DECLARE #outerTSV TABLE
(
Transition_Set_Variable_ID INT,
Passed BIT
);
insert into #outerTSV
exec MyStoredProdecure 1, 2;
Alternatively, if the SP is really as simple as you showed, turn it into a table valued function instead.
No, but you can write a table valued function that returns a table.
create function MyTVF
#Parameter1 INT,
#Parameter2 INT
returns #tsv table
(
Transition_Set_Variable_ID INT,
Passed BIT
)
AS
BEGIN
INSERT INTO #TSV
{ some data }
return
END
Table Valued Parameters can only be used for input only, not output.
Depending on what your end goal is, here are some options:
change the sproc to a table-valued function to return a TABLE, that can then be used inline in another statement
simply SELECT the data from the #TSV table var at the end of your sproc
return an XML OUTPUT parameter (get a grubby feeling suggesting this, but just to highlight one way to return multiple rows actually using an OUTPUT parameter)
If you go for a Table Valued Function, ideally create an inline one if it is simple as it looks in your case:
e.g.
CREATE FUNCTION dbo.Func()
RETURNS TABLE
AS
RETURN
(
SELECT Something
FROM Somewhere
WHERE x = 1
)

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