This question already has an answer here:
Mysql min and max values and corresponding "date" for each month
(1 answer)
Closed 8 years ago.
So I want to be able to show the most expensive movie to rent and the least expensive movie to rent. Basically I want to show the movie title along with its price. Now I am able to get the highest and lowest rental price with this query:
SELECT MAX(rental_rate) as MaxRate, MIN(rental_rate) as MinRate
FROM film;
However how do I edit that query above to show the movie titles in relation to their rates?
I have also tried:
SELECT title (SELECT MAX(rental_rate) FROM film as MaxRate),
(SELECT MIN(rental_rate) FROM film as MinRate)
FROM film;
But that did not work.
Any suggestions?
A proper solution can be found in the question I referred to in comments, but it is a bit complex. I think another, simpler solution would be to ORDER BY rate and use LIMIT to get 1 record. You can use UNION to combine two similar queries to get the lowest and highest rate:
(SELECT title, rental_rate
FROM film
ORDER BY rental_rate
LIMIT 1)
UNION
(SELECT title, rental_rate
FROM film
ORDER BY rental_rate DESC
LIMIT 1)
UNION ALL could be used too, but then you could get the same title if the table contains only one film.
Note that this query will return one lowest rate title and one highest rate title. If you want all titles that share the lowest or highest rate, you'll need that other solution.
What you want is two rows with different conditions, so keep them separate:
(SELECT title, rental_rate, "most expensive" as which_title
from film
ORDER BY rental_rate DESC LIMIT 1)
UNION ALL
(SELECT title, rental_rate, "least expensive" from film
ORDER BY rental_rate ASC LIMIT 1)
with working sqlfiddle: http://sqlfiddle.com/#!2/1e290/3
you can also use below query if you want the min and max of rates with the title of them:
select title, (SELECT MAX(rental_rate) FROM film) from film
where rental_rate=(SELECT MAX(rental_rate) FROM film)
union
select title, (SELECT MIN(rental_rate) FROM film) from film
where rental_rate=(SELECT MIN(rental_rate) FROM film)
Related
I have a table in which student marks in each subject and i have to get query in such a way that i will able to get all top 5 student in every subject who secure highest marks.
Here is a sample table:
My expected output look somthing like :
Top five student in PCM, ART, PCB on the basis of students marks,And also if two or more student secure same than those record also need to be in list with single query.
Original Answer
Technically, what you want to accomplish is not possible using a single SQL query. Had you only wanted one student per subject you could have achieved that using GROUP BY, but in your case it won't work.
The only way I can think of to get 5 students for each subject would be to write x queries, one for each subject and use UNION to glue them together. Such query will return a maximum of 5x rows.
Since you want to get the top 5 students based on the mark, you will have to use an ORDER BY clause, which, in combination with the UNION clauses will cause an error. To avoid that, you will have to use subqueries, so that UNION and ORDER BY clauses are not on the same level.
Query:
-- Select the 5 students with the highest mark in the `PCM` subject.
(
SELECT *
FROM student
WHERE subject = 'PCM'
ORDER BY studentMarks DESC
LIMIT 5
)
UNION
(
SELECT *
FROM student
WHERE subject = 'PCB'
ORDER BY studentMarks DESC
LIMIT 5
)
UNION
(
SELECT *
FROM student
WHERE subject = 'ART'
ORDER BY studentMarks DESC
LIMIT 5
);
Check out this SQLFiddle to evaluate the result yourself.
Updated Answer
This update aims to allow getting more than 5 students in the scenario that many students share the same grade in a particular subject.
Instead of using LIMIT 5 to get the top 5 rows, we use LIMIT 4,1 to get the fifth highest grade and use that to get all students that have a grade more or equal to that in a given subject. Though, if there are < 5 students in a subject LIMIT 4,1 will return NULL. In that case, we want essentially every student, so we use the minimum grade.
To achieve what is described above, you will need to use the following piece of code x times, as many as the subjects you have and join them together using UNION. As can be easily understood, this solution can be used for a small handful of different subjects or the query's extent will become unmaintainable.
Code:
-- Select the students with the top 5 highest marks in the `x` subject.
SELECT *
FROM student
WHERE studentMarks >= (
-- If there are less than 5 students in the subject return them all.
IFNULL (
(
-- Get the fifth highest grade.
SELECT studentMarks
FROM student
WHERE subject = 'x'
ORDER BY studentMarks DESC
LIMIT 4,1
), (
-- Get the lowest grade.
SELECT MIN(studentMarks)
FROM student
WHERE subject = 'x'
)
)
) AND subject = 'x';
Check out this SQLFiddle to evaluate the result yourself.
Alternative:
After some research I found an alternative, simpler query that will yield the same result as the one presented above based on the data you have provided without the need of "hardcoding" every subject in its own query.
In the following solution, we define a couple of variables that help us control the data:
one to cache the subject of the previous row and
one to save an incremental value that differentiates the rows having the same subject.
Query:
-- Select the students having the top 5 marks in each subject.
SELECT studentID, studentName, studentMarks, subject FROM
(
-- Use an incremented value to differentiate rows with the same subject.
SELECT *, (#n := if(#s = subject, #n +1, 1)) as n, #s:= subject
FROM student
CROSS JOIN (SELECT #n := 0, #s:= NULL) AS b
) AS a
WHERE n <= 5
ORDER BY subject, studentMarks DESC;
Check out this SQLFiddle to evaluate the result yourself.
Ideas were taken by the following threads:
Get top n records for each group of grouped results
How to SELECT the newest four items per category?
Select X items from every type
Getting the latest n records for each group
Below query produces almost what I desired, may this query helps others in future.
SELECT a.studentId, a.studentName, a.StudentMarks,a.subject FROM testquery AS a WHERE
(SELECT COUNT(*) FROM testquery AS b
WHERE b.subject = a.subject AND b.StudentMarks >= a.StudentMarks) <= 2
ORDER BY a.subject ASC, a.StudentMarks DESC
This is some sorting: I have a table with ids, names and ratings. I want to list the 10 best items based on ratings, that's fine:
SELECT id FROM items ORDER BY ratings DESC LIMIT 10
But now here comes the hard part: I want to list the 10 best items based on ratings but order them alphabetically. I tried
SELECT id FROM items ORDER BY ratings DESC, names ASC LIMIT 10
and
SELECT id FROM items ORDER BY names ASC, ratings DESC LIMIT 10
but neither gives the desired result.
You could use a subquery:
SELECT *
FROM (
SELECT id, names
FROM items
ORDER BY ratings DESC
LIMIT 10
) t
ORDER BY names
EDIT: Further Explanation
Your original query sorts by ratings DESC, and then by names -- it would only sort the names with the same ratings. So if two items had the same rating, then you'd get those 2 sorted by name. It's going to sort all your records by rating first, and then by name afterwards (within the same ratings).
SELECT id, name, rating
FROM
(SELECT id, name, rating FROM items ORDER BY ratings LIMIT 10) t
ORDER BY name
This will take top 10 by rating, and then sort by name.
Your queries are incorrect because: They sorts rows by names and then by ratings (or in oposite order), taking top10 after the sort is performed. You need to make the first sort, take top 10 and then sort these 10 results using second column values.
So i need to select the city with highest and lowest population in the same query using a Union statement... I have tried almost every answer on the site, google, mysql.com and mysql tutorials... nothing works so
this is my code
(select name, population from city order by population asc limit 1)
union
( select name, population from city order by population desc limit 1)
it is not working obviously, I dont want the answer, I just need to understand why it isnt working and what to fix please and thanks
I have a voting application that writes values to a mysql db table. It is a preference/weighted voting system so people choose a first option, second option, and third option. These all go into separate fields in the table. I'm looking for a way to write a query that will assign numerical values to the responses (3 for a first response, 2 for a second, 1 for a first) and then display the value with the summed score. I've been able to do this for total number of votes
select count(name) as votes,name
from (select 1st_option as name from votes
union all
select 2nd_option from votes
union all
select 3rd_option from votes) as tbl
group by name
having count(name) > 0
order by 1 desc;
but haven't quite figured out how to assign values to response in each column and then pull them together. Any help is much appreciated. Thanks!
You could do something like this:
select sum(score) as votes,name
from (select 1st_option as name, 3 as score from votes
union all
select 2nd_option as name, 2 as score from votes
union all
select 3rd_option as name, 1 as score from votes) as tbl
group by name;
I have a table containing news posts and would like to get the entire last added newspost of every category.
The table contains these columns:
id, title, images, description, category, date
Example: I have 20 posts in 3 categories. The last post by date of every category is returned so I get 3 posts back.
You want the groupwise maximum:
SELECT newsposts.* FROM newsposts NATURAL JOIN (
SELECT category, MAX(date) AS date FROM newsposts GROUP BY category
) t
think the smallest and most usable solution for this is that one:
SELECT * FROM (
SELECT * FROM table ORDER BY date DESC
) as t
GROUP BY t.category;
an other approach will be the group having with subquery...
#eggyal:
This will use the LASTEST inserted with max_date, because of the internal sortorder of the rdbms...