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

Posted

技术标签:

【中文标题】如何在 SQL Server 中创建一个接受一列数据的函数?【英文标题】:How do I make a function in SQL Server that accepts a column of data? 【发布时间】:2010-05-07 13:22:08 【问题描述】:

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

我并不精通定义 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

如您所见,我在函数中选择列数据,然后使用光标循环遍历结果以构建逗号分隔的 varchar。

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

【问题讨论】:

【参考方案1】:

其他人已经回答了您的主要问题 - 但让我指出您的功能的另一个问题 - 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,没有混乱的连接和所有粘糊糊的代码——只有一个语句,就是这样。

【讨论】:

【参考方案2】:

您可以使用表值参数:

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

【讨论】:

【参考方案3】:

从 SQL Server 2008 开始,您可以使用 Table Valued Parameters,这将允许您将 TABLE 变量作为参数传递。这方面的限制和示例都在链接的文章中。

不过,我还要指出,使用游标很可能会影响性能。 您不需要使用游标,因为您可以在 1 条 SELECT 语句中完成所有操作:

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

不需要光标

【讨论】:

+1 无光标!!!!请记住,有时您需要循环,但您永远不需要光标来循环:***.com/questions/2622230/… ***.com/questions/935336/… 只需替换光标并继续使用这些技术进行循环,您通常会看到性能提升。 感谢 Ada 的无光标解决方案。我曾希望有一种没有游标的方法,但不知道我可以以这种方式使用变量。但是,就性能而言(我在这里看到很多关于性能的抱怨!)我的基于光标的函数的运行速度几乎比您建议的解决方案快 5 倍。我不知道为什么会这样,但是我可以在大约 2 秒内使用每行 4 个函数调用(处理 150,000 个详细记录)提取 6,000 个“标题”记录,但是 SELECT @Var = COALESCE(@Var,'' ) + 数据耗时超过 10。我将继续测试这两种方法,感谢链接!【参考方案4】:

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

在不完全了解您的目标的情况下,您可以考虑将参数更改为表变量。填充调用代码本地的表变量并将其传递给函数。不过,您可以将其作为存储过程执行,并且不需要函数。

【讨论】:

以上是关于如何在 SQL Server 中创建一个接受一列数据的函数?的主要内容,如果未能解决你的问题,请参考以下文章

在特定数据库中创建 SQL Server 视图 [重复]

如何在 SQL Server 中创建“脚本生成器选项”脚本?

如何在 SQL Server 2008 中创建具有新名称的重复表

如何使用 SQL Server Management Studio (2008) 在 SQL Server Compact Edition 中创建列

如何在 SQL Server 中创建维护计划?

如何在 SQL Server 2008 表中创建计算列