在早期版本上创建一个用户定义的函数,例如 SQL server 2017 STRING_AGG

Create a User defined function like SQL server 2017 STRING_AGG on earlier versions

我尝试创建一个通用函数,可以像 this example 使用 SQL Server 2017

上的新 string_agg 内置函数

内部实现可以像下面这样

with tbl as(
   select a.Id, c.Desc
     from TableA a
     join TableB b on b.aId = a.Id
     join TableC c on c.Code = b.bCode 
)  
select distinct ID
     , STUFF(( select ', ' + Desc from tbl t where t.ID = tbl.ID 
            for xml path(''),TYPE).value('.','VARCHAR(MAX)'),1,2,'') Desc   
from tbl

但是如何接收字段键、要连接的字段、分隔符字符和作用域select上下文? 与Inline or Multi-Statement Table-Valued Functions有关吗?

嗯,这是一个丑陋的 hack,我现在必须去洗手,但它有效(在某种程度上 :-D)

CREATE FUNCTION dbo.MyStringAgg(@SelectForXmlAuto XML,@Delimiter NVARCHAR(10))
RETURNS NVARCHAR(MAX)
AS
BEGIN
    RETURN STUFF((
             SELECT @Delimiter + A.nd.value(N'(@*)[1]',N'nvarchar(max)')
             FROM @SelectForXmlAuto.nodes(N'/*') AS A(nd)
             FOR XML PATH(''),TYPE
           ).value(N'.',N'nvarchar(max)'),1,LEN(@Delimiter),'');
END
GO

DECLARE @tbl TABLE(GroupId INT,SomeValue NVARCHAR(10));
INSERT INTO @tbl VALUES(1,'A1'),(1,'A2'),(2,'B1'),(3,'C1'),(3,'C2'),(3,'C3');

SELECT GroupId
      ,dbo.MyStringAgg((SELECT SomeValue 
                        FROM @tbl AS t2 
                        WHERE t2.GroupId=t.GroupId 
                        FOR XML AUTO), N', ')
FROM @tbl AS t
GROUP BY GroupId;
GO

DROP FUNCTION dbo.MyStringAgg;

结果

1    A1, A2
2    B1
3    C1, C2, C3

参数是括号内的FOR XML子select。这将隐式地将子 select 的结果作为 XML 传递给函数。

老实说:我自己不会用这个...

这样的查询

SELECT GroupId
      ,STUFF((SELECT N', ' + SomeValue 
              FROM @tbl AS t2 
              WHERE t2.GroupId=t.GroupId 
              FOR XML PATH,TYPE).value(N'.','nvarchar(max)'),1,2,'')
FROM @tbl AS t
GROUP BY GroupId;

产生相同的结果并且输入的次数几乎相同 - 但应该比调用慢速 UDF 更快...

好的..所以@MichałTurczyn 的第一条评论我 运行 到 this Microsoft 文章关于 CLR 用户定义的聚合 - 调用函数

将代码编译成 SrAggFunc.dll 后,我尝试按如下方式在 SQL 服务器中注册聚合:

CREATE ASSEMBLY [STR_AGG] FROM 'C:\tmp\STR_AGG.dll'; 
GO

但是我得到了以下错误。

Msg 6501, Level 16, State 7, Line 1
CREATE ASSEMBLY failed because it could not open the physical file 'C:\tmp\SrAggFunc.dll': 3(The system cannot find the path specified.).

所以我使用了@SanderRijken 代码的this 优秀部分,然后将命令更改为

CREATE ASSEMBLY [STR_AGG] 
FROM 0x4D5A90000300000004000000FF......000; --from GetHexString function
GO

然后,

CREATE AGGREGATE [STR_AGG] (@input nvarchar(200)) RETURNS nvarchar(max) 
EXTERNAL NAME [STR_AGG].C_STRING_AGG;`

大功告成。

您可以在数据库 -> SSMS 上的可编程性下看到它

并像这样使用:

SELECT a.Id, [dbo].[STR_AGG](c.Desc) cDesc
FROM TableA a
JOIN TableB b on b.aId = a.Id
JOIN TableC c on c.Code = b.bCode 
GROUP BY a.Id

谢谢大家=)