4

I have a a table in my database where I store categories for newsarticles and each time a user reads an article it increments the value in the associated column. Like this:

enter image description here

Now I want to execute a query where I can get the column names with the 4 highest values for each record. For example for user 9, it would return this:

enter image description here

I've tried several things, searched a lot but don't know how to do it. Can anyone help me?

4
  • imgur is blocked where I work, can you put the text of your examples into the question? Commented May 24, 2012 at 17:53
  • @MartinSmith: I'm using MySQL. Commented May 24, 2012 at 18:09
  • 1
    @Kevin: sqlfiddle.com/#!2/ff624. Example returns userID:9 | highest value:Media | 2nd highest value:Wetenschap | 3rd highest value:Economie | 4th highest value:Sport Commented May 24, 2012 at 18:25
  • 2
    It sounds like this would work much better as a table with one record per user per category (i.e., the columns would be userid, category, articlecount). Then it would be easy to pull the 4 largest articlecount values for each user, and print the associated categories. Commented May 24, 2012 at 18:32

4 Answers 4

5

This should do it:

select
  userid,
  max(case when rank=1 then name end) as `highest value`,
  max(case when rank=2 then name end) as `2nd highest value`,
  max(case when rank=3 then name end) as `3rd highest value`,
  max(case when rank=4 then name end) as `4th highest value`
from
(
  select userID, @rownum := @rownum + 1 AS rank, name, amt from (
    select userID, Buitenland as amt, 'Buitenland' as name from newsarticles where userID = 9 union
    select userID, Economie, 'Economie' from newsarticles where userID = 9 union
    select userID, Sport, 'Sport' from newsarticles where userID = 9 union
    select userID, Cultuur, 'Cultuur' from newsarticles where userID = 9 union
    select userID, Wetenschap, 'Wetenschap' from newsarticles where userID = 9 union
    select userID, Media, 'Media' from newsarticles where userID = 9
  ) amounts, (SELECT @rownum := 0) r
  order by amt desc
  limit 4
) top4
group by userid

Demo: http://www.sqlfiddle.com/#!2/ff624/11

Sign up to request clarification or add additional context in comments.

2 Comments

I don't know what ":=" is shorthand for in SQL. Is this for MySQL or Oracle or something else?
the demo in fiddler does not load. please fix demo and syntax in the answer.
1

A very simple way of doing this is shown below

select userId, substring_index(four_highest,',',1) as 'highest value', substring_index(substring_index(four_highest,',',2),',',-1) as '2th highest value',  substring_index(substring_index(four_highest,',',3),',',-1) as '3 rd highest value',  substring_index(four_highest,',',-1) as '4th highest value'   from
(
select userid, convert(group_concat(val) using utf8) as four_highest from
(
select userId,Buitenland as val,'Buitenland' as col from test where userid=9 union
select userId,Economie as val,' Economie' as col from test where   userid=9 union
select userId,Sport as val ,'Sport' as col from test where  userid=9 union
select userId,Cultuur as val,'Cultuur' as col from test where userid=9 union
select userId,Wetenschap as val,'Wetenschap' as col from test where userid=9 union
select userId,Media as val,'Media' as col from test where  userid=9 order by val desc limit 4
) inner_query
)outer_query;

Comments

0

PL/SQL, maybe? Set user_id, query your table, store the returned row in an nx2 array of column names and values (where n is the number of columns) and sort the array based on the values.

Of course, the correct thing to do is redesign your database in the manner that @octern suggests.

Comments

0

This will get you started with the concept of grabbing the highest value from multiple columns on a single row (modify for your specific tables - I created a fake one).

create table fake 
(
  id int Primary Key,
  col1 int,
  col2 int,
  col3 int,
  col4 int 
)
insert into fake values (1, 5, 9, 27, 10)
insert into fake values (2, 3, 5, 1, 20)
insert into fake values (3, 89, 9, 27, 6)
insert into fake values (4, 17, 40, 1, 20)

SELECT *,(SELECT Max(v) 
FROM (VALUES (col1), (col2), (col3), (col4) ) AS value(v))
FROM fake

2 Comments

this gets the max value of multiple columns but does not answer question, what is the column name for the column with the highest (max) value.
I couldn't get this code to work in MySQL. The proper way to do it would be to use GREATEST, like this: SELECT *, GREATEST(col1, col2, col3, col4) AS v FROM fake; As already noted it only gets the highest value, not the name of the column with the highest value.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.