Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom aggregate function (concat) in SQL Server

Question: I want to write a custom aggregate function that concatenates string on group by.

So that I can do a

SELECT SUM(FIELD1) as f1, MYCONCAT(FIELD2)  as f2 FROM TABLE_XY GROUP BY FIELD1, FIELD2 

All I find is SQL CRL aggregate functions, but I need SQL, without CLR.



Edit:1
The query should look like this:

   SELECT SUM(FIELD1) as f1, MYCONCAT(FIELD2)  as f2     FROM TABLE_XY     GROUP BY FIELD0 



Edit 2:
It is true that it isn't possible without CLR.
However, the subselect answer by astander can be modified so it doesn't XML-encode special characters.

The subtle change for this is to add this after "FOR XML PATH": ,

 TYPE                    ).value('.[1]', 'nvarchar(MAX)')  

Here a few examples

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    
like image 880
Stefan Steiger Avatar asked Dec 07 '10 08:12

Stefan Steiger


People also ask

Is concat an aggregate function in SQL?

The GROUP_CONCAT() function in MySQL is used to concatenate data from multiple rows into one field. This is an aggregate (GROUP BY) function which returns a String value, if the group contains at least one non-NULL value. Otherwise, it returns NULL.

What is the use of STRING_AGG in SQL Server?

STRING_AGG is an aggregate function that takes all expressions from rows and concatenates them into a single string. Expression values are implicitly converted to string types and then concatenated. The implicit conversion to strings follows the existing rules for data type conversions.

Can we use aggregate function on varchar in SQL?

The STRING_AGG() is an aggregate function that concatenates rows of strings into a single string, separated by a specified separator. It does not add the separator at the end of the result string. In this syntax: input_string is any type that can be converted VARCHAR and NVARCHAR when concatenation.


2 Answers

You cannot write custom aggregates outside of the CLR.

The only type of functions you can write in pure T-SQL are scalar and table valued functions.

Compare the pages for CREATE AGGREGATE, which only lists CLR style options, with CREATE FUNCTION, which shows T-SQL and CLR options.

like image 98
Damien_The_Unbeliever Avatar answered Oct 13 '22 12:10

Damien_The_Unbeliever


Have a look at something like. This is not an aggregate function. If you wish to implement your own aggregate function, it will have to be 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 
like image 42
Adriaan Stander Avatar answered Oct 13 '22 13:10

Adriaan Stander