How break ties after getting rank - php

I have a query that gets me a users rank in a table of scores.
SELECT
*
FROM
(SELECT
*, #rank:=#rank + 1 rank
FROM
(SELECT
user_id, SUM(round_total) TotalPoints
FROM
sx14sp_mem_picks
GROUP BY user_id) s, (SELECT #rank:=0) init
ORDER BY TotalPoints DESC) r
WHERE
user_id = 22234
There is a problem with ties. I have a table field "pick_date" that i would like to use to break ties with. The user who made his picks first beats the tie.
Any ideas?

If sx14sp_mem_picks.pickdate is the field to break ties then in the order by sx14sp_mem_picks subquery, add
min( pickdate) asc
This will put the earliest pickdate first - you have to use MIN() bc you need to use an aggregate function given the use of "group by".

You need to order by the pick date in addition to the total points. However, you are talking about multiple rows per user. So, let's take the last pick date:
SELECT *
FROM (SELECT *, (#rank:=#rank + 1) as rank
FROM (SELECT user_id, SUM(round_total) as TotalPoints, max(pick_date) as max_pick_date
FROM sx14sp_mem_picks
GROUP BY user_id
) s CROSS JOIN
(SELECT #rank := 0) init
ORDER BY TotalPoints DESC, max_pick_date asc
) r
WHERE user_id = 22234;

Related

How we can get the data from the table by limiting the number of identical columns MySql

Yesterday I tried to retrieve data from my db table using 'user_id' as a criterion to limit the amount of data per user.
I tried to get data from table https://prnt.sc/p53zhp in format like this https://prnt.sc/p541wk and limit the number of output records for user_id where limit will be 2 (count(user_id) <= 2), but i don't understand how to do that. What kind of sql request can i use to get this data?
Assuming that your RDBMS, here is a solution yo select only the top 2 records per user. You can use ROW_NUMBER() in a subquery to rank records by id within groups of records having the same user_id, and the filter out unerelevant records in the outer query, like:
SELECT *
FROM (
SELECT
t.*,
ROW_NUMBER() OVER(PARTITION BY user_id ORDER BY id)
FROM mytable
) x WHERE rn <= 2
On earlier versions of MySQL, you could use self-LEFT JOIN the table and use GROUP BY and HAVING COUNT(...) < 2 to limit the results to first two records per group:
SELECT
t.id,
t.user_id,
t.vip,
t.title,
t.description,
t.data
FROM mytable t
LEFT JOIN mytable t1 ON t1.user_id = t.user_id AND t1.id > t.id
GROUP BY
t.id,
t.user_id,
t.vip,
t.title,
t.description,
t.data
HAVING COUNT(t1.id) < 2
I don't understand if your problem is a Transact-SQL or your code.
In SQL you can limit record with "LIMIT": https://www.w3schools.com/sql/sql_top.asp
In code, you can use a condition IF.

show users the position after sorting based on score

I have a table which has the id column and score column, I want to sort the table based on score column and then find the specific user who is loading the page and show him his/her position. for example, tell him "your position is 40th".
Well I know how to sort a query:
SELECT id,score FROM `table` ORDER BY `score` DESC
But after the sort how can I find an specific id's position?
You don't need an order by for this. Instead:
select 1 + count(*)
from table t
where t.score > (select t2.score from table t2 where id = $id);
Try it:
SELECT #rownum:=#rownum+1 ‘rank’, id, score FROM table t, (SELECT #rownum:=0) r ORDER BY score DESC;
This will create a column and increase 1 in each record.

MySQL: order by sum

I have article table
`id`,
`article_id`,
`stage_1_point`,
`stage_2_point`
I need top 10 articles based on
(stage_1_point+stage_2_point),
in the list and when i view any article i need to show its place.
My question is how can show its place without using order by.
USE ORDER BY (stage_1_point+stage_2_point) DESC
So, It will be like
SELECT `id`,
`article_id`,
`stage_1_point`,
`stage_2_point`
FROM YOUR_TABLE ORDER BY (stage_1_point+stage_2_point) DESC
LIMIT 0,10
UPDATE
As OP stated, he/she needs to know the position of specific article.
SELECT * FROM (SELECT `id`,
`article_id`,
`stage_1_point`,
`stage_2_point`,
#curRank := #curRank + 1 AS rank
FROM YOUR_TABLE, (SELECT #curRank := 0) r ORDER BY
(stage_1_point+stage_2_point) DESC) TAB
WHERE `article_id`=10
Above query will return rows for article_id 10, which will have a column Rank which tells the position of the article.
You can try below Query as below
Select
stage_1_point+stage_2_point as added_point,
columnsid,
article_id,
stage_1_point,
stage_2_point
FROM tablename
ORDER BY 1 desc
Limit 0,10
This will sort data based on column one result and fetch top 10 results only.

Verify a specific and unique group of values in a group

I have a MySQL table with the following structure:
I want a query that would receive a group of uids (or a single uid) and then check for their existence in a closed group under a specific mid. If they exist, the query should return the mid under which they exist. For example in the table above:
('chuks.obima', 'crackhead') should return '2
('vweetah','crackhead') should return '1'
('vweetah','crackhead','chuks.obima') should return 3
('crackhead') should return an empty result
I think you need something like this:
SELECT mid
FROM your_table
WHERE uid in ('favour','crackhead','charisma')
GROUP BY mid
HAVING COUNT(*)=3
EDIT: based on your second example, this is what you are looking for:
SELECT mid
FROM your_table
WHERE uid in ('vweetah', 'crackhead')
GROUP BY mid
HAVING
COUNT(distinct uid)=
(select count(*)
from (select 'vweetah' union select 'crackhead') s)
or you can just substitute last subquery with the number of elements you are looking for, e.g. HAVING COUNT(distinct uid) = 2
EDIT2: now i understand exactly what you are looking for. This should give you the correct results:
SELECT your_table.mid, s.tot_count, count(distinct uid)
FROM
your_table inner join
(select mid, seq, count(distinct uid) tot_count from your_table group by mid, seq) s
on your_table.mid = s.mid and your_table.seq=s.seq
WHERE your_table.uid in ('crackhead')
GROUP BY your_table.mid
HAVING COUNT(distinct uid)=s.tot_count AND COUNT(distinct uid)=1
where the last count is equal to the number of elements you are looking for. This could be simplified like this:
SELECT your_table.mid
FROM your_table
GROUP BY your_table.mid
HAVING
count(distinct uid)=
count(distinct case when your_table.uid in ('vweetah','crackhead','chuks.obima') then your_table.uid end)
and count(distinct uid)=3
If the group is to considered closed if all uid are under the same seq, you also have to modify group by with: group by your_table.mid, your_table.seq and your select with SELECT distinct your_table.mid
To verify that it is a closed group, you can get the aggregate COUNT() of the total members of that mid group and compare it to the number of people in your list. If they are equal, it is closed.
The following would return a 1 if all 3 are in the group, and the total number of people in the group is also 3.
SELECT
(((SELECT COUNT(*) FROM yourtable WHERE `uid` IN ('favour','crackhead','charisma') AND `mid` = 2)
=
(SELECT COUNT(*) FROM yourtable WHERE `mid` = 2))
AND (SELECT COUNT(*) FROM yourtable WHERE `mid` = 2) = 3) AS group_is_closed
Wrap it in a subquery to avoid counting the mid twice.
SELECT
/* 3 is the number of uid you are looking for */
(mid_count = 3 AND mid_count = member_count) AS group_is_closed
FROM (
SELECT
/* Find how many of your uids are in the `mid` */
(SELECT COUNT(*) FROM yourtable WHERE `uid` IN ('favour','crackhead','charisma') AND `mid` = 2) AS member_count,
/* Find the total number of uids in the `mid` */
(SELECT COUNT(*) FROM yourtable WHERE `mid` = 2) AS mid_count
) subq
SQLFiddle demos (aka wow, it actually works):
Positive result (Only the 3 selected are in the mid, returns 1)
Negative result (A user not among the 3 is also in the mid, returns 0)
Negative result 2 (One of the 3 users is not in the mid, returns 0)
Try this:
SELECT mid
FROM your_table
WHERE uid in ('favour','crackhead','charisma')
GROUP BY mid
HAVING COUNT(DISTINCT uid) = 3

Limit the amount of results from mySQL conditionally?

Here is my query:
SELECT * FROM Photos WHERE Event_ID IN ($eventidstring)
I know I can limit the total amount of results from this query using LIMIT 5
I need the Limit the amount of results Per value in $eventidstring.
So if $eventidstring = 23,41,23*
*And there are 10 results WHERE Event_ID = 23, I want to limit this amount to 5. The same for all the other values in $eventidstring.
You may have some joy doing something similar to Oracle's RANK by PARITION in MySQL.
Sadly this feature is not available in MySQL though you can work around it using this method
Dump that in an inline view and then select those rows with rank <= 5;
Hence:
SELECT t.* FROM (
SELECT (
CASE Event_id
WHEN #curEventId
THEN #curRow := #curRow + 1
ELSE #curRow := 1 AND #curEventId := Event_Id END
) AS rank,
p.*
FROM Photos p INNER JOIN (SELECT #curRow := 0, #curEventId := '') r
ORDER BY p.Event_Id DESC
) t
WHERE t.rank <= 5 ORDER BY t.Event_Id asc;
Consider how you are going to 'choose' the top five by Event_Id too. You can always add in more after the ORDER BY p.Event_Id DESC to decide this.
I take it you're writing that query somewhere inside your PHP, so you need to split the $eventidstring into it's component values, form a SELECT for each and UNION all after the first one.
You sould do this with a loop of some sort, and concatenate the query strings in the loop...
If I understand correctly and you want to get five of each, you can use this:
(SELECT * FROM Photos WHERE Event_ID = 23 LIMIT 5)
UNION
(SELECT * FROM Photos WHERE Event_ID = 41 LIMIT 5)
UNION
(SELECT * FROM Photos WHERE Event_ID = ... LIMIT 5)
...
Maybe with a SELECT UNION but you need a new select for each value:
SELECT * FROM Photos WHERE Event_ID = 23 LIMIT 5
UNION SELECT * FROM Photos WHERE Event_ID = 41 LIMIT 5
UNION SELECT ...

Categories