Pass table as parameter into sql server UDF

2019-01-03 10:16发布

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)

10条回答
我只想做你的唯一
2楼-- · 2019-01-03 10:30

Cutting to the bottom line, you want a query like SELECT x FROM y to be passed into a function that returns the values as a comma separated string.

As has already been explained you can do this by creating a table type and passing a UDT into the function, but this needs a multi-line statement.

You can pass XML around without declaring a typed table, but this seems to need a xml variable which is still a multi-line statement i.e.

DECLARE @MyXML XML = (SELECT x FROM y FOR XML RAW);
SELECT Dbo.CreateCSV(@MyXml);

The "FOR XML RAW" makes the SQL give you it's result set as some xml.

But you can bypass the variable using Cast(... AS XML). Then it's just a matter of some XQuery and a little concatenation trick:

CREATE FUNCTION CreateCSV (@MyXML XML) 
RETURNS VARCHAR(MAX)
BEGIN
    DECLARE @listStr VARCHAR(MAX);
    SELECT 
            @listStr = 
                COALESCE(@listStr+',' ,'') + 
                c.value('@Value[1]','nvarchar(max)') 
        FROM @myxml.nodes('/row') as T(c)
    RETURN @listStr
END
GO

-- And you call it like this:
SELECT Dbo.CreateCSV(CAST((    SELECT x FROM y    FOR XML RAW) AS XML));

-- Or a working example
SELECT Dbo.CreateCSV(CAST((
        SELECT DISTINCT number AS Value 
        FROM master..spt_values 
        WHERE type = 'P' 
            AND number <= 20
    FOR XML RAW) AS XML));

As long as you use FOR XML RAW all you need do is alias the column you want as Value, as this is hard coded in the function.

查看更多
啃猪蹄的小仙女
3楼-- · 2019-01-03 10:32

The following will enable you to quickly remove the duplicate,null values and return only the valid one as list.

CREATE TABLE DuplicateTable (Col1 INT)
INSERT INTO DuplicateTable
SELECT 8
UNION ALL
SELECT 1--duplicate
UNION ALL
SELECT 2 --duplicate
UNION ALL
SELECT 1
UNION ALL
SELECT 3
UNION ALL
SELECT 4
UNION ALL
SELECT 5
UNION 
SELECT NULL
GO

WITH CTE (COl1,DuplicateCount)
AS
(
SELECT COl1,
ROW_NUMBER() OVER(PARTITION BY COl1 ORDER BY Col1) AS DuplicateCount
FROM DuplicateTable
WHERE (col1 IS NOT NULL) 
)
SELECT COl1
FROM CTE
WHERE DuplicateCount =1
GO

CTE are valid in SQL 2005 , you could then store the values in a temp table and use it with your function.

查看更多
啃猪蹄的小仙女
4楼-- · 2019-01-03 10:33
    create table Project (ProjectId int, Description varchar(50));
    insert into Project values (1, 'Chase tail, change directions');
    insert into Project values (2, 'ping-pong ball in clothes dryer');

    create table ProjectResource (ProjectId int, ResourceId int, Name varchar(15));
    insert into ProjectResource values (1, 1, 'Adam');
    insert into ProjectResource values (1, 2, 'Kerry');
    insert into ProjectResource values (1, 3, 'Tom');
    insert into ProjectResource values (2, 4, 'David');
    insert into ProjectResource values (2, 5, 'Jeff');


    SELECT *, 
      (SELECT Name + ' ' AS [text()] 
       FROM ProjectResource pr 
       WHERE pr.ProjectId = p.ProjectId 
       FOR XML PATH ('')) 
    AS ResourceList 
    FROM Project p

-- ProjectId    Description                        ResourceList
-- 1            Chase tail, change directions      Adam Kerry Tom 
-- 2            ping-pong ball in clothes dryer    David Jeff 
查看更多
不美不萌又怎样
5楼-- · 2019-01-03 10:36

Step 1: Create a Type as Table with name TableType that will accept a table having one varchar column

create type TableType
as table ([value] varchar(100) null)

Step 2: Create a function that will accept above declared TableType as Table-Valued Parameter and String Value as Separator

create function dbo.fn_get_string_with_delimeter (@table TableType readonly,@Separator varchar(5))
returns varchar(500)
As
begin

    declare @return varchar(500)

    set @return = stuff((select @Separator + value from @table for xml path('')),1,1,'')

    return @return

end

Step 3: Pass table with one varchar column to the user-defined type TableType and ',' as separator in the function

select dbo.fn_get_string_with_delimeter(@tab, ',')
查看更多
家丑人穷心不美
6楼-- · 2019-01-03 10:41

you can do something like this

/* CREATE USER DEFINED TABLE TYPE */

CREATE TYPE StateMaster AS TABLE
(
 StateCode VARCHAR(2),
 StateDescp VARCHAR(250)
)
GO

/*CREATE FUNCTION WHICH TAKES TABLE AS A PARAMETER */

CREATE FUNCTION TableValuedParameterExample(@TmpTable StateMaster READONLY)
RETURNS  VARCHAR(250)
AS
BEGIN
 DECLARE @StateDescp VARCHAR(250)
 SELECT @StateDescp = StateDescp FROM @TmpTable
 RETURN @StateDescp
END
GO

/*CREATE STORED PROCEDURE WHICH TAKES TABLE AS A PARAMETER */

CREATE PROCEDURE TableValuedParameterExample_SP
(
@TmpTable StateMaster READONLY
)
AS
BEGIN
 INSERT INTO StateMst 
  SELECT * FROM @TmpTable
END
GO


BEGIN
/* DECLARE VARIABLE OF TABLE USER DEFINED TYPE */
DECLARE @MyTable StateMaster

/* INSERT DATA INTO TABLE TYPE */
INSERT INTO @MyTable VALUES('11','AndhraPradesh')
INSERT INTO @MyTable VALUES('12','Assam')

/* EXECUTE STORED PROCEDURE */
EXEC TableValuedParameterExample_SP @MyTable
GO

For more details check this link: http://sailajareddy-technical.blogspot.in/2012/09/passing-table-valued-parameter-to.html

查看更多
We Are One
7楼-- · 2019-01-03 10:43

To obtain the column count on a table, use this:

select count(id) from syscolumns where id = object_id('tablename')

and to pass a table to a function, try XML as show here:

create function dbo.ReadXml (@xmlMatrix xml)
returns table
as
return
( select
t.value('./@Salary', 'integer') as Salary,
t.value('./@Age', 'integer') as Age
from @xmlMatrix.nodes('//row') x(t)
)
go

declare @source table
( Salary integer,
age tinyint
)
insert into @source
select 10000, 25 union all
select 15000, 27 union all
select 12000, 18 union all
select 15000, 36 union all
select 16000, 57 union all
select 17000, 44 union all
select 18000, 32 union all
select 19000, 56 union all
select 25000, 34 union all
select 7500, 29
--select * from @source

declare @functionArgument xml

select @functionArgument =
( select
Salary as [row/@Salary],
Age as [row/@Age]
from @source
for xml path('')
)
--select @functionArgument as [@functionArgument]

select * from readXml(@functionArgument)

/* -------- Sample Output: --------
Salary Age
----------- -----------
10000 25
15000 27
12000 18
15000 36
16000 57
17000 44
18000 32
19000 56
25000 34
7500 29
*/
查看更多
登录 后发表回答