0

I have below table like: SQL Fiddle

I am able to get this output via FOR XML, but I am not sure how I can get below output properly for larger number of users (approx 0.2M users).

Later I want to get top-3 Names by their counts for each id, so RANK or OrderBy clauses will come into SQL and not sure how many iteration will it take when data is of large no. users.

enter image description here

Screenshot of table after group by:

enter image description here

Required output:

enter image description here

Working code that I have tried:

-----------SQL Raw Table Creation------------------------
CREATE TABLE tb
(
    Id INT,
    Name VARCHAR(50) NOT NULL
);

INSERT INTO tb (Id, Name) VALUES (1,  'aa');
INSERT INTO tb (Id, Name) VALUES (1,  'aa');
INSERT INTO tb (Id, Name) VALUES (1,  'aa');
INSERT INTO tb (Id, Name) VALUES (1,  'aa');
INSERT INTO tb (Id, Name) VALUES (1,  'aa');
INSERT INTO tb (Id, Name) VALUES (1,  'bb');
INSERT INTO tb (Id, Name) VALUES (1,  'cc');
INSERT INTO tb (Id, Name) VALUES (1,  'cc');
INSERT INTO tb (Id, Name) VALUES (1,  'dd');
INSERT INTO tb (Id, Name) VALUES (1,  'dd');
INSERT INTO tb (Id, Name) VALUES (1,  'dd');

INSERT INTO tb (Id, Name) VALUES (2,  'aa');
INSERT INTO tb (Id, Name) VALUES (2,  'bb');
INSERT INTO tb (Id, Name) VALUES (2,  'bb');
INSERT INTO tb (Id, Name) VALUES (2,  'ee');
INSERT INTO tb (Id, Name) VALUES (2,  'ee');
INSERT INTO tb (Id, Name) VALUES (2,  'ee');
INSERT INTO tb (Id, Name) VALUES (2,  'ee');

INSERT INTO tb (Id, Name) VALUES (3,  'aa');
INSERT INTO tb (Id, Name) VALUES (3,  'bb');
INSERT INTO tb (Id, Name) VALUES (3,  'cc');
INSERT INTO tb (Id, Name) VALUES (3,  'dd');
INSERT INTO tb (Id, Name) VALUES (3,  'dd');
INSERT INTO tb (Id, Name) VALUES (3,  'dd');




-----------------Want to RANK or get only top 3 rows for each Id when group by Name--------------
select f.* into #t1
from(
    select f.* 
    from(
        select f.* 
        from (
        
        select top 3 id,name,count(name) as total 
        from tb 
        where id = 1
        group by id,name 
        order by id,total desc
        )f
        Union 
    
        select top 3 id,name,count(name) as total 
        from tb 
        where id = 2
        group by id,name 
        order by id,total desc
    )f
    Union 

    select top 3 id,name,count(name) as total 
    from tb 
    where id = 3
    group by id,name 
    order by id,total desc

    ) f

/* Output is moved in temp table #t1 which looks like 
id  name    total
1   aa  5
1   cc  2
1   dd  3
2   aa  1
2   bb  2
2   ee  4
3   bb  1
3   cc  1
3   dd  3 
 */

---------Final Joining for each Top3Names and RespectiveTotal -----

select a.id as ID, a.listStr as Top3Names , b.Total as RespectiveTotal
from
    (
    SELECT  id,STUFF((SELECT  ',' + name
                FROM #t1 EE
                WHERE  EE.id=E.id
           FOR XML PATH('')), 1, 1, '') AS listStr
    FROM  #t1 E
    GROUP BY E.id
    )a
    left Join
    (
    SELECT  id,STUFF((SELECT  ',' + cast(total as Varchar)
                FROM #t1 EE
                WHERE  EE.id=E.id
           FOR XML PATH('')), 1, 1, '') AS Total
    FROM  #t1 E
    GROUP BY E.id
    )b 
    on a.id=b.id

Output:

ID  Top3Names   RespectiveTotal
1   aa,cc,dd    5,2,3
2   aa,bb,ee    1,2,4
3   bb,cc,dd    1,1,3

Also let me know any easy solution or alternatives so that I can test it on larger.

halfer
  • 19,824
  • 17
  • 99
  • 186
Shivkumar kondi
  • 6,458
  • 9
  • 31
  • 58
  • So what have you tried, why didn't it work? – Thom A Nov 20 '20 at 09:21
  • Does this answer your question? [Comma separated results in SQL](https://stackoverflow.com/q/18870326/2029983), [string_agg for sql server pre 2017](https://stackoverflow.com/q/49361088/2029983) – Thom A Nov 20 '20 at 09:22
  • Hi @Larnu, First Screenshot shows that I can use For XML for two columns. My issue that I have 3-columns were first I need to do the RANKing stuff and then FORXML twice for remaining 2-columns. So I can do this in multiple steps ..looking for an easy way from here – Shivkumar kondi Nov 20 '20 at 09:29
  • `STRING)AGG` is the "easy" way, which is on SQL Server 2017+. Otherwise `FOR XML PATH`, as the duplicates show. – Thom A Nov 20 '20 at 09:33

0 Answers0