在早期版本上创建一个用户定义的函数,例如 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
谢谢大家=)
我尝试创建一个通用函数,可以像 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
谢谢大家=)