如何在 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 2008 中创建具有新名称的重复表
如何使用 SQL Server Management Studio (2008) 在 SQL Server Compact Edition 中创建列