I'd like to calculate a ordered-by rank for my rows. It isn't calculating correctly- I'm only getting a null and 1. I expect to get a rank of 1, 2, 3... based on my joins/order by ladder_name_lh2 = ladder_name_lh1 and date_trigger_event_lh2, and member_id_lh1.
Basically, I am trying to say
If ladder_name_2 matches ladder_name_1 (this is a before/after set up - ladder 2 comes after ladder 1, and there are 6 ladder names (categories), but in order to tell that they're related, I want to make sure that the rank is only being generated if the categories for before and after match) and then generate a rank based on date_2, member_id.
I've written the following:
select
cte_ladder_history_self_join_lh1.member_id_lh1,
cte_ladder_history_self_join_lh1.ladder_config_id_lh1,
cte_ladder_history_self_join_lh1.trigger_name_lh1,
cte_ladder_history_self_join_lh1.trigger_record_id_lh1,
cte_ladder_history_self_join_lh1.date_trigger_event_lh1,
cte_ladder_history_self_join_lh1.ladder_name_lh1,
cte_ladder_history_self_join_lh1.ladder_value_lh1,
cte_ladder_history_self_join_lh1.ladder_change_lh1,
cte_ladder_history_self_join_lh2.member_id_lh2,
cte_ladder_history_self_join_lh2.trigger_name_lh2,
cte_ladder_history_self_join_lh2.trigger_record_id_lh2,
cte_ladder_history_self_join_lh2.date_trigger_event_lh2,
cte_ladder_history_self_join_lh2.ladder_name_lh2,
cte_ladder_history_self_join_lh2.ladder_value_lh2,
cte_ladder_history_self_join_lh2.ladder_change_lh2,
datediff(cte_ladder_history_self_join_lh2.date_trigger_event_lh2,cte_ladder_history_self_join_lh1.date_trigger_event_lh1) as days_spent,
#member_id:=member_id_lh2 AS member_id,
#row_number:=(CASE
WHEN #member_id = member_id_lh1
THEN #row_number + 1
ELSE 1
END) AS rank
from
cte_ladder_history_self_join_lh1 #previous or current ladder history
left join cte_ladder_history_self_join_lh2 on cte_ladder_history_self_join_lh1.member_id_lh1 = cte_ladder_history_self_join_lh2.member_id_lh2
and cte_ladder_history_self_join_lh2.ladder_name_lh2 = cte_ladder_history_self_join_lh1.ladder_name_lh1
and cte_ladder_history_self_join_lh1.ladder_value_lh1 <> cte_ladder_history_self_join_lh2.ladder_value_lh2
and cte_ladder_history_self_join_lh1.date_trigger_event_lh1 < cte_ladder_history_self_join_lh2.date_trigger_event_lh2 # lh2 shows second begin date / end date for lh if exists
order by date_trigger_event_lh2 desc, member_id_lh1 desc;
Which returns the following:
I'm not sure why the ranking isn't working correctly. I'd expect there to be a rank from about 1 - 20 (based on the number of rows that match the ladder_name = advocacy criteria for this person) but I'm getting some wildly different numbers.
Thoughts?
Fixed teh ranking code to read:
CREATE TEMPORARY TABLE cte_leenk_ladder_history_rank
SELECT * ,
#row_number:=(CASE
WHEN #member_id = member_id
THEN #row_number + 1
ELSE 1
END) AS rank,
#member_id := member_id
FROM
cte_leenk_ladder_history_order
where ladder_change = 1
order by salesforce_id desc, date_trigger_event desc;
Related
I'm looking into creating a column Status based on a football result where if you have the maximum points, then you're the champion. However, if there are two teams with the maximum points, then another condition where goal differences need to be the highest as well to be the champion. The status will display as '1' if the team is a champion and '0' otherwise.
An example of my original table is as follow:
Team
Total_points
Goal_difference
A
15
3
B
20
2
C
20
5
D
10
9
Afterwards, I'd insert another column called status, and update it based on the total_points only:
alter table_name
add column status int(1) after goal_difference;
update table_name
set status = case
when total_points = (select * from (select max(total_points) from table_name) as X) then '1'
else '0'
end;
How can I modify my command so that if the first condition is satisfied and only when duplicate values of '1' is detected, it will then proceed to check the conditions of the goal difference? The priority is still the total points not the goal difference.
Any feedback is appreciated, thanks!
If you are running MySQL 8+, then ROW_NUMBER would work well here:
WITH cte AS (
SELECT *, ROW_NUMBER() OVER (ORDER BY Total_points DESC, Goal_difference DESC) rn
FROM yourTable
)
SELECT Team, Total_points, Goal_difference,
CASE WHEN rn = 1 THEN 1 ELSE 0 END AS champion
FROM cte
ORDER BY Team, rn;
having a mysql table with multiple records belonging many different users like this:
id score
1 , 50
1 , 75
1 , 40
1, 20
2 , 85
2 , 60
2 , 20
i need to get the rank of each id but after finding the sum of their score;
the rank should be the same if the total score for each player is the same.
this gives me the total for each player:
select id,sum(score) as total from table_scores group by id order by total desc;
is it posssible to find the sum like above and use it to rank the players in one query?
Something big missing from the accepted answer. The rank needs to be bumped after a tie. If you've got 2 tied for 3rd place, there is no 4th place.
The following query is an adjustment of the accepted SQL to account for this and reset the rank variable (#r in the query) to match the row value. You can avoid the extra addition in the CASE/WHEN but initializing #row to 1 instead of 0 but then the row value is off by 1 and my OCD won't let that stand even if row number is not valuable.
select
id, total,
CASE WHEN #l=total THEN #r ELSE #r:=#row + 1 END as rank,
#l:=total,
#row:=#row + 1
FROM (
select
id, sum(score) as total
from
table_scores
group by
id
order by
total desc
) totals, (SELECT #r:=0, #row:=0, #l:=NULL) rank;
You can rank rows using variables:
select
id, total,
CASE WHEN #l=total THEN #r ELSE #r:=#r+1 END as rank,
#l:=total
FROM (
select
id, sum(score) as total
from
table_scores
group by
id
order by
total desc
) totals, (SELECT #r:=0, #l:=NULL) rank;
Please see it working here.
i find one more way to this problem... This one is based on JOIN clause
SET #rank = 0;
SELECT t1.id, t1.score, t2.rank
FROM (SELECT id, SUM(score) as score
FROM table_scores GROUP BY id ORDER BY score Desc) AS t1
INNER JOIN
(SELECT x.score, #rank:=#rank + 1 as rank FROM
(SELECT DISTINCT(SUM(score)) AS score
FROM table_scores
GROUP BY id ORDER BY score DESC) AS x) AS t2
ON t1.score = t2.score
Here is SQL Fiddle: http://sqlfiddle.com/#!9/2dcfc/16
P.S. it's interesting to see there is more then one way to solve a problem...
I can simplify my table structure for the purposes of this question to the following:
http://sqlfiddle.com/#!2/dcdd3/1
I want to get the longest win streak for each user (i.e. the largest number of contiguous win=1 rows without a win=0 row in between, returned in the following format:
user_id | win_streak
--------------------
1 | 5
2 | 3
3 | 3
The current solution I have is to get all of the rows and build the results in a PHP foreach loop, but I can't help thinking that there is a way to do this in MySQL.
You need a column that defines the order of the wins. I was assuming this to be the auto_increment column id:
select
user_id, max(wins) as longest_winning_streak
from (
SELECT
ugr.*
, #winstreak := if(#prev_user = user_id, if(won = 1, #winstreak + 1, 0), 1) as wins
, #prev_user := user_id
FROM `user_game_results` ugr
, (SELECT #winstreak := 0, #prev_user := null) var_init
ORDER BY user_id, id
) sq
group by user_id
see it working live in an sqlfiddle
Your desired result is not quite correct, user_id has 3 wins in a row.
Take a look at this previous answer:
http://stackoverflow.com/questions/15484908/mysql-count-the-number-of-consecutive-times-a-value-appears
I have two tables:
Members:
id username
Trips:
id member_id flag_status created
("YES" or "NO")
I can do a query like this:
SELECT
Trip.id, Trip.member_id, Trip.flag_status
FROM
trips Trip
WHERE
Trip.member_id = 1711
ORDER BY
Trip.created DESC
LIMIT
3
Which CAN give results like this:
id member_id flag_status
8 1711 YES
9 1711 YES
10 1711 YES
My goal is to know if the member's last three trips all had a flag_status = "YES", if any of the three != "YES", then I don't want it to count.
I also want to be able to remove the WHERE Trip.member_id = 1711 clause, and have it run for all my members, and give me the total number of members whose last 3 trips all have flag_status = "YES"
Any ideas?
Thanks!
http://sqlfiddle.com/#!2/28b2d
In that sqlfiddle, when the correct query i'm seeking runs, I should see results such as:
COUNT(Member.id)
2
The two members that should qualify are members 1 and 3. Member 5 fails because one of his trips has flag_status = "NO"
You could use GROUP_CONCAT function, to obtain a list of all of the status ordered by id in ascending order:
SELECT
member_id,
GROUP_CONCAT(flag_status ORDER BY id DESC) as status
FROM
trips
GROUP BY
member_id
HAVING
SUBSTRING_INDEX(status, ',', 3) NOT LIKE '%NO%'
and then using SUBSTRING_INDEX you can extract only the last three status flags, and exclude those that contains a NO. Please see fiddle here. I'm assuming that all of your rows are ordered by ID, but if you have a created date you should better use:
GROUP_CONCAT(flag_status ORDER BY created DESC) as status
as Raymond suggested. Then, you could also return just the count of the rows returned using something like:
SELECT COUNT(*)
FROM (
...the query above...
) as q
Although I like the simplicity of fthiella's solution, I just can't think of a solution that depends so much on data representation. In order not to depend on it you can do something like this:
SELECT COUNT(*) FROM (
SELECT member_id FROM (
SELECT
flag_status,
#flag_index := IF(member_id = #member, #flag_index + 1, 1) flag_index,
#member := member_id member_id
FROM trips, (SELECT #member := 0, #flag_index := 1) init
ORDER BY member_id, id DESC
) x
WHERE flag_index <= 3
GROUP BY member_id
HAVING SUM(flag_status = 'NO') = 0
) x
Fiddle here. Note I've slightly modified the fiddle to remove one of the users.
The process basically ranks the trips for each of the members based on their id desc and then only keeps the last 3 of them. Then it makes sure that none of the fetched trips has a NO in the flag_status. FInally all the matching meembers are counted.
I have a table in MySQL that contains a column name category.
I am trying to write a query that will return 2 random records from each category.
Here is code that I use to get 2 records from each category with the highest values in my rating column:
SELECT e1.*
FROM entries AS e1
WHERE (SELECT Count(*)
FROM entries AS e2
WHERE e2.category = e1.category
AND e1.rating <= e2.rating) <= 2
ORDER BY category,
rating DESC
Check this link out to see a table with some sample data and the above query:
http://sqlfiddle.com/#!9/bab8e/1
I achieved your desired results by sorting the table by the category column and a random number. I then assigned an incrementing number to each row that starts over each at 1 each time the category changed. I then return only the results that have a rowNum that is less than or equal to 2. If you wanted to return 3 random rows you would just change it to less than or equal to 3 and so on.
SELECT entry_id,
category,
rating
FROM (SELECT #currank := IF(#category = category, #currank + 1, 1) AS rowNum,
#category := category AS categoryVar,
e1.*
FROM (SELECT *,
(SELECT #currank := 0) r
FROM entries
ORDER BY category,
Rand()) AS e1)AS e2
WHERE rownum <= 2
ORDER BY category,
rating;
Here is an sqlfiddle link like the one you posted in your question:
http://sqlfiddle.com/#!9/bab8e/37/0
Do note that this same query could easily be adjusted to return a set number of records that are not random. For example, if you wanted to return the top 5 ratings from each category you could change the
ORDER BY category,rand()
to
ORDER BY category, rating DESC
and changing
WHERE rownum <= 2
to
WHERE rownum <= 5