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

发布于 2024-08-31 20:57:16 字数 1169 浏览 2 评论 0原文

本周早些时候,我在 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。

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

I made the following function in SQL Server 2008 earlier this week that takes two parameters and uses them to select a column of "detail" records and returns them as a single varchar list of comma separated values. Now that I get to thinking about it, I would like to take this table and application-specific function and make it more generic.

I am not well-versed in defining SQL functions, as this is my first. How can I change this function to accept a single "column" worth of data, so that I can use it in a more generic way?

Instead of calling:

SELECT ejc_concatFormDetails(formuid, categoryName)

I would like to make it work like:

SELECT concatColumnValues(SELECT someColumn FROM SomeTable)

Here is my function definition:

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

As you can see, I am selecting the column data within my function and then looping over the results with a cursor to build my comma separated varchar.

How can I alter this to accept a single parameter that is a result set and then access that result set with a cursor?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

爱殇璃 2024-09-07 20:57:16

其他人已经回答了您的主要问题 - 但让我指出您的函数的另一个问题 - 游标的糟糕使用!

您可以轻松重写此函数以不使用游标、不使用 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('') - 这会返回 数据的串联列表 列和固定的 ', ' 分隔符。添加一个 SUBSTRING() 就完成了!就这么简单......没有顽固缓慢的 CURSOR,没有混乱的串联和所有那些粘糊糊的代码 - 只需一个语句即可。

Others have answered your main question - but let me point out another problem with your function - the terrible use of a CURSOR!

You can easily rewrite this function to use no cursor, no WHILE loop - nothing like that. It'll be tons faster, and a lot easier, too - much less code:

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)

The trick is to use the FOR XML PATH('') - this returns a concatenated list of your data columns and your fixed ', ' delimiters. Add a SUBSTRING() on that and you're done! As easy as that..... no dogged-slow CURSOR, no messie concatenation and all that gooey code - just one statement and that's all there is.

萌能量女王 2024-09-07 20:57:16

您可以使用表值参数:

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

You can use table-valued parameters:

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
挽手叙旧 2024-09-07 20:57:16

从 SQL Server 2008 开始,您可以使用表值参数,这将允许您将 TABLE 变量作为参数传递。相关限制和示例都在该链接的文章中。

然而,我还要指出,使用游标很可能会降低性能。
您不需要使用游标,因为您可以在 1 个 SELECT 语句中完成所有操作:

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

不需要游标

You can use Table Valued Parameters as of SQL Server 2008, which would allow you to pass a TABLE variable in as a parameter. The limitations and examples for this are all in that linked article.

However, I'd also point out that using a cursor could well be painful for performance.
You don't need to use a cursor, as you can do it all in 1 SELECT statement:

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

No need for a cursor

白况 2024-09-07 20:57:16

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

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

Your question is a bit unclear. In your first SQL statement it looks like you're trying to pass columns to the function, but there is no WHERE clause. In the second SQL statement you're passing a collection of rows (results from a SELECT). Can you supply some sample data and expected outcome?

Without fully understanding your goal, you could look into changing the parameter to be a table variable. Fill a table variable local to the calling code and pass that into the function. You could do that as a stored procedure though and wouldn't need a function.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文