如何在SQL Server中接受一列数据的函数?

如何在SQL Server中接受一列数据的函数?

问题描述:

本周早些时候,我在SQL Server 2008中做了以下函数,它接受两个参数,并使用它们来选择一列“详细”记录并将它们作为单个逗号分隔值的varchar列表返回。现在我开始思考这个问题了,我想要使用这个表和特定于应用程序的功能,并使其更通用。如何在SQL Server中接受一列数据的函数?

我不是很精通定义SQL函数,因为这是我的第一个。我怎样才能改变这个函数来接受一个“列”值的数据,以便我可以以更通用的方式使用它?

,不再拨打电话:

SELECT ejc_concatFormDetails(formuid, categoryName) 

我想,使其工作,如:

SELECT concatColumnValues(SELECT someColumn FROM SomeTable) 

这里是我的函数的定义:

FUNCTION [DNet].[ejc_concatFormDetails](@formuid AS int, @category as VARCHAR(75)) 
RETURNS VARCHAR(1000) AS 
BEGIN 
DECLARE @returnData VARCHAR(1000) 
DECLARE @currentData VARCHAR(75) 
DECLARE dataCursor CURSOR FAST_FORWARD FOR 
    SELECT data FROM DNet.ejc_FormDetails WHERE formuid = @formuid AND category = @category 

SET @returnData = '' 

OPEN dataCursor 

FETCH NEXT FROM dataCursor INTO @currentData 
WHILE (@@FETCH_STATUS = 0) 
BEGIN 
    SET @returnData = @returnData + ', ' + @currentData 
    FETCH NEXT FROM dataCursor INTO @currentData 
END 

CLOSE dataCursor 
DEALLOCATE dataCursor 

RETURN SUBSTRING(@returnData,3,1000) 
END 

正如你所看到的,我我在我的函数中选择列数据,然后用游标遍历结果来构建我的逗号分隔的var焦炭。

我该如何改变它以接受作为结果集的单个参数,然后使用游标访问该结果集?

您可以使用表值参数:

CREATE FUNCTION MyFunction(
    @Data AS TABLE (
     Column1 int, 
     Column2 nvarchar(50), 
     Column3 datetime 
    ) 
) 
RETURNS NVARCHAR(MAX) 
AS BEGIN 
    /* here you can do what you want */ 
END 

您可以使用Table Valued Parameters作为SQL Server 2008中,这将允许你通过一个表变量作为参数。这个限制和例子都在这篇链接文章中。

但是,我还要指出,使用游标对性能可能会很痛苦。 你并不需要使用游标,因为你可以做到这一切在1个SELECT语句:

SELECT @MyCSVString = COALESCE(@MyCSVString + ', ', '') + data 
FROM DNet.ejc_FormDetails 
WHERE formuid = @formuid AND category = @category 

无需光标

+0

+1刚刚准备粘贴,你击败了我! – 2010-05-07 13:29:00

+0

+1为游标免费!!!!只要记住,你需要循环有时,但你永远不需要游标循环:http://*.com/questions/2622230/how-can-i-iterate-over-a-recordset-within-a-stored-过程/ 2622279#2622279 http://*.com/questions/935336/sql-server-cursor-reference-syntax-etc/935367#935367通过只更换光标,仍然使用这些技术循环,你通常会看到性能增益。 – 2010-05-07 13:34:48

+0

感谢无光标解决方案Ada。我希望有一种不使用游标的方法,并且不知道我可以用这种方式使用变量。然而,就性能而言(我在这里看到很多关于性能的呻吟!)基于光标的函数运行速度比您的建议解决方案快5倍。我不知道为什么会这样,但我可以在大约2秒内抽取6,000个“标题”记录和每行4个函数调用(处理150,000个详细记录),但SELECT @Var = COALESCE(@Var,'' )+数据需要超过10个。 我将继续测试这两种方法,感谢您的链接! – 2010-05-07 13:56:29

你的问题有点不清楚。在你的第一个SQL语句中,它看起来像是在尝试将列传递给函数,但是没有WHERE子句。在第二个SQL语句中,您传递了一个行集合(来自SELECT的结果)。你能提供一些样本数据和预期结果吗?

如果不完全理解您的目标,您可以考虑将参数更改为表变量。填写调用代码本地的表变量并将其传递给函数。尽管你可以做到这一点,但不需要函数。

其他人已经回答了您的主要问题 - 但让我指出您的功能的另一个问题 - 使用CURSOR的可怕!

你可以很容易重写此函数使用没有游标,没有WHILE循环 - 没有这样的。这将是吨更快,轻松了很多,太 - 更少的代码:

FUNCTION DNet.ejc_concatFormDetails 
      (@formuid AS int, @category as VARCHAR(75)) 
RETURNS VARCHAR(1000) 
AS 
    RETURN 
     SUBSTRING(
     (SELECT ', ' + data 
     FROM DNet.ejc_FormDetails 
     WHERE formuid = @formuid AND category = @category 
     FOR XML PATH('') 
     ), 3, 1000) 

诀窍是使用FOR XML PATH('') - 这将返回您的data列和你的固定', '分隔符的连续清单。添加SUBSTRING()就完成了!就像那样简单......没有顽皮的慢CURSOR,没有messie连接和所有那些粘性代码 - 只有一个声明,这就是全部。