remove repeated users from rank with group by - mysql

I am trying to rank from a table users. This table contains a log of all results. I already can rank the elements depending on the result ASC, but I have repeated users ID that I want to group by but I can't.
ID_competitionLog ID_event ID_athlete result wind rank
4 19 2 49.12 NULL 1
6 19 11 49.56 NULL 2
13 19 1 50.12 NULL 4
17 4 1 49.8 NULL 3
SELECT *, FIND_IN_SET( result, ( SELECT GROUP_CONCAT( result ORDER BY result ASC )
FROM competitionlog where (ID_event = 19 or ID_event = 4) and (result <> 0.0125 and result <> 0.00125 and result <> 0.000125))) AS rank
FROM competitionlog where (ID_event = 19 or ID_event = 4) and (result <> 0.0125 and result <> 0.00125 and result <> 0.000125);
I try to group by the repeated users and get only theirs best result to compare in the ranking

Related

Query to return to 4th to 8th rank in a leaderboard?

I have been given a leaderboard, I need to return the row correspond to 4th to 8th rank in a leaderboard?
id name score
1 gongy 3001
2 urandom 2401
3 eduardische 2477
4 Gassa 2999
5 bcc32 2658
6 Alex_2oo8 6000
7 mirosuaf 2479
8 Sparik 2399
9 thomas_holmes 2478
The query I have is not being accepted
select b.name from
(
select a.name as name ,a.score as score from
(
select name,score from leaderboard order by score desc limit 8
)a
order by a.score
limit 5
) b
order by b.score desc;
You can use LIMIT OFFSET
select id,
name,
score
from leaderboard
order by score desc
limit 4 offset 3 ; --- fetch 4 records, begin with record 4 (OFFSET 3)
https://dbfiddle.uk/Ys-3jC4L
Above query skips the first 4 rows and limit the result to 4 make it from 4th to 8th
select x.id,x.name,x.score
from
(
select id,name,score,
row_number()over(order by score desc)xcol
from your_table
)x where x.xcol >=3 and x.xcol<=8
May be something like this ?

Select only unique ids row of table with different values in Descending order

I'm trying to get data that have the same medicine_id and unique insurance_id and last inserted row. Put Group by and Order by but in that got random data not last inserted.
I tried this code but got not last inserted data
SELECT
`m1`.`*`
FROM
(
`pricings` `m1`
LEFT JOIN `pricings` `m2` ON
(
(
(
`m1`.`medicine_id` = `m2`.`medicine_id`
)
)
)
)
WHERE m1.medicine_id = 2
group BY m1.insurance_id DESC
ORDER BY m1.created_at;
Here are the total rows.
This is a full table
id
medicine_id
insurance_id
created_at
4311
2
1
2021-04-12 16:05:07
4766
2
1
2022-01-15 11:56:06
4767
2
38
2021-05-12 08:17:11
7177
2
38
2022-03-30 10:14:11
4313
2
39
2021-04-12 16:05:46
4768
2
39
2021-05-12 08:17:30
1356
2
40
2020-11-02 11:25:43
3764
2
40
2021-03-08 15:42:16
4769
2
40
2021-05-12 08:17:44
And I want to like this
id
medicine_id
insurance_id
created_at
4766
2
1
2022-01-15 11:56:06
4768
2
39
2021-05-12 08:17:30
4769
2
40
2021-05-12 08:17:44
7177
2
38
2022-03-30 10:14:11
MySQL 5.x: Use a sub-query to find the max created_at value per group, then join that on the source table to identify the row it was from.
SELECT
p.`*`
FROM
`pricings` p
INNER JOIN
(
SELECT
`medicine_id`,
`insurance_id`,
MAX(created_at) AS `created_at`
FROM
`pricings`
GROUP BY
`medicine_id`,
`insurance_id`
)
p_max
ON p.`medicine_id` = p_max.`medicine_id`
AND p.`insurance_id` = p_max.`insurance_id`
AND p.`created_at` = p_max.`created_at`
WHERE
p.`medicine_id` = 2
ORDER BY
p.`created_at`;
MySQL 8: Use ROW_NUMBER() to enumerate each group, then pick the first row from each group.
SELECT
p.`*`
FROM
`pricings` p
FROM
(
SELECT
*,
ROW_NUMBER() OVER (
PARTITION BY `medicine_id`,
`insurance_id`
ORDER BY `created_at` DESC
)
AS `row_id`
FROM
`pricings`
)
p
WHERE
p.`medicine_id` = 2
AND p.`row_id` = 1
ORDER BY
p.`created_at`;
Adding it as an answer as well. I have not tested it, just fix the formating to work with whatever version of databse you are working with and let me know of the results.
SELECT m1.id , m1.Insurance_id , m1.medicine_id , max(m1,created_at)
FROM (
`pricings` `m1` LEFT JOIN `pricings` `m2` ON `m1`.`medicine_id` = `m2`.`medicine_id`
)
WHERE m1.medicine_id = 2 and m1.insurance_id in (1,39,40,38)
GROUP BY m1.insurance_id DESC
ORDER BY m1.created_at;
Edit. I also removed the 6 extra parenthesis, I don't see how they could be of any use

get last completed (some condition) id while counting

I'm trying to get the last completed task id of the child table while counting all the child records and completed child records:
set #tmp := 0;
select
count(*) total,
count(if(completed=1, 1, null)) completed,
#tmp:=if(completed=1, task_id, #tmp) last_completed_task_id
from child_table where parent_id = 6
order by sequence
Here is some sample data:
id parent_id completed task_id sequence
526 6 1 1 1
1653 6 0 5 2
2749 6 0 20 3
3840 6 0 21 4
4913 6 1 22 5
5983 6 0 23 6
7063 6 0 25 7
7183 6 0 26 8
8241 6 1 27 9
9317 6 0 28 10
10380 6 0 29 11
So final result should be like that:
total: 11
completed: 3
last_completed_task_id: 27
I know how to get it with separate queries, but I wish to get it with one query if possible.
You could use a cros join between the count and the max task_id eg:
select
count(*) total,
count(if(completed=1, 1, null)) completed,
t.last_completed_task_id
from child_table
cross join (
select max(task_id) last_completed_task_id
from child_table
where parent_id = 6
and completed=1 ) t
where parent_id = 6
You can easily get the last completed id using conditional aggregation:
select count(*),
sum(is_completed = 1),
max(case when is_completed = 1 then id end) as last_completed_id
from child_table ct
where parent_id = 6;
If task_id is increasing -- as in your sample data -- you can just use task_id rather than id in the max().
Otherwise, just join the table back in:
select cnt, cnt_completed, ct2.task_id
from (select count(*) as cnt,
sum(is_completed = 1) as cnt_completed,
max(case when is_completed = 1 then id end) as last_completed_id
from child_table ct
where parent_id = 6
) x join
child_table ct2
on x.last_completed_id = ct2.id
You could try this :
select count(*) total,
count(if(completed=1, 1, null)) completed,
(select task_id from child_table where parent_id = 6 and completed = 1 order by sequence desc limit 1) as last_completed_task_id
from child_table
where parent_id = 6

Get max and min values along with all values and multiple where clause

I have this query which works very good
SELECT cm.id ,cm.edited,cm.date_edited,cm.voteup,cm.votedown
FROM chat_messages cm
WHERE TIMESTAMPDIFF(SECOND,cm.date_edited,'$now') < 10 GROUP BY cm.id
Which gives me the entries which are edited in less then 10 seconds.
But along with that im trying to get also the max(voteup) and min(votedown)
But dont affect the first entries of the first query . How can i combine then to get all entries i need ?
Example:
if im getting 3 newly updates entries . i want to get them those 3 plus the max of voteup and votedown .
Example:
id edited date_edited voteup votedown
37 0 2016-03-05 22:13:03 5 0
38 0 2016-04-02 11:15:00 3 7
39 0 2016-03-05 22:10:06 10 6
40 0 2016-03-20 21:40:06 5 0
41 1 2016-04-20 22:28:59 5 0
42 1 2016-03-20 21:59:15 0 20
43 1 2016-04-21 22:20:25 8 0 <---- this new updated
My wished result is
id edited date_edited voteup votedown maxup maxdown
39 0 2016-03-05 22:10:06 10 6 10 NULL
42 1 2016-03-20 21:59:15 0 20 NUll 20
43 1 2016-04-21 22:20:25 8 0 NULL NULL
My $now time is 2016-04-21 22:20:20
explanation:
-id 39 is having maxup vote i want get it
-id 42 is having maxdown i want get it
-id 43 is newly updated in that period of 10 seconds.
so i general i want get new updated entries pls the max up and down .
if many max voteup values are same then just choose one which have min votedown
Any solution to that pls ?
Here my sqlfiddle example
Edit: oh sorry i meant id . now wish my question is clear like
you will want to use a UNION statement:
SELECT * FROM (
select cm.id ,cm.edited,cm.date_edited,cm.voteup,cm.votedown
, voteup as maxup, null AS maxdown
from chat_messages cm
ORDER BY voteup DESC, votedown
LIMIT 1
) a
UNION
SELECT * FROM (
select cm.id ,cm.edited,cm.date_edited,cm.voteup,cm.votedown
, null as maxup, votedown AS maxdown
from chat_messages cm
ORDER BY votedown DESC, voteup
LIMIT 1
) b
UNION
SELECT * FROM (
SELECT cm.id ,cm.edited,cm.date_edited,cm.voteup,cm.votedown
, null as maxup, null AS maxdown
from chat_messages cm
WHERE TIMESTAMPDIFF(SECOND,cm.date_edited,'2016-04-21 22:20:20') < 10
) c
note that I used '2016-04-21 22:20:20', but you will want to substitute the $now back in
you can use user-defined variables to track your maximums and then outer query the rows that match your rules.
SELECT id,edited,date_edited,voteup,votedown,
IF(voteup=#maxvoteup,voteup,NULL) as maxvoteup,
IF(votedown=#maxvotedown,votedown,NULL) as maxvotedown
FROM (SELECT cm.id ,cm.edited,cm.date_edited,cm.voteup,cm.votedown,
#maxvoteup := GREATEST(#maxvoteup,cm.voteup) as maxvoteup,
#maxvotedown := GREATEST(#maxvotedown,cm.votedown) as maxvotedown
FROM chat_messages cm,(SELECT #maxvoteup:=0,#maxvotedown:=0)initial
)T
WHERE TIMESTAMPDIFF(SECOND,date_edited,'2016-04-21 22:20:25') < 10
OR voteup = #maxvoteup
OR votedown = #maxvotedown
ORDER BY id ASC
sqlfiddle
Here's another query that is much more CRAZY..but it works ..
for maxupvote row, it'll find row that has maxupvote and minimum down vote, if more than 1 row exists (in a tie) it'll grab the row with latest/largest id.
for maxdownvote row, it'll find row that has maxdownvote and minimum up vote,
if more than 1 row exists (in a tie) it'll grab the row with latest/largest id.
SELECT id,edited,date_edited,voteup,votedown,
IF(voteup=#maxvoteup,voteup,NULL) as maxvoteup,
IF(votedown=#maxvotedown,votedown,NULL) as maxvotedown
FROM (SELECT cm.id ,cm.edited,cm.date_edited,cm.voteup,cm.votedown,
#minvotedown :=
(CASE WHEN cm.voteup > #maxvoteup OR (cm.voteup = #maxvoteup AND cm.votedown < #minvotedown)
THEN cm.votedown
ELSE #minvotedown
END),
#minvoteup :=
(CASE WHEN cm.votedown > #maxvotedown OR (cm.votedown = #maxvotedown AND cm.voteup < #minvoteup)
THEN cm.voteup
ELSE #minvoteup
END),
#maxvoteup := GREATEST(#maxvoteup,cm.voteup) as maxvoteup,
#maxvotedown := GREATEST(#maxvotedown,cm.votedown) as maxvotedown,
#maxvoteupid :=
(CASE WHEN cm.voteup = #maxvoteup AND cm.votedown = #minvotedown
THEN cm.id
ELSE #maxvoteupid
END),
#maxvotedownid :=
(CASE WHEN cm.votedown = #maxvotedown AND cm.voteup = #minvoteup
THEN cm.id
ELSE #maxvotedownid
END)
FROM chat_messages cm,(SELECT #maxvoteup:=0,#maxvotedown:=0,#minvoteup:=0,#minvotedown:=0,#maxvoteupid:=0,#maxvotedownid:=0)initial
ORDER BY cm.id ASC
)T
WHERE TIMESTAMPDIFF(SECOND,date_edited,'2016-04-21 22:20:25') < 10
OR id = #maxvoteupid
OR id = #maxvotedownid
ORDER BY id ASC;
sqlfiddle
I call it CRAZY because it is...if i was doing this. I would just run 3 separate queries
1 query to return one row with order by upvote DESC, downvote ASC, id DESC limit 1
1 query to return one row with order by downvote DESC, upvote ASC, id DESC limit 1
1 query to return one row that's within the last 10 seconds order by id DESC
this way it's much easier to maintain.

MYSQL query better way to group by if values?

I have a working query, but there has to be a better way to do this.
Here is the working query
SELECT gameid FROM(
SELECT gameid, SUM(count) as total FROM (
SELECT IF(vanguard = 1, 30, gameid) as gameid, count FROM (
SELECT opserv_operation.gameid, opserv_games.vanguard, COUNT(opserv_games.gameid) AS count FROM opserv_operation_attendees INNER JOIN opserv_operation ON opserv_operation_attendees.operationid = opserv_operation.operationid INNER JOIN opserv_games on opserv_operation.gameid = opserv_games.gameid WHERE (start_time >= '2015-11-11' || FIND_IN_SET(opserv_operation.operationid, '17951,17701,17702,17775,17969,17890,17958,17966,17900')) AND completed = 1 AND opserv_operation_attendees.userid = 5750 AND opserv_operation_attendees.status = 4 AND opserv_operation.type <> 5 AND opserv_operation.completed = 1 GROUP BY opserv_operation.gameid) as m
) as l
GROUP BY gameid
ORDER BY total DESC LIMIT 1) as k
The main query
SELECT opserv_operation.gameid, opserv_games.vanguard, COUNT(opserv_games.gameid) AS count FROM opserv_operation_attendees INNER JOIN opserv_operation ON opserv_operation_attendees.operationid = opserv_operation.operationid INNER JOIN opserv_games on opserv_operation.gameid = opserv_games.gameid WHERE (start_time >= '2015-11-11' || FIND_IN_SET(opserv_operation.operationid, '17951,17701,17702,17775,17969,17890,17958,17966,17900')) AND completed = 1 AND opserv_operation_attendees.userid = 5750 AND opserv_operation_attendees.status = 4 AND opserv_operation.type <> 5 AND opserv_operation.completed = 1 GROUP BY opserv_operation.gameid
gameid vanguard
16 0
36 1
36 1
36 1
16 0
36 1
27 0
16 0
36 1
36 1
36 1
30 0
36 1
36 1
27 0
36 1
36 1
36 1
So here is the tricky part. I need it to group by and count all the values however if gameid = 30 or vanguard = 1 then they should be all counted together.
So with the above data, the only thing I need is the gameid returned in this case gameid 30. It would have the most counts which would be 13.
There has to be a better way than I have done it.
Edit: So far this one works great thanks to Ed Gibbs. However is still returns two values, I'm guessing only way is to have another subquery? to get just gameid.
SELECT
CASE WHEN vanguard = 1 THEN 30 ELSE gameid END AS gameid,
SUM(count) AS total
FROM (SELECT opserv_operation.gameid, opserv_games.vanguard, COUNT(opserv_games.gameid) AS count FROM opserv_operation_attendees INNER JOIN opserv_operation ON opserv_operation_attendees.operationid = opserv_operation.operationid INNER JOIN opserv_games on opserv_operation.gameid = opserv_games.gameid WHERE (start_time >= '2015-11-11' || FIND_IN_SET(opserv_operation.operationid, '17951,17701,17702,17775,17969,17890,17958,17966,17900')) AND completed = 1 AND opserv_operation_attendees.userid = 5750 AND opserv_operation_attendees.status = 4 AND opserv_operation.type <> 5 AND opserv_operation.completed = 1 GROUP BY opserv_operation.gameid) as l
GROUP BY CASE WHEN vanguard = 1 THEN 30 ELSE gameid END
ORDER BY total DESC
LIMIT 1;
If bottom line you mean "1" and "30" have to be counted together then this should work:
SELECT
CASE WHEN vanguard = 1 THEN 30 ELSE gameid END AS gameid
FROM (... main query ...)
GROUP BY CASE WHEN gameid = 1 THEN 30 ELSE gameid END
ORDER BY SUM(count) DESC
LIMIT 1;