将表格作为parameter passing给sql server UDF
我想将一个表作为parameter passing给一个缩放UDF。
我还希望限制参数只有一列的表。 (可选的)
这可能吗?
编辑
我不想传递一个表名,我想通过数据表(作为我想的参考)
编辑
我希望我的Scaler UDF基本上获取一个值的表,并返回一个CSV列表的行。
IE
col1 "My First Value" "My Second Value" ... "My nth Value"
会返回
"My First Value, My Second Value,... My nth Value"
我想在桌面上做一些过滤,IE确保没有空值,并确保没有重复。 我期待着以下几点:
SELECT dbo.MyFunction(SELECT DISTINCT myDate FROM myTable WHERE myDate IS NOT NULL)
不幸的是,在SQL Server 2005中没有简单的方法。虽然Lukasz的答案对于SQL Server 2008是正确的,
任何解决scheme都会涉及临时表,或者在UDF中传递xml / CSV和parsing。 例如:更改为xml,在udf中parsing
DECLARE @psuedotable xml SELECT @psuedotable = ... FROM ... FOR XML ... SELECT ... dbo.MyUDF (@psuedotable)
你想在大的图景中做什么? 有可能是另一种方法来做到这一点…
编辑:为什么不传递查询作为一个string,并使用输出参数存储过程
注意:这是一段未经testing的代码,您需要考虑SQL注入等。但是,它也满足您的“单列”要求,应该帮助您
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
你可以,但是没有任何表。 从文档:
对于Transact-SQL函数,除时间戳数据types之外,所有数据types(包括CLR用户定义types和用户定义表types)都是允许的。
您可以使用用户定义的表格types 。
用户定义的表格types的示例:
CREATE TYPE TableType AS TABLE (LocationName VARCHAR(50)) GO DECLARE @myTable TableType INSERT INTO @myTable(LocationName) VALUES('aaa') SELECT * FROM @myTable
所以你可以做的是定义你的表types,例如TableType
和定义funcion这个参数就是这个types。一个例子函数:
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
该参数必须是READONLY。 和示例用法:
DECLARE @myTable TableType INSERT INTO @myTable(LocationName) VALUES('aaa') SELECT * FROM @myTable SELECT dbo.Example(@myTable)
根据你想要达到什么,你可以修改这个代码。
编辑:如果你有一个表中的数据,你可以创build一个variables:
DECLARE @myTable TableType
并从你的表中的数据variables
INSERT INTO @myTable(field_name) SELECT field_name_2 FROm my_other_table
切割到底线,你想要一个像SELECT x FROM y这样的查询被传递给一个函数,该函数以逗号分隔的string的forms返回值。
正如已经解释过的,你可以通过创build一个表types并将一个UDT传递给函数来实现,但是这需要一个多行语句。
你可以在不声明types表的情况下传递XML,但是这似乎需要一个xmlvariables,它仍然是一个多行语句,
DECLARE @MyXML XML = (SELECT x FROM y FOR XML RAW); SELECT Dbo.CreateCSV(@MyXml);
“FOR XML RAW”使SQL给你它的结果集为一些XML。
但是可以使用Cast(… AS XML)绕过variables。 那么这只是一些XQuery和一个小小的连接技巧:
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));
只要您使用FOR XML RAW,您所需要做的就是作为Value的别名,因为这是硬编码的函数。
我一直在处理一个非常类似的问题,已经能够实现我正在寻找的东西,即使我正在使用SQL Server 2000.我知道这是一个老问题,但认为它是有效的在这里发布解决scheme应该有像我这样的老版本,仍然需要帮助。
这里的技巧是:SQL Server不会接受将表传递给UDF,也不能传递T-SQL查询,以便函数创build临时表,甚至调用存储过程来完成此操作。 所以,相反,我创build了一个保留表,我称之为xtList。 这将包含值的列表(1列,根据需要)来处理。
CREATE TABLE [dbo].[xtList]( [List] [varchar](1000) NULL ) ON [PRIMARY]
然后,一个存储过程来填充列表。 这不是绝对必要的,但我认为是非常有用和最好的做法。
-- ============================================= -- Author: Zark Khullah -- Create date: 20/06/2014 -- ============================================= CREATE PROCEDURE [dbo].[xpCreateList] @ListQuery varchar(2000) AS BEGIN SET NOCOUNT ON; DELETE FROM xtList INSERT INTO xtList EXEC(@ListQuery) END
现在,只要用你想要的方式处理列表,使用xtList。 您可以在一个过程(用于执行多个T-SQL命令),标量函数(用于检索多个string)或多语句表值函数(检索string,但是像在一个表内,每行1个string)中使用。 对于任何一个,你将需要游标:
DECLARE @Item varchar(100) DECLARE cList CURSOR DYNAMIC FOR (SELECT * FROM xtList WHERE List is not NULL) OPEN cList FETCH FIRST FROM cList INTO @Item WHILE @@FETCH_STATUS = 0 BEGIN << desired action with values >> FETCH NEXT FROM cList INTO @Item END CLOSE cList DEALLOCATE cList
所需的操作如下,取决于创build的对象types:
存储过程
-- ============================================= -- Author: Zark Khullah -- Create date: 20/06/2014 -- ============================================= CREATE PROCEDURE [dbo].[xpProcreateExec] ( @Cmd varchar(8000), @ReplaceWith varchar(1000) ) AS BEGIN DECLARE @Query varchar(8000) << cursor start >> SET @Query = REPLACE(@Cmd,@ReplaceWith,@Item) EXEC(@Query) << cursor end >> END /* EXAMPLES (List A,B,C) Query = 'SELECT x FROM table' with EXEC xpProcreateExec(Query,'x') turns into SELECT A FROM table SELECT B FROM table SELECT C FROM table Cmd = 'EXEC procedure ''arg''' --whatchout for wrong quotes, since it executes as dynamic SQL with EXEC xpProcreateExec(Cmd,'arg') turns into EXEC procedure 'A' EXEC procedure 'B' EXEC procedure 'C' */
标量函数
-- ============================================= -- Author: Zark Khullah -- Create date: 20/06/2014 -- ============================================= CREATE FUNCTION [dbo].[xfProcreateStr] ( @OriginalText varchar(8000), @ReplaceWith varchar(1000) ) RETURNS varchar(8000) AS BEGIN DECLARE @Result varchar(8000) SET @Result = '' << cursor start >> SET @Result = @Result + REPLACE(@OriginalText,@ReplaceWith,@Item) + char(13) + char(10) << cursor end >> RETURN @Result END /* EXAMPLE (List A,B,C) Text = 'Access provided for user x' with "SELECT dbo.xfProcreateStr(Text,'x')" turns into 'Access provided for user A Access provided for user B Access provided for user C' */
多语句表值函数
-- ============================================= -- Author: Zark Khullah -- Create date: 20/06/2014 -- ============================================= CREATE FUNCTION [dbo].[xfProcreateInRows] ( @OriginalText varchar(8000), @ReplaceWith varchar(1000) ) RETURNS @Texts TABLE ( Text varchar(2000) ) AS BEGIN << cursor start >> INSERT INTO @Texts VALUES(REPLACE(@OriginalText,@ReplaceWith,@Item)) << cursor end >> END /* EXAMPLE (List A,B,C) Text = 'Access provided for user x' with "SELECT * FROM dbo.xfProcreateInRow(Text,'x')" returns rows 'Access provided for user A' 'Access provided for user B' 'Access provided for user C' */
第1步 :使用名称TableType创build一个types为Table,该types将接受具有一个varchar列的表
create type TableType as table ([value] varchar(100) null)
第2步 :创build一个函数,将接受上面声明的TableType作为Table-Valued参数和string值作为分隔符
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
步骤3 :将带有一个varchar列的表传递给用户定义的typesTableType,将','作为函数中的分隔符
select dbo.fn_get_string_with_delimeter(@tab, ',')
要获得表格中的列数,请使用以下命令:
select count(id) from syscolumns where id = object_id('tablename')
并传递一个表到一个函数,试试XML如下所示:
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 */
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
以下将使您能够快速删除重复的空值,并只返回有效的列表。
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在SQL 2005中是有效的,然后你可以将这些值存储在一个临时表中,并在你的函数中使用它。
通过表作为参数在存储过程
步骤1:
CREATE TABLE [DBO] .T_EMPLOYEES_DETAILS(Id int,Name nvarchar(50),Gender nvarchar(10),Salary int)
第2步:
CREATE TYPE EmpInsertType AS TABLE(Id int,Name nvarchar(50),Gender nvarchar(10),Salary int)
第3步:
/ *必须在variables末尾添加READONLY关键字* /
CREATE PROC PRC_EmpInsertType @EmployeeInsertType EmpInsertType READONLY AS BEGIN INSERT INTO [DBO] .T_EMPLOYEES_DETAILS SELECT * FROM @EmployeeInsertType END
步骤4:
DECLARE @EmployeeInsertType EmpInsertType
INSERT INTO @EmployeeInsertType VALUES(1,'John','Male',50000)INSERT INTO @EmployeeInsertType VALUES(2,'Praveen','Male',60000)INSERT INTO @EmployeeInsertType VALUES(3,'Chitra','Female ',45000)INSERT INTO @EmployeeInsertType VALUES(4,'Mathy','Female',6600)INSERT INTO @EmployeeInsertType VALUES(5,'Sam','Male',50000)
EXEC PRC_EmpInsertType @EmployeeInsertType
=======================================
SELECT * FROM T_EMPLOYEES_DETAILS
OUTPUT
1约翰男50000
2 Praveen男60000
3 Chitra女45000
4 Mathy女6600
5 Sam男50000
你可以做这样的事情
/ * CREATE USER DEFINED TABLE TYPE * /
CREATE TYPE StateMaster AS TABLE ( StateCode VARCHAR(2), StateDescp VARCHAR(250) ) GO
/ *创buildfunction,以表作为参数* /
CREATE FUNCTION TableValuedParameterExample(@TmpTable StateMaster READONLY) RETURNS VARCHAR(250) AS BEGIN DECLARE @StateDescp VARCHAR(250) SELECT @StateDescp = StateDescp FROM @TmpTable RETURN @StateDescp END GO
/ *创build存储过程,以表格作为参数* /
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
有关更多详情,请查看此链接: http : //sailajareddy-technical.blogspot.in/2012/09/passing-table-valued-parameter-to.html