[英]Custom aggregate function (concat) in SQL Server
問題:我想編寫一個自定義聚合函數來連接 group by 上的字符串。
這樣我就可以做一個
SELECT SUM(FIELD1) as f1, MYCONCAT(FIELD2) as f2
FROM TABLE_XY
GROUP BY FIELD1, FIELD2
我發現的只是 SQL CRL 聚合函數,但我需要 SQL,沒有 CLR。
編輯:1
查詢應如下所示:
SELECT SUM(FIELD1) as f1, MYCONCAT(FIELD2) as f2
FROM TABLE_XY
GROUP BY FIELD0
編輯2:
確實,沒有 CLR 是不可能的。
但是,可以修改旁觀者的子選擇答案,因此它不會對特殊字符進行 XML 編碼。
對此的細微變化是在“FOR XML PATH”之后添加:
TYPE
).value('.[1]', 'nvarchar(MAX)')
這里有幾個例子
DECLARE @tT table([A] varchar(200), [B] varchar(200));
INSERT INTO @tT VALUES ('T_A', 'C_A');
INSERT INTO @tT VALUES ('T_A', 'C_B');
INSERT INTO @tT VALUES ('T_B', 'C_A');
INSERT INTO @tT VALUES ('T_C', 'C_A');
INSERT INTO @tT VALUES ('T_C', 'C_B');
INSERT INTO @tT VALUES ('T_C', 'C_C');
SELECT
A AS [A]
,
(
STUFF
(
(
SELECT DISTINCT
', ' + tempT.B AS wtf
FROM @tT AS tempT
WHERE (1=1)
--AND tempT.TT_Status = 1
AND tempT.A = myT.A
ORDER BY wtf
FOR XML PATH, TYPE
).value('.[1]', 'nvarchar(MAX)')
, 1, 2, ''
)
) AS [B]
FROM @tT AS myT
GROUP BY A
SELECT
(
SELECT
',äöü<>' + RM_NR AS [text()]
FROM T_Room
WHERE RM_Status = 1
ORDER BY RM_NR
FOR XML PATH('')
) AS XmlEncodedNoNothing
,
SUBSTRING
(
(
SELECT
',äöü<>' + RM_NR AS [data()]
FROM T_Room
WHERE RM_Status = 1
ORDER BY RM_NR
FOR XML PATH('')
)
,2
,10000
) AS XmlEncodedSubstring
,
(
STUFF
(
(
SELECT ',äöü<>' + RM_NR + CHAR(10)
FROM T_Room
WHERE RM_Status = 1
ORDER BY RM_NR
FOR XML PATH, TYPE
).value('.[1]', 'nvarchar(MAX)')
, 1, 1, ''
)
) AS XmlDecodedStuffInsteadSubstring
您不能在 CLR 之外編寫自定義聚合。
您可以在純 T-SQL 中編寫的唯一類型的函數是標量和表值函數。
將CREATE AGGREGATE的頁面(僅列出 CLR 樣式選項)與CREATE FUNCTION 的頁面(顯示 T-SQL 和 CLR 選項)進行比較。
看看類似的東西。 這不是聚合函數。 如果您希望實現自己的聚合函數,則必須是 CLR ...
DECLARE @Table TABLE(
ID INT,
Val VARCHAR(50)
)
INSERT INTO @Table (ID,Val) SELECT 1, 'A'
INSERT INTO @Table (ID,Val) SELECT 1, 'B'
INSERT INTO @Table (ID,Val) SELECT 1, 'C'
INSERT INTO @Table (ID,Val) SELECT 2, 'B'
INSERT INTO @Table (ID,Val) SELECT 2, 'C'
--Concat
SELECT t.ID,
SUM(t.ID),
stuff(
(
select ',' + t1.Val
from @Table t1
where t1.ID = t.ID
order by t1.Val
for xml path('')
),1,1,'') Concats
FROM @Table t
GROUP BY t.ID
從 2017 年開始,有內置的連接聚合函數 STRING_AGG :)
https://docs.microsoft.com/en-us/sql/t-sql/functions/string-agg-transact-sql?view=sql-server-2017
此解決方案無需從 Visual Studio 或服務器中的 dll 文件進行部署。
復制粘貼和它的工作!
https://github.com/orlando-colamatteo/ms-sql-server-group-concat-sqlclr
dbo.GROUP_CONCAT(VALUE )
dbo.GROUP_CONCAT_D(VALUE ), DELIMITER )
dbo.GROUP_CONCAT_DS(VALUE , DELIMITER , SORT_ORDER )
dbo.GROUP_CONCAT_S(VALUE , SORT_ORDER )
找到了這個關於連接的鏈接,它涵蓋了類似的方法
當項目數未知時連接值
不可靠的方法
雖然它不包括 aggerate 函數,但在那里可能會使用一些連接來幫助您解決問題。
您可以像我在下面所做的那樣在純 T-SQL 中創建自定義聚合連接函數。 顯然,我使用了硬編碼的表名和按列分組,但它應該說明了該方法。 可能有一些方法可以使用從輸入參數構造的動態 TSQL 使其成為真正的通用函數。
/*
User defined function to help perform concatenations as an aggregate function
Based on AdventureWorks2008R2 SalesOrderDetail table
*/
--select * from sales.SalesOrderDetail
IF EXISTS (SELECT *
FROM sysobjects
WHERE name = N'fnConcatenate')
DROP FUNCTION fnConcatenate
GO
CREATE FUNCTION fnConcatenate
(
@GroupByValue int
)
returnS varchar(8000)
as
BEGIN
DECLARE @SqlString varchar(8000)
Declare @TempStore varchar(25)
select @SqlString =''
Declare @MyCursor as Cursor
SET @MyCursor = CURSOR FAST_FORWARD
FOR
Select ProductID
From sales.SalesOrderDetail where SalesOrderID = @GroupByValue
order by SalesOrderDetailID asc
OPEN @MyCursor
FETCH NEXT FROM @MyCursor
INTO @TempStore
WHILE @@FETCH_STATUS = 0
BEGIN
select @SqlString = ltrim(rtrim(@TempStore )) +',' + ltrim(rtrim(@SqlString))
FETCH NEXT FROM @MyCursor INTO @TempStore
END
CLOSE @MyCursor
DEALLOCATE @MyCursor
RETURN @SqlString
END
GO
select SalesOrderID, Sum(OrderQty), COUNT(*) as DetailCount , dbo.fnConcatenate(salesOrderID) as ConCatenatedProductList
from sales.SalesOrderDetail
where salesOrderID= 56805
group by SalesOrderID
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.