Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pass table as parameter into sql server UDF

I'd like to pass a table as a parameter into a scaler UDF.

I'd also prefer to restrict the parameter to tables with only one column. (optional)

Is this possible?

EDIT

I don't want to pass a table name, I'd like to pass the table of data (as a reference I presume)

EDIT

I would want my Scaler UDF to basically take a table of values and return a CSV list of the rows.

IE

col1   "My First Value"   "My Second Value" ... "My nth Value" 

would return

"My First Value, My Second Value,... My nth Value" 

I'd like to do some filtering on the table though, IE ensuring that there are no nulls and to ensure there are no duplicates. I was expecting something along the lines of:

SELECT dbo.MyFunction(SELECT DISTINCT myDate FROM myTable WHERE myDate IS NOT NULL) 
like image 522
Nathan Koop Avatar asked Oct 22 '09 18:10

Nathan Koop


People also ask

Can I pass a table as a parameter in SQL?

A table-valued parameter is a parameter with a table type. Using this parameter, you can send multiple rows of data to a stored procedure or a parameterized SQL command in the form of a table. Transact-SQL can be used to access the column values of the table-valued parameters.

Can we pass temp table as parameter to function in SQL Server?

A TEMP Table of User Defined Table Type has to be created of the same schema as that of the Table Valued parameter and then it is passed as Parameter to the Stored Procedure in SQL Server.

Can we pass table as a parameter to stored procedure?

Table-Valued Parameters aka TVPs are commonly used to pass a table as a parameter into stored procedures or functions. They are helpful in a way, we can use a table as an input to these routines and we can get rid of dealing more complex steps to achieve this process.


2 Answers

You can, however no any table. From documentation:

For Transact-SQL functions, all data types, including CLR user-defined types and user-defined table types, are allowed except the timestamp data type.

You can use user-defined table types.

Example of user-defined table type:

CREATE TYPE TableType  AS TABLE (LocationName VARCHAR(50)) GO   DECLARE @myTable TableType INSERT INTO @myTable(LocationName) VALUES('aaa') SELECT * FROM @myTable 

So what you can do is to define your table type, for example TableType and define the function which takes the parameter of this type. An example function:

CREATE FUNCTION Example( @TableName TableType READONLY) RETURNS VARCHAR(50) AS BEGIN     DECLARE @name VARCHAR(50)      SELECT TOP 1 @name = LocationName FROM @TableName     RETURN @name END 

The parameter has to be READONLY. And example usage:

DECLARE @myTable TableType INSERT INTO @myTable(LocationName) VALUES('aaa') SELECT * FROM @myTable  SELECT dbo.Example(@myTable) 

Depending on what you want achieve you can modify this code.

EDIT: If you have a data in a table you may create a variable:

DECLARE @myTable TableType 

And take data from your table to the variable

INSERT INTO @myTable(field_name) SELECT field_name_2 FROM my_other_table 
like image 87
Lukasz Lysik Avatar answered Oct 02 '22 09:10

Lukasz Lysik


Unfortunately, there is no simple way in SQL Server 2005. Lukasz' answer is correct for SQL Server 2008 though and the feature is long overdue

Any solution would involve temp tables, or passing in xml/CSV and parsing in the UDF. Example: change to xml, parse in udf

DECLARE @psuedotable xml  SELECT     @psuedotable = ... FROM     ... FOR XML ...  SELECT ... dbo.MyUDF (@psuedotable) 

What do you want to do in the bigger picture though? There may be another way to do this...

Edit: Why not pass in the query as a string and use a stored proc with output parameter

Note: this is an untested bit of code, and you'd need to think about SQL injection etc. However, it also satisfies your "one column" requirement and should help you along

CREATE PROC dbo.ToCSV (     @MyQuery varchar(2000),     @CSVOut varchar(max) ) AS SET NOCOUNT ON  CREATE TABLE #foo (bar varchar(max))  INSERT #foo EXEC (@MyQuery)  SELECT     @CSVOut = SUBSTRING(buzz, 2, 2000000000) FROM     (     SELECT          bar -- maybe CAST(bar AS varchar(max))??     FROM          #foo     FOR XML PATH (',')     ) fizz(buzz) GO 
like image 35
gbn Avatar answered Oct 02 '22 11:10

gbn