I am trying to get from this
tPeople
Name
Alice
Bob
tAnimals
Name Animal
Alice Cat
Alice Cat
Bob Horse
Bob Dog
To this
Alice "Cat*2"
Bob "Horse, Dog"
So far I have an intermediate table grouping and counting animals
tGrouped Name Animal Tally
Alice Cat 2
Bob Dog 1
Bob Horse 1
And if I run
SELECT Name, Animals=STUFF((
SELECT N', '+animal+'*'+tally FROM tgrouped as g
WHERE g.Name = p.Name
FOR XML PATH(''), TYPE).value(N'.[1]', N'varchar(max)'), 1, 2, N'')
FROM tpeople as p
I get
Name Animals
Alice Cat*2
Bob Dog*1, Horse*1
Is there any way to skip the intermediate table? And any way to not show the tally when it is 1?
You don't need an intermediate table. You can just do the calculation in the query. For the second you can just adjust your logic:
WITH grouped as (
SELECT a.name, a.animal, COUNT(*) as cnt
FROM tAnimals a
GROUP BY a.name, a.animal
)
SELECT Name,
STUFF((SELECT (CASE WHEN cnt = 1 THEN N', ' + animal
ELSE CONCAT(N', ', animal, '*', cnt)
END)
FROM grouped g
WHERE p.Name = g.Name
FOR XML PATH(''), TYPE
).value(N'.[1]', N'varchar(max)'
), 1, 2, N''
) as animals
FROM tpeople p;
Similar approach to Gordon, but without the CTE:
CREATE TABLE dbo.tPeople ([Name] nvarchar(10));
CREATE TABLE dbo.tAnimal ([Name] nvarchar(10),
Animal varchar(10));
INSERT INTO dbo.tPeople ([Name])
VALUES('Alice'),('Bob');
INSERT INTO dbo.tAnimal ([Name],
Animal)
VALUES('Alice','Cat'),
('Alice','Cat'),
('Bob', 'Dog'),
('Bob', 'Horse');
GO
SELECT P.[Name] + ' "' +
STUFF((SELECT ', ' + CONCAT(A.Animal, '*' + CONVERT(varchar(3),NULLIF(COUNT(A.Animal),1)))
FROM dbo.tAnimal A
WHERE A.[Name] = P.[Name]
GROUP BY A.Animal
FOR XML PATH(''),TYPE).value('.','varchar(MAX)'),1,2,'') + '"'
FROM dbo.tPeople P;
GO
DROP TABLE dbo.tPeople;
DROP TABLE dbo.tAnimal;
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.