MySQL Group By - Top 3 rows and nth row - mysql

I have a MySQL table like this:
+------+--------+--------+
| ID | UserID | Score |
+------+--------+--------+
| 1 | 3 | 12 |
| 2 | 3 | 11 |
| 3 | 3 | 12 |
| 4 | 2 | 14 |
| 5 | 4 | 8 |
| 6 | 2 | 13 |
+------+--------+--------+
From this I want to top 3 scores from entire table and a top score from particular user
+------+--------+--------+
| ID | UserID | Score |
+------+--------+--------+
| 4 | 2 | 14 |
| 6 | 2 | 13 |
| 3 | 3 | 12 |
| 5 | 4 | 8 |
+------+--------+--------+
Is this something I can get done in a single query?
Any help is appreciated
Thanks in advance!

spoiler alert ;)
(SELECT * FROM tableA ORDER BY score DESC LIMIT 3)
UNION
(SELECT * FROM tableB WHERE UserID = 4 ORDER BY score DESC LIMIT 1);

For certain definitions of "single query", sure... If you're willing to use sub queries or a union.
The best performance will probably come from two queries, but you can join them in a UNION for convenience if you wish.

Related

sum up frags and group teams with sql query

I have a table with two teams and frag counts
| id | teamA_name | teamA_frags | teamB_name | teamB_frags |
| 1 | 5 | 3 | 7 | 9 |
| 2 | 5 | 4 | 7 | 1 |
| 3 | 3 | 2 | 6 | 4 |
| 4 | 3 | 8 | 6 | 8 |
Is it possible to sum up all frags and present this data like that?
| team | frags |
| 5 | 7 |
| 7 | 10 |
| 3 | 10 |
| 6 | 12 |
EDIT 1: I tried queries with group by and group concat, but they are not giving me the output I wanted. For example:
SELECT teamA_name, teamB_name, SUM(teamA_frags), SUM(teamB_frags) FROM Table;
This is summing up frags OK, but printing teams next to eachother. My knowledge of SQL is limited.
Basically, you need to unpivot and re-aggregate. Here is one approach:
select team, sum(frags)
from ((select teamA_name as team, teamA_frags as frags
from t
) union all
(select teamB_name as team, teamB_frags as frags
from t
)
) t
group by team;

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);

MySQL GROUP By Only when Two column matches

I am trying to group a record only if two of the fields repeat themselves.
I am designing a social sharing photo app. users can share, like and comment on thers photo. Each action (share, comment, like) will appear on their friends wall.
The Problem is that when a user do all the three actions, the picture appears three times instead of one with the three action on it.
Data in database is like this (activities_tb)
id | photoID | uiID | action | date
-------------------------------------------
1 | 1 | 2 | like | 01/01/2015
2 | 1 | 2 | share | 02/01/2015
3 | 1 | 4 | share | 03/01/2015
4 | 1 | 2 | comment | 04/01/2015
5 | 2 | 4 | like | 04/01/2015
6 | 2 | 2 | like | 05/01/2015
7 | 2 | 3 | share | 05/01/2015
8 | 2 | 4 | comment | 06/01/2015
8 | 3 | 3 | like | 07/01/2015
9 | 3 | 5 | like | 08/01/2015
10 | 3 | 5 | comment | 08/01/2015
The query result I want to get
id | photoID | uiID | action | date
-------------------------------------------
3 | 1 | 4 | share | 03/01/2015
4 | 1 | 2 | comment | 04/01/2015
6 | 2 | 2 | like | 05/01/2015
7 | 2 | 3 | share | 05/01/2015
8 | 2 | 4 | comment | 06/01/2015
8 | 3 | 3 | like | 07/01/2015
10 | 3 | 5 | comment | 08/01/2015
This is my statement
SELECT id, photoID, uiID, action, date
FROM activities_tb
GROUP BY photoID, uiID.
This combines all the photos by their id returning only three results
I will be glad if anyone can be of help, thank you
You can first select required ids and join on your table:
select tb.*
from activities_tb tb
join(select max(id) as id
from activities_tb
group by photoID, uiID) t on t.id = tb.id
You are looking for "SELECT DISTINCT"
SELECT DISTINCT photoID, uiID, action, date
FROM activities_tb
GROUP BY photoID, uiID.

mysql: order -> limit -> sum... possible?

i am loosing it over the following problem:
i have a table with participants and points. each participant can have up to 11 point entries of which i only want the sum of the top 6.
in this example lets say we want the top 2 of 3
+----+---------------+--------+
| id | participantid | points |
+----+---------------+--------+
| 1 | 1 | 11 |
+----+---------------+--------+
| 2 | 3 | 1 |
+----+---------------+--------+
| 3 | 3 | 4 |
+----+---------------+--------+
| 4 | 2 | 3 |
+----+---------------+--------+
| 5 | 1 | 5 |
+----+---------------+--------+
| 6 | 2 | 10 |
+----+---------------+--------+
| 7 | 2 | 9 |
+----+---------------+--------+
| 8 | 1 | 3 |
+----+---------------+--------+
| 9 | 3 | 4 |
+----+---------------+--------+
as a result i want something like
+---------------+--------+
| participantid | points |
+---------------+--------+
| 2 | 19 |
+---------------+--------+
| 1 | 16 |
+---------------+--------+
| 3 | 8 |
+---------------+--------+
(it should be ordered DESC by the resulting points)
is this at all possible with mysql? in one query?
oh and the resulting participant ids should be resolved into the real names from another 'partcipant' table where
+----+------+
| id | name |
+----+------+
| 1 | what |
+----+------+
| 2 | ev |
+----+------+
| 3 | er |
+----+------+
but that should be doable with a join at some point... i know...
Using one of the answers from ROW_NUMBER() in MySQL for row counts, and then modifying to get the top.
SELECT ParticipantId, SUM(Points)
FROM
(
SELECT a.participantid, a.points, a.id, count(*) as row_number
FROM scores a
JOIN scores b ON a.participantid = b.participantid AND cast(concat(a.points,'.', a.id) as decimal) <= cast(concat(b.points,'.', b.id) as decimal)
GROUP BY a.participantid, a.points, a.id
) C
WHERE row_number IN (1,2)
GROUP BY ParticipantId
Had an issue with ties until I arbitrarily broke them with the id

select random value from each type

I have two tables, rating:
+-----------+-----------+-------------+----------+
| rating_id | entity_id | rating_code | position |
+-----------+-----------+-------------+----------+
| 1 | 1 | Quality | 0 |
| 2 | 1 | Value | 0 |
| 3 | 1 | Price | 0 |
+-----------+-----------+-------------+----------+
And rating_option
+-----------+-----------+------+-------+----------+
| option_id | rating_id | code | value | position |
+-----------+-----------+------+-------+----------+
| 1 | 1 | 1 | 1 | 1 |
| 2 | 1 | 2 | 2 | 2 |
| 3 | 1 | 3 | 3 | 3 |
| 4 | 1 | 4 | 4 | 4 |
| 5 | 1 | 5 | 5 | 5 |
| 6 | 2 | 1 | 1 | 1 |
| 7 | 2 | 2 | 2 | 2 |
| 8 | 2 | 3 | 3 | 3 |
| 9 | 2 | 4 | 4 | 4 |
| 10 | 2 | 5 | 5 | 5 |
| 11 | 3 | 1 | 1 | 1 |
| 12 | 3 | 2 | 2 | 2 |
| 13 | 3 | 3 | 3 | 3 |
| 14 | 3 | 4 | 4 | 4 |
| 15 | 3 | 5 | 5 | 5 |
+-----------+-----------+------+-------+----------+
I need a SQL query (not application level, must stay in the database) which will select a set of ratings randomly. A sample result would look like this, but would pick a random value for each rating_id on subsequent calls:
+-----------+-----------+------+-------+----------+
| option_id | rating_id | code | value | position |
+-----------+-----------+------+-------+----------+
| 1 | 1 | 1 | 1 | 1 |
| 8 | 2 | 3 | 3 | 3 |
| 15 | 3 | 5 | 5 | 5 |
+-----------+-----------+------+-------+----------+
I'm totally stuck on the random part, and grouping by rating_id has been a crap shoot so far. Any MySQL ninjas want to take a stab?
Thanks,
Joe
EDIT: I've tried rand() in a bunch of combinations, and I'm sure that it will be necessary to create the randomness of the result, but I cannot figure out how to return one random row for each of the rows in rating. I cannot use order by rand() limit 1 because I need three rows, and order by rand() limit 3 won't give me one of each rating_id, which is the ultimate goal. I need a combination of rand() and either subqueries or joins so that I can ensure one of each rating_id.
Alright, a little messy, but seems to do the job. Someone may know what they're doing better than I do that can clean this up:
SELECT random.rating_id, random.rand_option_id, r3.code, r3.value, r3.position
FROM
(SELECT r.rating_id,
(SELECT r2.option_id
FROM rating_option r2
WHERE r2.rating_id = r.rating_id
ORDER BY RAND() LIMIT 1) AS 'rand_option_id'
FROM rating_option r
GROUP BY r.rating_id
) random
LEFT JOIN rating_option AS r3 ON r3.option_id = rand_option_id
Results (varies every time, of course):
+-----------+----------------+------+-------+----------+
| rating_id | rand_option_id | code | value | position |
+-----------+----------------+------+-------+----------+
| 1 | 4 | 4 | 4 | 4 |
| 2 | 6 | 1 | 1 | 1 |
| 3 | 13 | 3 | 3 | 3 |
+-----------+----------------+------+-------+----------+
You could use the rand() function to do sorting in a select on the rating table.
For example:
select rating_id from rating order by rand() limit 1
As clarified in your comments, and the other posts above
select * from rating_option order by rand()
will return all records in a random order... However, if you want only X number, then inclue that as the limit as noted by others
select * from rating_option order by rand() limit 5 (or whatever number)
Have you looked into the rand() function?
SELECT column FROM table
ORDER BY RAND()
LIMIT 1
http://www.petefreitag.com/item/466.cfm
http://dev.mysql.com/doc/refman/5.0/en/mathematical-functions.html#function_rand
Sample code
select *
from rating_option
group by rating_id
order by rand()