Can this be done with a subquery? - mysql

I have a table looking like this:
Team Name Points
A Peter 26
A John 18
A Carl 20
A Robert 32
A Mike 10
B Tom 22
B Michael 28
B Tina 18
B Donald 35
B Jeff 20
I want to get a result from the query that will give me the best 3 users from a team and the SUM of the point from the 3 highest users.
For team A the 3 highest scores are Robert (32), Peter (26) and (Carl (20) which is a total of 78 points.
For team B the highest 3 scores are Donald (35), Michael (28) and Tom (22) which is a total of 85 points
So it must be something like this:
Place Team Points
1 B 85
2 A 78
I have tried something like this:
SELECT points, user FROM table ORDER BY points DESC, LIMIT 3
That will give me the 3 users with the highest points but I want also the SUM of these 3 users and these records must be per team.
I think it must be done with a subquery, is this correct?

SELECT team,SUM(points) sp FROM
(
(
SELECT * FROM `table` WHERE team = "A" ORDER BY points DESC LIMIT 3
)
UNION ALL
(
SELECT * FROM `table` WHERE team = "B" ORDER BY points DESC LIMIT 3
)
)
AS dbx
GROUP BY team
ORDER BY sp DESC
Explaination:
Your Data:
Get Highest 3 from both Team (A and B).
And then, sum After join them All.
Result:

Related

Mysql return all results matching one column based on a value appearing at least once in another column

I'll try to explain what I need done...I have a table called 'quizzes' with data similar to this:
quiz_id
username
score
5
john
50
5
mary
75
9
mary
20
12
tom
15
12
john
13
12
anne
10
3
john
100
14
john
29
Note - there is only one person per quiz, it's like a record of 'high scores', so no person will have more than one row with a specific quiz_id.
What I want to do is pull all the results where John and at least one other person took that quiz, i.e. 'john' appears as a username and at one other person does too. So, the rows I would want returned are:
quiz_id
username
score
5
john
50
5
mary
75
12
tom
15
12
john
13
12
anne
10
As those are the only quizzes that john and at least one other person took, john didn't take 9, and only john took 3 and 14, so those aren't included either.
I've tried just SELECT quiz_id WHERE username = 'john' but obviously that only returns rows corresponding to his results.
Using a join aggregation approach we can try:
SELECT t1.quiz_id, t1.username, t1.score
FROM yourTable t1
INNER JOIN
(
SELECT quiz_id
FROM yourTable
GROUP BY quiz_id
HAVING SUM(username = 'john') > 0 AND -- john is present
SUM(username <> 'john') > 0 -- someone other than john is present
) t2
ON t2.quiz_id = t1.quiz_id
ORDER BY
t1.quiz_id;

MySQL modifying order by rand() to other methods

I am now trying to make random selections from each grouped column array, with chances followed by the weight of each row. For example, I have a table (DemoTable) like this:
http://sqlfiddle.com/#!9/23470/3/0
Name
State
Grade
Weight
John
NY
100
1
Liam
NY
90
2
Olivia
NY
90
3
Emma
NY
80
4
James
CA
10
1
Henry
CA
20
1
Mia
NJ
50
1
Ava
NJ
30
4
For State = 'NY', there are four rows with grade array: [100, 90, 90, 80] and the weight [1, 2, 3, 4], respectively. So 80 has the largest chance to be picked while 100 has the least within its State group.
I made a query for it:
SELECT a.*,
(SELECT b.Grade FROM DemoTable b WHERE a.State = b.State
ORDER BY RAND() * -b.Weight LIMIT 1) AS 'random_val' FROM DemoTable a;
and it worked with the result:
Name
State
Grade
Weight
random_val
John
NY
100
1
80
Liam
NY
90
2
80
Olivia
NY
90
3
80
Emma
NY
80
4
90
James
CA
10
1
20
Henry
CA
20
1
10
Mia
NJ
50
1
30
Ava
NJ
30
4
30
Though, I would like to know if there is any other method like join or union instead of using order by rand() alone.
Is there any other way to modify my MySQL query that gives the same result?
I've searched for solving this problem all day, but couldn't find the proper way to do so; and that's why I asked here for the aid.
I would sincerely appreciate if I could get some advice.
My first attempt using analytic functions, though I suspect yours is faster over larger datasets...
WITH
ranged AS
(
SELECT
*,
SUM(weight) OVER (PARTITION BY state ORDER BY id) - weight AS weight_range_lower,
SUM(weight) OVER (PARTITION BY state ORDER BY id) AS weight_range_upper,
SUM(weight) OVER (PARTITION BY state ) * rand() AS rand_threshold
FROM
DemoTable
)
SELECT
ranged.*,
lookup.grade AS random_grade
FROM
ranged
INNER JOIN
ranged AS lookup
ON lookup.state = ranged.state
AND lookup.weight_range_lower <= ranged.rand_threshold
AND lookup.weight_range_upper > ranged.rand_threshold
ORDER BY
ranged.id
Or, if you want all members of the same state to be given the same random_grade...
SELECT
*,
FIRST_VALUE(grade) OVER (PARTITION BY state ORDER BY weight * rand() DESC)
FROM
DemoTable
ORDER BY
id
https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=133f9e86b013a477ac342d0295132dd5

How to filter rows from an ordered table?

Here's the table. It's ordered by points (desc) and id
id name points
1 ed 10
1 ed 9
2 jim 14
2 jim 8
2 jim 4
3 mike 11
Here's the results i'm looking for:
id name points
1 ed 10
2 jim 14
3 mike 11
How can this be done? basically, i want to list only the highest point row for each name and filter other rows away.
You can try something like this: use the MAX() function
SELECT id, name, MAX(points)
FROM your_table
GROUP BY id, name
ORDER BY points desc
Try this:
select id,name,max(points) from table1 group by id

Query: Count Alphabetical wise name

I have one voter table which contain large amount of data. Like
Voter_id name age
1 san 24
2 dnyani 20
3 pavan 23
4 ddanial 19
5 sam 20
6 pickso 38
I need to show all voter_name by Alphabetically and count them.Like
name
san
sam
s...
s...
dnyani
ddanial
d...
pavan
pickso
p..
p..
I try using count(voter_name) or GROUP BY.
But both not working for me..... Suppose table contain 50 voters details.
number of person name start with A=15,b=2, c=10,y=3 and so on.
Then how to count and show first 15 record of 'A' person, next 2 record of 'B' person and so on..
Give me any reference or hint..
Thanks in Advance.
It is as simple as this,
SELECT SUBSTRING(name,1,1) as ALPHABET, COUNT(name) as COUNT
FROM voter GROUP BY SUBSTRING(name,1,1);
This order names only:
SELECT `name` FROM `voter` ORDER BY `name` ASC
This counts each occurrence of the first letter and group them group them together
ex.:
Letter COUNT
------ -------
A 15
B 2
C 10
y 3
SELECT SUBSTR(`name`,1,1) GRP, COUNT(`name`) FROM `voter` WHERE
SUBSTR(`name`,1,1)=SUBSTR(`name`,1,1) GROUP BY GRP ORDER BY GRP ASC
Here you go!
If you need names and their counts in ascending order, then you can use:
SELECT
name, COUNT(*) AS name_count
FROM
voter
GROUP BY
name
ORDER BY
name ASC
Which will give the output like
name name_count
------------------
albert 15
baby 6
...
If you need to display all records along with their counts, then you may use this:
SELECT
voter_id, name, age, name_count
FROM
(
SELECT
name, COUNT(name) AS name_count
FROM
voter
GROUP BY
name
) counts
JOIN actor
USING (name)
ORDER BY
name
and you get the output as:
voter_id name age name_count
------------------------------------
6 abraham 26 2
24 abraham 36 2
2 albert 19 1
4 babu 24 4
15 babu 53 4
99 babu 28 4
76 babu 43 4
...
Check the SUBSTRING function of MySQL here
http://dev.mysql.com/doc/refman/5.5/en/string-functions.html#function_substring
And we can use a sub-query to achieve our result.
So using that, how about this
SELECT voter_id, name, age, COUNT(*) AS alphabet
FROM
(SELECT voter_id, name, age, SUBSTRING(name, 1, 1) AS first_letter FROM voter)
AS voter
GROUP BY first_letter
ORDER BY first_letter ASC

MYSQL rating algorithm

I have a MYSQL table which stores a rating for each event of a user, 1-10 in the events table called event_rating. What i'm trying to find is the highest accurate rating based on the number of votes and rating like this:
SELECT
c.userid,
c.user_name,
COUNT(d.event_rating) AS votesCount,
AVG(d.event_rating) AS votesAvg,
SUM(d.event_rating) AS tsum,
COUNT(d.event_rating)*AVG(d.event_rating)/COUNT(d.event_rating) as totalRating
FROM events d JOIN users c ON d.userid = c.userid WHERE (d.userid = '2') GROUP BY d.userid ORDER BY totalRating DESC
I added two dummy ratings for a user, one with a rating of 10 and another with 5.
The results are below:
userid user_name votesCount votesAvg tsum totalRating
2 Rahul Khanna 2 7.5000 15 7.50000000
Is that accurate, and am i calculating it right?
--- EDIT ---
Posting Some more results
USING COUNT(d.event_rating)*AVG(d.event_rating)/COUNT(d.event_rating) as totalRating
userid user_name votesCount votesAvg tsum totalRating
2 Rahul Khanna 2 7.5000 15 7.50000000
1 Rita Agnihotri 9 4.8889 44 4.88888889
3 Daniel Springs 4 3.5000 14 3.50000000
4 Roger Myers 6 3.5000 21 3.50000000
5 Chun Tanakat 3 3.0000 9 3.00000000
USING COUNT(d.event_rating)*AVG(d.event_rating) as totalRating
userid user_name votesCount votesAvg tsum totalRating
1 Rita Agnihotri 9 4.8889 44 44.0000
4 Roger Myers 6 3.5000 21 21.0000
2 Rahul Khanna 2 7.5000 15 15.0000
3 Daniel Springs 4 3.5000 14 14.0000
5 Chun Tanakat 3 3.0000 9 9.0000
--- MORE ---
Should i be using the below instead?
COUNT(d.event_rating)*AVG(d.event_rating)/10 as totalRating
What i need is an accurate way to calculate the total rating, putting votesCount into consideration as well and that the rating has to be between 1-10.
--- MORE DETAIL ---
I have one table Users another Events, user is able to add new events and rate those events. The Events table has a eventID, userid, event_rating column. So each event can hold a rating for the event the user has created. What i want is to calculate all the events rating to get the max (total) rating for that user. I want the total rating i get to be between 1-10 and not exceed over 10 no matter how many events the user has created. Is that possible? if not any solutions or ideas?
Thanks for reading :)
What is this silly piece of query??
COUNT(d.event_rating)*AVG(d.event_rating)/COUNT(d.event_rating) as totalRating
This is nothing
(a*b)/a which is always b
you have to just fetch AVG(d.event_rating)
what do you want really ??