Say I have a table like ID, NAME, SCORE. Now normally, to get the rankings of the teams, I'd select all and order by. Sometimes though, I don't want to know all the rankings, just the ranking of one team. If I added a column RANK, is there any way for MySQL to automatically fill in those values for me based off of SCORE? (I believe MS Excel has this capability)
and if so, how does it handle ties?
thanks
You can calculate the rankings when you make your query:
SELECT * FROM (
SELECT teams.*, #rownum := #rownum + 1 AS rank
FROM teams, (SELECT #rownum := 0) T1
ORDER BY score DESC) T2
WHERE id = 1
It works by initializing a variable called rownum to 0 and then iterating over the rows in order of decreasing score. For each team the rownum is increased and the team is assigned a rank based on the current value of rownum. The outer select applies a where clause so that only one row is returned.
Here is an improved version that assigns the same rank to teams that have tied scores:
SELECT id, name, teams.score, rank FROM (
SELECT score, #rownum := #rownum + 1 AS rank
FROM (SELECT DISTINCT(score) FROM teams) T1, (SELECT #rownum := 0) T2
ORDER BY score DESC) T3
JOIN teams ON T3.score = teams.score
If this isn't fast enough for you, then use a trigger instead.
looks like I'm looking for a MySQL trigger
Get All Teams:
SELECT
s1.name,
s1.score,
COUNT(s2.name) + 1 AS rank
FROM scores s1
LEFT OUTER JOIN scores AS s2 ON (s1.score < s2.score)
GROUP BY s1.name
ORDER BY COUNT(s2.name)
Get One Team ('The Canucks'):
SELECT
s1.name,
s1.score,
COUNT(s2.name) + 1 AS rank
FROM scores s1
LEFT OUTER JOIN scores AS s2 ON (s1.score < s2.score)
GROUP BY s1.name
HAVING s1.name = 'The Canucks'
ORDER BY COUNT(s2.name)
The method shown in the above examples get the ranking dynamically (not filling a regular or temp table).
Note: both of these assume a given team only exists once in scores table for the rank value to be correct.
Related
I have a table called player_stage.
I am trying to prepare my data so I can put it into a data warehouse.
I currently have a unreliable work-around that involves a duplicates view and handpicking the values from the duplicates.
I need to create a query that gives duplicates the same surrogate key(sk).
Any idea how I can do this? I've been stuck on t
his for 3 days.
If you are using MySQL 8+, then DENSE_RANK can work here:
SELECT
PLAYER_ID,
PLAYER_NAME,
DB_SOURCE,
DENSE_RANK() OVER (ORDER BY PLAYER_NAME) SK
FROM yourTable;
The above call to DENSE_RANK would assign the same SK value to all records belonging to the same player name.
If you are using a version of MySQL earlier than 8+, then we can simulate the dense rank with user variables, e.g.
SELECT t1.PLAYER_ID, t1.PLAYER_NAME, t1.DB_SOURCE, t2.rn AS SK
FROM yourTable t1
INNER JOIN
(
SELECT PLAYER_NAME, #rn := #rn + 1 AS rn
FROM (SELECT DISTINCT PLAYER_NAME FROM yourTable) t, (SELECT #rn := 0) r
ORDER BY PLAYER_NAME
) t2
ON t1.PLAYER_NAME = t2.PLAYER_NAME
ORDER BY
t1.PLAYER_ID;
Demo
Which team has the most number of members on their roster?
Okay so below is the code that I have input currently. It returns all the teams as well as how many people are on each team. I am not sure how to code it to only display the team with the most members as when I try to use a max function and a count function I get an error.
SELECT Team_Name, COUNT(Member.Student_ID_Num)
FROM Teams
JOIN Member ON Teams.Team_Number = Member.Team_Number
GROUP BY Team_Name
you can try below - using limit and order by desc
Select Team_Name, count(Member.Student_ID_Num) as cnt
from Teams join Member on Teams.Team_Number = Member.Team_Number
group by Team_Name
order by cnt desc
limit 1
If you are using MySQL 8+, then the ROW_NUMBER function comes in handy here:
SELECT Team_Name, cnt
FROM
(
SELECT t.Team_Name, COUNT(*) AS cnt,
ROW_NUMBER() OVER (ORDER BY COUNT(*) DESC) rn
FROM Teams t
INNER JOIN Member m
ON t.Team_Number = m.Team_Number
GROUP BY t.Team_Name
) t
WHERE rn = 1;
If you instead want all ties for the highest count, should two or more teams be tied, then replace ROW_NUMBER with RANK.
If you have to do this the old fashioned way, without LIMIT or ROW_NUMBER, then get ready for a really ugly query:
SELECT
t.Team_Name,
COUNT(*) AS cnt
FROM Teams t
INNER JOIN Member m
ON t.Team_Number = m.Team_Number
GROUP BY t.Team_Name
HAVING COUNT(*) = (SELECT MAX(cnt) FROM (SELECT COUNT(*) AS cnt
FROM Teams t
INNER JOIN Member m
ON t.Team_Number = m.Team_Number
GROUP BY t.Team_Name) t );
In order to get the team with the highest member count, we need no join (unless we also want to show the member count). One thing to keep in mind that there may be multiple teams sharing the same maximum member count.
The old fashioned way in standard SQL, before there was any limit clause (FETCH FIRST ROWS in standard SQL) was this:
Count members per team number.
Get the maximum count.
Get the team number(s) with this maximum count.
Get the team(s) for these team numbers.
The query:
select *
from teams
where team_number in
(
select team_number
from member
group by team_number
having count(*) =
(
select max(cnt) as max_cnt
from
(
select count(*) as cnt
from member
group by team_number
) counted
)
);
As of MySQL 8 we would rather use a wnindow function, however:
select *
from teams
where (team_number, 1) in
(
select team_number, rank() over (order by count(*) desc)
from member
group by team_number
);
Let's say I have a table films(film, category).
I want to find the category with the most films. How do I do that without using LIMIT?
I suppose I could do something like this:
SELECT category
FROM
(SELECT category, COUNT(*) AS num
FROM films
GROUP BY category) AS T1
WHERE num =
(SELECT MAX(num)
FROM
(SELECT category, COUNT(*) AS num
FROM films
GROUP BY category) AS T2)
But is there a more elegant way of doing that? Preferably one where I don't have to write the same subquery multiple times?
Thanks!
(And if you're wondering why I can't use LIMIT, it's for homework)
you could do it using a variable to create a row number:
SELECT category
FROM
(
SELECT
category
COUNT(*) as NumOfFiles
,(#rn:= #rn + 1) as RowNumber
FROM
Films f
CROSS JOIN (SELECT #rn:=0) vars
GROUP BY
category
ORDER BY
COUNT(*) DESC
) t
WHERE
t.RowNumber = 1
Table A shows results that I have by running the following SQL in MySQL.
SELECT * FROM table
WHERE MATCH (title) AGAINST ('marka tv')
Table A
Table B shows results that I want to get. As you can see the groups are in round-robin order.
Table B
If I understand the question, you want to sort the output so the groups are in a round-robin fashion rather than ordered. You can do this by enumerating the values within each group and then using that information for sorting:
SELECT t.*
FROM (SELECT t.*,
(#rn := if(#g = groups, #rn + 1,
if(#g := groups, 1, 1)
)
) as rn
FROM table t CROSS JOIN
(SELECT #rn := 0, #g := '') params
WHERE MATCH (title) AGAINST ('marka tv')
ORDER BY groups
) t
ORDER BY rn, groups;
Consider a subquery in a derived table to calculate a group number to be sorted at final table:
SELECT f.*
FROM
(SELECT t1.* ,
(SELECT count(*)
FROM table t2
WHERE (t2.title <= t1.title)
AND (t1.groups = t2.groups)) AS groupNo
FROM table t1
WHERE MATCH (t1.title) AGAINST ('marka tv')
) AS f
ORDER BY groupNo, groups
The below query is working absolutely fine, as I need. All the user get unique RANKS (User of same points should not get same rank)
SELECT
id,
first_name,
email,
(SELECT
rank
FROM ( SELECT
#rownum:=#rownum+1 rank,
u.id AS user_id,
points
FROM
user_master u, (SELECT #rownum:=0) r
ORDER BY
points
DESC) AS tmp
WHERE
user_id = um.id) AS Rank,
registered_date AS registered,
um.points as Points
FROM
user_master um
ORDER BY
um.id ASC
Now I want to make view for this query, it gives me error message
View's SELECT contains a subquery in the FROM clause
I've also tried first to make a view of user ranks to merge 2 different views. The below query gives perfect rankings of user but when I try to make view of this:
SELECT
#rownum:=#rownum+1 rank,
id AS user_id,
points
FROM
user_master u, (SELECT #rownum:=0) r
ORDER BY
points
DESC
..it gives me error message:
View's SELECT contains a variable or parameter
Is there any other way to apply rank in this query (Rank must be unique even if points are same).
Give this a go:
create view test_view as SELECT t.id,t.first_name,t.email,
(select sum(case when t1.points > t.points then 1
when t1.points = t.points and t1.id < t.id then 1
else 0 end) from user_master t1)+1 as rank, t.registered_date AS registered,
t.points as Points
from user_master t
order by points desc;