I have the following database
id rank1 rank2 rank3 rank4
1 5 4 8 9
2 5 8 9 4
3 8 5 3 1
4 5 8 2 1
5 8 5 3 1
6 5 8 3 1
i need a mysql query or php script that will tally up the ranks and display the top 4 based on the number of times it appears in the table... ie. the end result should look something like:
rank1 = 5
rank2 = 8
rank3 = 3
rank4 = 1
any ideas??? thanks in advance
Your table design is far from optimal, if you didn't think it was before you will definitely see it after realizing that the way to get the result you are after requires this " not that pretty " query, though it works.
SELECT name, rank FROM (
(
SELECT 'rank1' name, rank1 rank
FROM foobar GROUP BY rank1
ORDER BY count(*) DESC LIMIT 1
) rank1_foobar
)
UNION SELECT name, rank FROM (
(
SELECT 'rank2' name, rank2 rank
FROM foobar GROUP BY rank2
ORDER BY count(*) DESC LIMIT 1
) rank2_foobar
)
UNION SELECT name, rank FROM (
(
SELECT 'rank3' name, rank3 rank
FROM foobar GROUP BY rank3
ORDER BY count(*) DESC LIMIT 1
) rank3_foobar
)
UNION SELECT name, rank FROM (
(
SELECT 'rank4' name, rank4 rank
FROM foobar GROUP BY rank4
ORDER BY count(*) DESC LIMIT 1
) rank4_foobar
)
output
+-------+------+
| name | rank |
+-------+------+
| rank1 | 5 |
| rank2 | 8 |
| rank3 | 3 |
| rank4 | 1 |
+-------+------+
I would restructure your table into something as the below, that'd make it much easier to write queries as the one you've requested.
CREATE TABLE ranks (
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
group_id INT UNSIGNED NOT NULL COMMENT 'to be able to group more than one row in `ranks` together',
rank_type ENUM('rank1','rank2','rank3','rank4'),
rank_value INT,
PRIMARY KEY(`id`)
);
Because of the poor data normalization, its not quite as simple as a single select/from group by. You need to query each "Rank" column as part of a union, THEN roll that up. To keep the interim temp summations down, we can still pre-group the counts so you are not running ALL rows 4 times, but the pre-roll-ups 1 per rank in the respective group segment
select
PreAgg.Rank,
SUM( PreAgg.RankCount ) as TotalCount
from
( select
YT.Rank1 as Rank,
COUNT(*) as RankCount
from
YourTable YT
group by
YT.Rank1
UNION ALL
select
YT.Rank2 as Rank,
COUNT(*) as RankCount
from
YourTable YT
group by
YT.Rank2
UNION ALL
select
YT.Rank3 as Rank,
COUNT(*) as RankCount
from
YourTable YT
group by
YT.Rank3
UNION ALL
select
YT.Rank4 as Rank,
COUNT(*) as RankCount
from
YourTable YT
group by
YT.Rank4 ) PreAgg
GROUP BY
PreAgg.Rank,
SUM( PreAgg.RankCount ) DESC
As pointed out by Ajreal, and it would need more clarification to the structure... Is there a reason why you have 4 distinct columns that are all "Rank" instead of a more normalized table something like..
ID RankGroup Rank
1 1 5
2 1 5
3 1 8
4 1 5
5 1 8
6 1 5
7 2 4
7 2 8
7 2 5
7 2 8
7 2 5
7 2 8
etc for ranks 3 and 4
Then you could just get your counts per RANK regardless of the "group level" condition, or get best ranking per group in very simplified query.
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.