I've been using the following code, given to me by HansUp (cheers!), and it's been working great:
SELECT g.ID, Count(t.Grade) AS Total
FROM grade AS g
LEFT JOIN (SELECT Grade FROM telephony WHERE [Date] BETWEEN #08/16/2010# AND #08/20/2010#) AS t ON g.ID=t.Grade
GROUP BY g.ID
ORDER BY 2 DESC;
I'm now looking to find the TOP 5 results returned. I thought it would be as simple as:
SELECT **TOP 5** g.ID, Count(t.Grade) AS Total
FROM grade AS g
LEFT JOIN (SELECT Grade FROM telephony WHERE [Date] BETWEEN #08/16/2010# AND #08/20/2010#) AS t ON g.ID=t.Grade
GROUP BY g.ID
ORDER BY 2 DESC;
Unfortunately that's not working.
Does anyone have any ideas.
Thanks
The TOP clause will get you the top based on your first sort field. Since your first sort field is a constant (2) for all records, you get all records. Add the ID field to your ORDER BY clause and you'll only get five records.
SELECT TOP 5 g.ID, Count(t.Grade) AS Total
FROM grade AS g LEFT JOIN (SELECT Grade FROM telephony WHERE [Date] BETWEEN #08/16/2010# AND #08/20/2010#) AS t ON g.ID = t.Grade
GROUP BY g.ID
ORDER BY g.ID, 2 DESC;
If you're actually after the top 5 by Total in descending order, change the SQL to the following:
SELECT TOP 5 g.ID, Count(t.Grade) AS Total
FROM grade AS g LEFT JOIN (SELECT Grade FROM telephony WHERE [Date] BETWEEN #08/16/2010# AND #08/20/2010#) AS t ON g.ID = t.Grade
GROUP BY g.ID
ORDER BY Count(t.Grade) DESC , 2 DESC;
This is top by value, so if multiple records have a total that is the same and it happens to be in the top 5 value of Total, you'll get them all back. If you truly only ever want five records back, you have to sort on a field that is unique.
This should work.
SELECT TOP 5 g.ID, Count(t.Grade) AS Total
FROM grade AS g
LEFT JOIN (SELECT Grade FROM telephony WHERE [Date] BETWEEN #08/16/2010# AND #08/20/2010#) AS t ON g.ID=t.Grade
GROUP BY g.ID
ORDER BY 2 DESC
So far as I can see, this should work:
SELECT TOP 5 g.ID, Count(t.Grade) AS Total
FROM grade AS g
LEFT JOIN (SELECT Grade FROM telephony WHERE [Date] BETWEEN #08/16/2010# AND #08/20/2010#) AS t ON g.ID=t.Grade
GROUP BY g.ID
ORDER BY Count(t.Grade) DESC;
The key point here is that you use the full expression from the SELECT statement when you want to use it in a WHERE or ORDER BY clause.
If you'd just use the Access query grid to write your SQL, you would have gotten the correct results right off the bat (though you'd have to dip into SQL view to write your subquery).
Related
I have 3 tables with the following values and the question is : Find the name of the instructor with the highest total salary along with the names of the dancers he trains.
I was thinking something like :
Select Instructor.name, Dancer.name
FROM Instructor, Dancer, Info
WHERE Instructor.i_ID=Info.ints_id
AND Dancer.d_ID=Info.danc_id
GROUP BY Info.inst_id, Info.danc_id
ORDER BY SUM(Info.salary)
DESC LIMIT 2;
But the output is not right and also I am not suppose to know how many dancers every instructor has, so DESC LIMIT 2 is definitely wrong.
Join properly the tables and group by instructor to get the total salary for each.
Then sort descending by the total salary and keep only the 1st row.
With group_concat() you get the names of the dancers as a comma separated list:
select i.name,
sum(n.salary) total_salary,
group_concat(d.name) dancers
from instructor i
inner join info n on n.inst_id = i.i_id
inner join dancer d on d.danc_id = d.d_id
group by i.i_id, i.name
order by total_salary desc limit 1
Note that this query will return only 1 row, so if there are 2 instructors with the same top total salary you will get only 1.
If you want in the results ties in the top salary then use a HAVING clause:
select i.name,
sum(n.salary) total_salary,
group_concat(d.name) dancers
from instructor i
inner join info n on n.inst_id = i.i_id
inner join dancer d on d.danc_id = d.d_id
group by i.i_id, i.name
having total_salary = (select sum(salary) from info group by inst_id order by sum(salary) desc limit 1)
Try This:
select tab3.name "Instructor",tab2.name "Dancer"
from info tab1
inner join
dancer tab2 on tab1.dance_id=tab2.d_id
inner join
(select t1.inst_id,t2.name, sum(t1.salary) as "total_salary" from info t1
inner join instructor t2
on t1.inst_id=t2.i_id
group by t1.inst_id,t2.name
order by total_salary desc limit 1) tab3
on tab3.inst_id=tab1.inst_id
DB-FIDDLE
well it's a bit odd relation table but you could try something like this
SELECT
ins.name,
SUBSTRING_INDEX(GROUP_CONCAT(inf.salary ORDER BY inf.salary DESC),',',1) salary,
SUBSTRING_INDEX(GROUP_CONCAT(d.name ORDER BY inf.salary DESC),',',1) dancer_name
FROM Instructor ins
JOIN Info inf ON (ins.i_ID=inf.inst_id)
JOIN Dancer d on (d.d_ID=danc_id)
GROUP BY ins.i_ID
LIMIT 1;
So i would like to make a toplist in mysql.
I have two table, users and teams.
In users I have: id,name,points,teamid
In teams I have: t_id,teamname,leaderid
I would like to make a toplist. The 10 teams with the most points.
I hope it is understandable what I want.
You need to calculate the total sum of points by using the subquery which will give you the top 10 points then join this result with a query which has team information with the sum of points for each team,from this approach if there is tie in scores of 2 teams they will be included in top 10 teams regarding the points
select t2.* from
(select t.*,sum(u.points) allpoints
from teams t
join users u
on(t.t_id= u.teamid)
group by t.t_id
) t2
join
(select sum(points) allpoints
from users
group by teamid
order by allpoints desc
limit 10) tp
on(t2.allpoints = tp.allpoints )
if you don't care for tie scenario you can simply use limit and order by
select t.*,sum(u.points) allpoints
from teams t
join users u
on(t.t_id= u.teamid)
group by t.t_id
order by allpoints desc
limit 10
I have a problem similar to this question but a bit more complicated and I'm having trouble figuring out how to do it efficiently. Given two tables, one for a list of athletes and one with a list of races they've run in, e.g.,
ATHLETES
id
name
gender
details
RACES
athlete_id
year
points
I want to rank all of the athletes by gender for a given period of years using only their top 4 race finishes (where "top" is defined by points). I feel like I should be able to do this in a subquery but I can't figure out how to reference the outer query from the inner. What I have now looks like this:
SELECT SUM(points) as points, a.* FROM
(SELECT rr.points, inner_a.id as athlete_id
FROM athletes_raceresult rr
INNER JOIN athletes_athlete inner_a ON rr.athlete_id = inner_a.id
WHERE inner_a.gender ='m' AND rr.year BETWEEN 2012 AND 2014
AND inner_a.id = a.id
ORDER BY rr.points DESC) as races
INNER JOIN athletes_athlete a ON races.athlete_id = a.id
GROUP BY races.athlete_id
ORDER BY points DESC
But that doesn't limit the points to 4 rows per athlete. It looks like I want a correlated subquery, but I can't get that to work.
The following SQL Fiddle example illustrates how this can be done:
SELECT SUM(rr.points), a.id
FROM athletes_raceresult AS rr
INNER JOIN athletes_athlete AS a ON rr.athlete_id = a.id
WHERE (
SELECT count(crr.points)
FROM athletes_raceresult AS crr
INNER JOIN athletes_athlete AS ca ON crr.athlete_id = ca.id
WHERE ca.gender = 'm'
AND crr.year BETWEEN 2012 AND 2014
AND crr.athlete_id = a.id AND crr.points >= rr.points
) <= 4
AND a.gender = 'm'
AND rr.year BETWEEN 2012 AND 2014
GROUP BY a.id
Each student has some scores (and each score has student_id column).
I want to calculate student average, compare his average with other student, and find his position in his class.
Is it possible to find his position based on his average with 1 query? (may contains subqueries or joins)
I can sort all students by their average by this query:
SELECT s.*
FROM
scores s LEFT JOIN lessons lesson
ON lesson.id = s.lesson_id
WHERE lesson.display = 1
GROUP BY s.student_id
ORDER BY AVG(s.score) DESC
but it needs processing with PHP array_search function. (I think using MySQL functions is better, in this situation)
select student_id, AVG(scores) as 'average' from lessons as l, scores as s
where lessons.id = s.lesson_id and lesson.display = 1
GROUP BY s.student_id order by average desc`
Try this query
sample http://sqlfiddle.com/#!2/4fb8d/1
Hope this helps
select s.id, AVG(l.scores) as average from lessons as l, student as s
where l.id = s.lessonid and l.display = 1
GROUP BY s.id order by average desc
can solve your problem
Check this link
Thanks to Meherzad's sql query
I think you are looking for something like this:
SELECT COUNT(DISTINCT average)
FROM (
SELECT AVG(score) as average
FROM scores INNER JOIN lessons
ON scores.lesson_id = lessons.id
WHERE display=1
GROUP BY student_id
) sub_scores
WHERE average >= (SELECT AVG(score)
FROM scores INNER JOIN lessons
ON scores.lesson_id = lessons.id
WHERE display=1
AND student_id=1)
In the subquery sub_scores I'm calculating all averages of all students, in the outer query I'm calculating the number of distinct averages bigger than the average of student 1.
This will return the position of student 1.
Depending on what you are after, you might want to remove DISTINCT clause.
See this fiddle.
You need to use a user defined variable over the result set.
Try this:
SELECT *, (#rank := if(#rank is null, 1, #rank + 1)) as rank
FROM (SELECT s.*
FROM scores s
LEFT JOIN lessons lesson ON lesson.id = s.lesson_id
WHERE lesson.display = 1
GROUP BY s.student_id
ORDER BY AVG(s.score) DESC
) x
I have this php/sql Query:
$result = mysql_query("
SELECT r.item_id, AVG(rating) AS avgrating, count(rating) AS count, i.item, c.category
FROM ratings AS r
LEFT JOIN items AS i
ON r.item_id = i.items_id
INNER JOIN master_cat c
ON c.cat_id = i.cat_id
GROUP BY item_id
ORDER BY avgrating DESC
LIMIT 25;");
When I output this, count is correct, it shows how much votes certain items have received.
I simply want to add a WHERE count >= 10 clause but everything breaks. Obviously, when there are thousands of items, some will get one vote and have 100%. But that is not a good indicator. I want to print out items that have at least 10 votes (or count >= 10)
You should to use having instead where
SELECT
r.item_id, AVG(rating) AS avgrating,
count(rating) AS count, i.item, c.category
FROM
ratings AS r
LEFT JOIN items AS i
ON r.item_id = i.items_id
INNER JOIN master_cat c
ON c.cat_id = i.cat_id
GROUP BY
item_id
HAVING
count >= 10
ORDER BY
avgrating DESC
LIMIT 25;
You can't use a where filter on the results of an aggregate function (count()). where is applied at the row-level, as the DB is deciding whether to include the row or not in the result set - at this point the results of the count aren't available yet.
What you want is a having clause, which is applied as one of the last steps before results are sent to the client, after all the aggregate results have been calculated.
...
GROUP BY item_id
HAVING count > 10
ORDER BY ...
you need to tell it what you want to count
having count(*) > 10