Fetch Max-Distict values from MySQL - mysql

I have a table in database. A user(Name) with a serial no(User-no) can play multiple times. Each time user plays, a new id(Id) is generated and it gets stored in the database along with the score(Score). I want to fetch the top three scores from the table where each users' only top scores get displayed.
Table:
Id | User-no | Name | Score
1 | 1 | Name1 | 400
2 | 2 | Name2 | 700
3 | 3 | Name3 | 100
4 | 2 | Name2 | 500
5 | 4 | Name4 | 800
6 | 3 | Name3 | 200
7 | 1 | Name1 | 500
8 | 4 | Name4 | 700
Result should be:
Id | User-no | Name | Score
5 | 4 | Name4 | 800
2 | 2 | Name2 | 700
7 | 1 | Name1 | 500
How can I get the above result. I am using MySQL.

this can be done with a join on a derived table, though you'd need the right index for it to be efficient
select id, uid, name, score
from scores
join (select uid, max(score) as score from scores group by uid) t
using (uid, score)
order by score desc
limit 3;
+------+------+------+-------+
| id | uid | name | score |
+------+------+------+-------+
| 5 | 4 | n4 | 800 |
| 2 | 2 | n2 | 700 |
| 7 | 1 | n1 | 500 |
+------+------+------+-------+
3 rows in set (0.00 sec)
Edit: the right index would be (uid, score). Derived tables do not have indexes, so mysql would loop through the max scores results and pull up the matching rows from the main table.

Related

inner join showing duplicate rows in output . it is showing data multiple times

Hello I want to show values table1, and values from table2 and show them together in datagridview.
But my output is showing duplicate values, rather than 2 values its showing 4 values with same values again
query = "select receive_bardana.bales,receive_wheat.bags from receive_bardana
inner Join receive_wheat
On receive_bardana.id= receive_wheat.id
where receive_bardana.id ='1'"
My output is:
+-------+------+
| BALES | BAGS |
+-------+------+
| 100 | 1000 |
| 1000 | 1000 |
| 100 | 2000 |
| 1000 | 2000 |
+-------+------+
What I have stored in tables is:
+-----+-------+
| ID | BALES |
+-----+-------+
| 1 | 100 |
| 1 | 1000 |
+-----+-------+
+-----+------+
| ID | BAGS |
+-----+------+
| 1 | 1000 |
| 1 | 2000 |
+-----+------+
ID IS THE RELATIONSHIP BETWEEN TWO TABLES. EG. I HAVE TWO GODOWNS.
ID IS THE ID NO. OF THE GODOWN
1 FOR GODOWN1
AND 2 FOR GODOWN 2
PRIMARY KEY IS THE AUTO INCREMENT VALUE.
What you can do is to add an extra row with ID2
query = "select receive_bardana.bales,receive_wheat.bags from receive_bardana
inner Join receive_wheat
On receive_bardana.id2 = receive_wheat.id2
where receive_bardana.id ='1'"
|ID | ID2 | BALES
| 1 | 1 | 100
| 1 | 2 | 1000
+-----+------+------+
|ID | ID2 | BAGS
| 1 | 1 | 1000
| 1 | 2 | 2000
+-----+------+------+

MySQL how to get first n groups?

For the follow table TestTable:
| Id | Name | Flags |
|----|-------|-------|
| 1 | name1 | 1 |
| 2 | name2 | 1 |
| 3 | name3 | 2 |
| 4 | name4 | 2 |
| 5 | name5 | 3 |
how to group by Flags and return the first 2 groups. That is to say I should return rows:
| 1 | name1 | 1 |
| 2 | name2 | 1 |
| 3 | name3 | 2 |
| 4 | name4 | 2 |
I tried this:
select *
from TestTable
group by Flags
order by Flags
limit 0,2
However the query returned 2 rows only.
You could use a sub query to take only the first two flags, and join that:
select t.id, t.name, t.flags
from testtable t
inner join (select distinct flags
from testtable
order by 1
limit 2) filter
on filter.flags = t.flags;
See it run on regtester.com

SQL query that randoms the id from all posible ids in table and outputs the rows containing that id

I want a query that selects all rows that have the UploadedbyUserID = Rand() (selects random id from possible UploadbyUserID in this case 4, 3 and 22 and only those 3 not 2 nor 5)
And if the rand gives 4 it outputs this:
+------+------+------------+--------------------+
| id | name | date | UploadedbyUserID |
+------+------+------------+--------------------+
| 1 | 2222 | Testing | 4 |
| 2 | Jack | description| 4 |
| 6 | Zara | 2007-02-06 | 4 |
+------+------+------------+--------------------+
This is the whole table
+------+------+------------+--------------------+
| id | name | date | UploadedbyUserID |
+------+------+------------+--------------------+
| 1 | 2222 | Testing | 4 |
| 2 | Jack | description| 4 |
| 3 | ffdsd| 2007-05-06 | 4 |
| 4 | dsm | 2007-05-27 | 3 |
| 5 | dddd | 2007-04-06 | 3 |
| 6 | Zara | 2007-02-06 | 4 |
| 7 | John | 2007-01-24 | 22 |
+------+------+------------+--------------------+
and if it randomizes 3 it outputs this
+------+------+------------+--------------------+
| id | name | date | UploadedbyUserID |
+------+------+------------+--------------------+
| 4 | dsm | 2007-05-27 | 3 |
| 5 | dddd | 2007-04-06 | 3 |
+------+------+------------+--------------------+
Ask if you need more information
Hmmm. This is one way:
select t.*
from (select uploadedbyuserid
from t
order by rand()
limit 1
) u join
t
using (uploadedbyuserid);
First, let me say that this is weighted by the number of times that a user has uploaded something. So, user "4" would appear a bit more often than "3", in your example. If this is an issue:
select t.*
from (select uploadedbyuserid
from (select distinct uploadedbyuserid from t) t
order by rand()
limit 1
) u join
t
using (uploadedbyuserid);
The next observation is that this can be compute intensive. If you have lots of rows, there are various ways to speed these up. For instance, one simple method would be to get about 1 out of 10000 rows:
select t.*
from (select uploadedbyuserid
from (select distinct uploadedbyuserid
from t
) t
where rand() < 0.001
order by rand()
limit 1
) u join
t
using (uploadedbyuserid);

How to get this specific user rankings query in mysql?

I've got tbl_items in my user database that I want to sort user rankings on a particular item with certain id (514). I have test data on my dev environment with this set of data:
mysql> select * from tbl_items where classid=514;
+---------+---------+----------+
| ownerId | classId | quantity |
+---------+---------+----------+
| 1 | 514 | 3 |
| 2 | 514 | 5 |
| 3 | 514 | 11 |
| 4 | 514 | 46 |
| 5 | 514 | 57 |
| 6 | 514 | 6 |
| 7 | 514 | 3 |
| 8 | 514 | 27 |
| 10 | 514 | 2 |
| 11 | 514 | 73 |
| 12 | 514 | 18 |
| 13 | 514 | 31 |
+---------+---------+----------+
12 rows in set (0.00 sec)
so far so good :) I wrote the following query:
set #row=0;
select a.*, #row:=#row+1 as rank
from (select a.ownerid,a.quantity from tbl_items a
where a.classid=514) a order by quantity desc;
+---------+----------+------+
| ownerid | quantity | rank |
+---------+----------+------+
| 11 | 73 | 1 |
| 5 | 57 | 2 |
| 4 | 46 | 3 |
| 13 | 31 | 4 |
| 8 | 27 | 5 |
| 12 | 18 | 6 |
| 3 | 11 | 7 |
| 6 | 6 | 8 |
| 2 | 5 | 9 |
| 7 | 3 | 10 |
| 1 | 3 | 11 |
| 10 | 2 | 12 |
+---------+----------+------+
12 rows in set (0.00 sec)
that ranks correctly the users. However in a table with lots of records, I need to do the following:
1) be able to get small portion of the list, around where the user ranking actually resides, something that would get me the surrounding records, preserving the overall rank:
I tried to do these things with setting a user variable to the ranking of the current user and by using offset and limit, but couldn't preserve the overall ranking.
This should get me something like the following (for instance ownerId=2 and surroundings limit 5:
+---------+----------+------+
| ownerid | quantity | rank |
+---------+----------+------+
| 3 | 11 | 7 |
| 6 | 6 | 8 |
| 2 | 5 | 9 | --> ownerId=2
| 7 | 3 | 10 |
| 1 | 3 | 11 |
+---------+----------+------+
5 rows in set (0.00 sec)
2) I'd also need another query (preferably single query) that gets me the top 3 places + the ranking of particular user with certain id, preferably with a single query, no matter if he's among the top 3 places or not. I couldn't get this as well
It would look like the following (for instance ownerId=2 again):
+---------+----------+------+
| ownerid | quantity | rank |
+---------+----------+------+
| 11 | 73 | 1 |
| 5 | 57 | 2 |
| 4 | 46 | 3 |
| 2 | 5 | 9 | --> ownerId=2
+---------+----------+------+
4 rows in set (0.00 sec)
Also I'm in a bit of a concern about the performance of the queries on a table with millions of records...
Hope someone helps :)
1) 5 entries around a given id.
set #row=0;
set #rk2=-1;
set #id=2;
select b.* from (
select a.*, #row:=#row+1 as rank, if(a.ownerid=#id, #rk2:=#row, -1) as rank2
from (
select a.ownerid,a.quantity
from tbl_items a
where a.classid=514) a
order by quantity desc) b
where b.rank > #rk2 - 3
limit 5;
Though you'll get an extra column rank2: you probably want to filter it out by explicit list of columns instead of b.*. Maybe it's possible whith a having clause rather than an extra nesting.
2) 3 top ranked entries + 1 specific id
select b.* from (
select a.*, #row:=#row+1 as rank
from (
select a.ownerid,a.quantity
from tbl_items a
where a.classid=514) a
order by quantity desc) b
where b.rank < 4 or b.ownerid=#id

Select Distinct Set Common to Subset From Join Table

Given a join table for m-2-m relationship between booth and user
+-----------+------------------+
| booth_id | user_id |
+-----------+------------------+
| 1 | 1 |
| 1 | 2 |
| 1 | 5 |
| 1 | 9 |
| 2 | 1 |
| 2 | 2 |
| 2 | 5 |
| 2 | 10 |
| 3 | 1 |
| 3 | 2 |
| 3 | 3 |
| 3 | 4 |
| 3 | 6 |
| 3 | 11 |
+-----------+------------------+
How can I get a distinct set of booth records that are common between a subset of user ids? For example, if I am given user_id values of 1,2,3, I expect the result set to include only booth with id 3 since it is the only common booth in the join table above between all user_id's provided.
I'm hoping I'm missing a keyword in MySQL to accompish this. The furthest I've come so far is using ... user_id = all (1,2,3) but this is always returning an empty result set (I believe I understand why it is though).
The SQL query for this will be:
select booth_id from table1 where [user_id]
in (1,2,3) group by booth_id having count(booth_id) =
(select count(distinct([user_id])) from table1 where [user_id] in (1,2,3))
If this could help you creating the MySQL query.