I have below table and string aggregation using XML:
CREATE TABLE TestTable ([ID] INT, [Name] CHAR(1))
INSERT INTO TestTable ([ID],[Name]) VALUES (1,'A')
INSERT INTO TestTable ([ID],[Name]) VALUES (2,'B')
INSERT INTO TestTable ([ID],[Name]) VALUES (3,'C')
INSERT INTO TestTable ([ID],[Name]) VALUES (1,'D')
INSERT INTO TestTable ([ID],[Name]) VALUES (1,'E')
INSERT INTO TestTable ([ID],[Name]) VALUES (2,'F')
INSERT INTO TestTable ([ID],[Name]) VALUES (3,'G')
INSERT INTO TestTable ([ID],[Name]) VALUES (4,'H')
SELECT
[ID],
STUFF((
SELECT ' ' + [Name]
FROM TestTable
WHERE (ID = Results.ID)
FOR XML PATH(''),TYPE).value('(./text())[1]','VARCHAR(MAX)')
,1,2,'') AS Names
FROM TestTable Results
GROUP BY ID
I get below result
ID Names
1 A D E
2 B F
3 C G
4 H
However i have requirement to limit number of Names to two, if its more than two, it should split to next row, Something like below. Here for ID=1, there were 3 Names, so 3rd name split into next row. How can i achieve this requirement
ID Names
1 A D
1 E
2 B F
3 C G
4 H
Thanks
It sounds like you want conditional aggregation, with up to two name
columns per row. You can do this using row_number()
and some arithmetic:
select id,
max(case when seqnum % 2 = 1 then name end) as name1,
max(case when seqnum % 2 = 0 then name end) as name2
from (select t.*,
row_number() over (partition by id order by name) as seqnum
from testtable t
) t
group by id, ceiling(seqnum / 2.0)
order by id, min(seqnum);
Here is a db<>fiddle.
I should note that you can concatenate these into a single column. I don't see a reason to do so, because you know the maximum number on each row.