Reputation: 1604
Situation:
Each id is part of a group and of these id have their favorite game played.
Output structure:
+----+--------+-------+-------+-------+
| id | group | game1 | game2 | game3 |
+----+--------+-------+-------+-------+
| 1 | brazil | wow | clash | dofus |
| 1 | brazil | fifa | clash| dofus |
| 1 | brazil | wow | wakfu | dofus |
| 2 | korea | clash | dofus | clash |
| 2 | korea | clash | dofus | clash |
| 3 | france | wow | fifa | nfl |
| 3 | france | wow | fifa | nfl |
+----+--------+-------+-------+-------+
Objective:
I need to take the top 1 value for game1, game2, game3 by group. The top 1 would be the game that appears the most times in the column.
The result should like this:
+--------+--------+-------+-------+
| group | game1 | game2 | game3 |
+--------+--------+-------+-------+
| brazil | wow | clash | dofus |
| korea | clash | dofus | clash |
| france | wow | fifa | nfl |
+--------+--------+-------+-------+
Data:
create table #t1 (id int,[group] varchar(10),game1 varchar(10),game2 varchar(10),game3 varchar(10))
insert into #t1 values
(1, 'brazil','wow','clash','dofus'),
(1, 'brazil','fifa','clash','dofus'),
(1, 'brazil','wow','wakfu','dofus'),
(2, 'korea','clash','dofus','clash'),
(2, 'korea','clash','dofus','clash'),
(3, 'france','wow','fifa','nfl'),
(3, 'france','wow','fifa','nfl')
Upvotes: 1
Views: 113
Reputation: 479
First, if my opinion means anything, rename the column titled group. Though I assume you might have typed it like this for explanation, it might give you an error as it is reserved (or not, if brackets are used). If anything, it'd make it easier to read.
In other news, if you could use CTE's, I'd suggest the following:
;WITH Set1 AS
(
SELECT id, GameGroup, game1,
ROW_NUMBER() OVER (PARTITION BY [id] ORDER BY id ASC, count(game1) DESC) rn
FROM #t1
GROUP BY id, GameGroup, game1
),
Set2 AS
(
SELECT id, GameGroup, game2,
ROW_NUMBER() OVER (PARTITION BY [id] ORDER BY id ASC, count(game2) DESC) rn
FROM #t1
GROUP BY id, GameGroup, game2
),
Set3 AS
(
SELECT id, GameGroup, game3,
ROW_NUMBER() OVER (PARTITION BY [id] ORDER BY id ASC, count(game3) DESC) rn
FROM #t1
GROUP BY id, GameGroup, game3
)
SELECT a.GameGroup, a.game1, b.game2, c.game3
FROM Set1 a
INNER JOIN Set2 b
ON a.id = b. id AND a.rn = b.rn
INNER JOIN Set3 c
ON a.id = c.id AND a.rn = c.rn
WHERE a.rn = 1
Example listed here:
Upvotes: 0
Reputation: 1270993
I am going to suggest cross apply
:
select t.group, g1.game1, g2.game2, g3.game3
from (select distinct group
from #t1 t
) t cross apply
(select top (1) game1
from #t1 t
group by game1
order by count(*) desc
) g1 cross apply
(select top (1) game2
from #t1 t
group by game2
order by count(*) desc
) g2 cross apply
(select top (1) game3
from #t1 t
group by game3
order by count(*) desc
) g3;
Upvotes: 2
Reputation: 164194
With a CTE
that UNION
s all 3 columns to 1 column and then aggregate on it:
with cte as (
select
id, [group], gamecol, game,
row_number() over (partition by [group], gamecol order by count(*) desc) rn
from (
select id, [group], 'game1' gamecol, game1 game from #t1
union all
select id, [group], 'game2', game2 from #t1
union all
select id, [group], 'game3', game3 from #t1
) t
group by id, [group], gamecol, game
)
select
id, [group],
max(case when gamecol = 'game1' then game end) game1,
max(case when gamecol = 'game2' then game end) game2,
max(case when gamecol = 'game3' then game end) game3
from cte
where rn = 1
group by id, [group]
order by id
See the demo.
Results:
> id | group | game1 | game2 | game3
> -: | :----- | :---- | :---- | :----
> 1 | brazil | wow | clash | dofus
> 2 | korea | clash | dofus | clash
> 3 | france | wow | fifa | nfl
Upvotes: 1