【问题标题】:How to write the T-SQL STRING_AGG function如何编写 T-SQL STRING_AGG 函数
【发布时间】:2018-12-22 05:16:12
【问题描述】:

我需要为我的 SQL Server 2014 主数据库编写一个STRING_AGG。它是 SQL Server 2017 和 Azure SQL 的内置函数。

我有一个应用程序在 Azure SQL 数据库中执行存储过程,其中一些使用 STRING_AGG。在我们的本地开发实例中,我们使用在旧版本 SQL Server 上运行的本地主机上的数据库。问题是,因为 SQL Server 2014 无权访问 STRING_AGG,我们为 Azure SQL 数据库编写的存储过程将无法在本地运行。

该函数的行为需要与 Azure SQL 版本相同,这样存储过程才能在两个数据库中工作而不会破坏本地版本。我无法重写 Azure 数据库中的存储过程,并且我无法在我的本地主机上升级版本。

我试图创建一个以sql_variant 类型作为参数的函数,在谷歌搜索后,这与any 类型非常接近,但我可能不正确。我认为我的函数很接近,但它只返回我传入的结果集。该函数需要通用工作,因此它不知道传入结果集的表。幸运的是,我们从不使用@987654328 @ 在多列的结果集上,这样可能会使事情变得更容易一些。到目前为止,这是我的尝试

CREATE FUNCTION dbo.my_STRING_AGG 
     (@expr sql_variant,
      @separator NVARCHAR(MAX)) 
RETURNS NVARCHAR(MAX)
AS
BEGIN
    RETURN
        STUFF((SELECT @separator + CONVERT(NVARCHAR(MAX), @expr)
               FOR XML PATH('')), 1, 1, '')
END

对于进一步的参考框架,这里是我如何在存储过程中使用STRING_AGG 的示例

SELECT 
    STRING_AGG(CAST(TaskCommentAuditId as VARCHAR(255)), ', ') 
FROM 
    TaskCommentAudit;

关于如何让我的功能正常工作或其他方法的建议?

谢谢!

【问题讨论】:

  • 您需要学习如何编写用户定义的聚合函数(参见docs.microsoft.com/en-us/sql/t-sql/statements/…)。它看起来不像你正在做的事情。网上可能有很多版本。
  • 读到这里好像我必须用 C# 编写它并将它编译成一个 dll?那么在 T-SQL 中没有办法做到这一点吗?
  • 看起来你想要这个,不是吗?:stackoverflow.com/q/17591490/6167855
  • @scsimon,不,这是针对特定表的,我需要一个适用于任何通用结果集的函数,例如 string_agg 函数

标签: sql sql-server tsql azure-sql-database sql-server-2014


【解决方案1】:

在您的数据库中设置以下外部函数

    /*
GROUP_CONCAT string aggregate for SQL Server - https://groupconcat.codeplex.com
Copyright (C) 2011  Orlando Colamatteo

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or 
any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

See http://www.gnu.org/licenses/ for a copy of the GNU General Public 
License.
*/

/*
Installation script for GROUP_CONCAT functions. Tested in SSMS 2008R2.
*/
SET NOCOUNT ON ;
GO

-- !! MODIFY TO SUIT YOUR TEST ENVIRONMENT !!
USE GroupConcatTest
GO

-------------------------------------------------------------------------------------------------------------------------------
 =-- Turn advanced options on
EXEC sys.sp_configure @configname = 'show advanced options', @configvalue = 1 ;
GO
RECONFIGURE WITH OVERRIDE ;
GO
 =-- Enable CLR
EXEC sys.sp_configure @configname = 'clr enabled', @configvalue = 1 ;
GO
RECONFIGURE WITH OVERRIDE ;
GO
-------------------------------------------------------------------------------------------------------------------------------
SET ANSI_NULLS, ANSI_PADDING, ANSI_WARNINGS, ARITHABORT, QUOTED_IDENTIFIER ON;
SET CONCAT_NULL_YIELDS_NULL, NUMERIC_ROUNDABORT OFF;
GO
IF EXISTS (SELECT * FROM tempdb..sysobjects WHERE id=OBJECT_ID('tempdb..#tmpErrors')) DROP TABLE #tmpErrors
GO
CREATE TABLE #tmpErrors (Error int)
GO
SET XACT_ABORT ON
GO
SET TRANSACTION ISOLATION LEVEL READ COMMITTED
GO
BEGIN TRANSACTION
GO
-------------------------------------------------------------------------------------------------------------------
PRINT N'Creating [GroupConcat]...';
GO
CREATE ASSEMBLY [GroupConcat]
    AUTHORIZATION [dbo]

    WITH PERMISSION_SET = SAFE;
GO
IF @@ERROR <> 0
   AND @@TRANCOUNT > 0
    BEGIN
        ROLLBACK;
    END
IF @@TRANCOUNT = 0
    BEGIN
        INSERT  INTO #tmpErrors (Error)
        VALUES                 (1);
        BEGIN TRANSACTION;
    END
GO
EXEC sys.sp_addextendedproperty 
    @name = N'URL',
    @value = N'http://groupconcat.codeplex.com',
    @level0type = N'ASSEMBLY',
    @level0name = N'GroupConcat'
GO
-------------------------------------------------------------------------------------------------------------------
PRINT N'Creating [dbo].[GROUP_CONCAT_D]...';
GO
CREATE AGGREGATE [dbo].[GROUP_CONCAT_D](@VALUE NVARCHAR (4000), @DELIMITER NVARCHAR (4))
    RETURNS NVARCHAR (MAX)
    EXTERNAL NAME [GroupConcat].[GroupConcat.GROUP_CONCAT_D];
GO
IF @@ERROR <> 0
   AND @@TRANCOUNT > 0
    BEGIN
        ROLLBACK;
    END
IF @@TRANCOUNT = 0
    BEGIN
        INSERT  INTO #tmpErrors (Error)
        VALUES                 (1);
        BEGIN TRANSACTION;
    END
GO
-------------------------------------------------------------------------------------------------------------------
PRINT N'Creating [dbo].[GROUP_CONCAT_S]...';
GO
CREATE AGGREGATE [dbo].[GROUP_CONCAT_S](@VALUE NVARCHAR (4000), @SORT_ORDER TINYINT)
    RETURNS NVARCHAR (MAX)
    EXTERNAL NAME [GroupConcat].[GroupConcat.GROUP_CONCAT_S];
GO
IF @@ERROR <> 0
   AND @@TRANCOUNT > 0
    BEGIN
        ROLLBACK;
    END
IF @@TRANCOUNT = 0
    BEGIN
        INSERT  INTO #tmpErrors (Error)
        VALUES                 (1);
        BEGIN TRANSACTION;
    END
GO
-------------------------------------------------------------------------------------------------------------------
PRINT N'Creating [dbo].[GROUP_CONCAT_DS]...';
GO
CREATE AGGREGATE [dbo].[GROUP_CONCAT_DS](@VALUE NVARCHAR (4000), @DELIMITER NVARCHAR (4), @SORT_ORDER TINYINT)
    RETURNS NVARCHAR (MAX)
    EXTERNAL NAME [GroupConcat].[GroupConcat.GROUP_CONCAT_DS];
GO
IF @@ERROR <> 0
   AND @@TRANCOUNT > 0
    BEGIN
        ROLLBACK;
    END
IF @@TRANCOUNT = 0
    BEGIN
        INSERT  INTO #tmpErrors (Error)
        VALUES                 (1);
        BEGIN TRANSACTION;
    END
GO
-------------------------------------------------------------------------------------------------------------------
PRINT N'Creating [dbo].[GROUP_CONCAT]...';
GO
CREATE AGGREGATE [dbo].[GROUP_CONCAT](@VALUE NVARCHAR (4000))
    RETURNS NVARCHAR (MAX)
    EXTERNAL NAME [GroupConcat].[GroupConcat.GROUP_CONCAT];
GO
IF @@ERROR <> 0
   AND @@TRANCOUNT > 0
    BEGIN
        ROLLBACK;
    END
IF @@TRANCOUNT = 0
    BEGIN
        INSERT  INTO #tmpErrors (Error)
        VALUES                 (1);
        BEGIN TRANSACTION;
    END
GO
-------------------------------------------------------------------------------------------------------------------
IF EXISTS (SELECT * FROM #tmpErrors) ROLLBACK TRANSACTION
GO
IF @@TRANCOUNT>0 BEGIN
PRINT N'The transacted portion of the database update succeeded.'
COMMIT TRANSACTION
END
ELSE PRINT N'The transacted portion of the database update failed.'
GO
DROP TABLE #tmpErrors
-------------------------------------------------------------------------------------------------------------------
GO

source

然后你可以在表单上使用它们

**select BlogId, dbo.GROUP_CONCAT(Title) from Posts 
group by BlogId** 

鲁塞尔

BlogId  (No column name)
1   Title 1,Title 2,Title 3,Title 11,Title 12,Title 13,Title 14,Title 
2   Title 29,Title 21,Title 10,Title 17,Title 15
3   Title 18,Title 5,Title 8,Title 28
4   Title 7,Title 19

需要在服务器上运行 CLR 因此,当数据库恢复到新服务器时,必须运行 CLR

-- Turn advanced options on
EXEC sys.sp_configure @configname = 'show advanced options', @configvalue = 1 ;
GO
RECONFIGURE WITH OVERRIDE ;
GO
-- Enable CLR
EXEC sys.sp_configure @configname = 'clr enabled', @configvalue = 1 ;
GO
RECONFIGURE WITH OVERRIDE ;
GO

【讨论】:

猜你喜欢
  • 2021-12-14
  • 1970-01-01
  • 2020-01-12
  • 2010-12-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-15
  • 2013-07-29
相关资源
最近更新 更多