This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
sql to select top 10 records
Assuming you have one table with StuId, StuName, Subject, Grade. You are required to provide a subquery to return a list of honor students (top 10 percent), sorted by their grade point average.
for example, if I have 10 student whose average grade is 100,90,80,...10.
It is required to output the first student name whose average is 100. Only one student grade is output. So I can't use limit 10
I am using mysql 5.1.
Here is my query:
SELECT Stuname, TOP 10 Avg(Grade) as GPA
FROM Table
GROUP BY Stuid
ORDER BY GPA
The query is not correct because of the TOP 10. Checking MYSQL 5.1 reference, it does not support top 10.
According to comments, I dont think it can be resolved using one query, so I come up with a method:
F(conn){
Statement stmt;
int top10percnet = 0;
try{
stmt = conn.createStatement;
String query = "select CEIL(count(stuname)*10/100) as 10percent from grades";
ResultSet rs = stmt.execute(query);
while(rs.next()){
top10percent = rs.getString("10percent");
}
query = "select stuname, avg(grade) as average from grades group by stuname order
by average desc limit " + Integer.toString(top10percnet);
rs=stmt.execute(query);
while(rs.next()){
...// output result
}
}
catch(SQLException e){
}
}
count = select CEIL(count(Stuname)*10/100) from table_name;
select Stuname from table_name ORDER BY GPA DESC limit count;
First query will return the 10% of the students.CEIL is used to convert it into integer.
Second query is to retrieve the data.
The count calculated from the first query is set as the limit to the second query.
Use LIMIT and DESC order (ie highest to lowest):
select Stuname, Avg(Grade) as GPA
from Table
group by Stuid
order by 1 DESC -- Add DESC
LIMIT 10 -- Add LIMIT
Update
Sounds like you want to incorporate a HAVING clause to limit the results to those scoring an average grade higher than 90.
Try
SELECT Stuid, Stuname, AVG(Grade) AS GPA FROM Table
GROUP BY Stuid, Stuname
HAVING AVG(GRADE) > 90
ORDER BY GPA DESC -- If you want highest-to-lowest. Thanks Bohemian
TOP is SQL Server 2000+ specific; MySQL uses the LIMIT syntax -- neither are ANSI, only recently was the FETCH FIRST 10 ROWS ONLY made ANSI (DB2 is the only DB I know of that supports it).
Because you tagged the question as "mysql":
SELECT t.stuname,
AVG(t.grade) AS grade_avg
FROM TABLE t
GROUP BY t.stuname
ORDER BY grade_avg DESC
LIMIT 10
For SQL Server 2000+, the query would be:
SELECT TOP 10
t.stuname,
AVG(t.grade) AS grade_avg
FROM TABLE t
GROUP BY t.stuname
ORDER BY grade_avg DESC
TOP is always before the columns in the SELECT clause. As of SQL Server 2005+, you can use brackets around the top value to allow you use a variable instead:
DECLARE #int_var INT
SET #int_var = 10
SELECT TOP (#int_var)
t.stuname,
AVG(t.grade) AS grade_avg
FROM TABLE t
GROUP BY t.stuname
ORDER BY grade_avg DESC
This allows you dynamically set the TOP without requiring dynamic SQL.
Have you tried using LIMIT instead?
e.g.
select Stuname, Avg(Grade) as GPA from Table group by Stuid order by GPA limit 10
Related
I have a mysql query which will return all the details from table along with i need max_row count i.e total no of rows in a table using COUNT(*) in a single select query without using cross join.
Note: MySQL version is earlier version of 8
Query :
SELECT * FROM tablename ORDER BY column name DESC LIMIT 0,10;
The total count of a table is simple, when you want to add it to every row.
SELECT
*
,(SELECT COUNT(*) FROM tablename ) count1
FROM tablename
ORDER BY column name
DESC LIMIT 0,10;,
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
How can I find the most frequent value in a given column in an SQL table?
For example, for this table it should return two since it is the most frequent value:
one
two
two
three
SELECT
<column_name>,
COUNT(<column_name>) AS `value_occurrence`
FROM
<my_table>
GROUP BY
<column_name>
ORDER BY
`value_occurrence` DESC
LIMIT 1;
Replace <column_name> and <my_table>. Increase 1 if you want to see the N most common values of the column.
Try something like:
SELECT `column`
FROM `your_table`
GROUP BY `column`
ORDER BY COUNT(*) DESC
LIMIT 1;
Let us consider table name as tblperson and column name as city. I want to retrieve the most repeated city from the city column:
select city,count(*) as nor from tblperson
group by city
having count(*) =(select max(nor) from
(select city,count(*) as nor from tblperson group by city) tblperson)
Here nor is an alias name.
Below query seems to work good for me in SQL Server database:
select column, COUNT(column) AS MOST_FREQUENT
from TABLE_NAME
GROUP BY column
ORDER BY COUNT(column) DESC
Result:
column MOST_FREQUENT
item1 highest count
item2 second highest
item3 third higest
..
..
For use with SQL Server.
As there is no limit command support in that.
Yo can use the top 1 command to find the maximum occurring value in the particular column in this case (value)
SELECT top1
`value`,
COUNT(`value`) AS `value_occurrence`
FROM
`my_table`
GROUP BY
`value`
ORDER BY
`value_occurrence` DESC;
Assuming Table is 'SalesLT.Customer' and the Column you are trying to figure out is 'CompanyName' and AggCompanyName is an Alias.
Select CompanyName, Count(CompanyName) as AggCompanyName from SalesLT.Customer
group by CompanyName
Order By Count(CompanyName) Desc;
If you can't use LIMIT or LIMIT is not an option for your query tool. You can use "ROWNUM" instead, but you will need a sub query:
SELECT FIELD_1, ALIAS1
FROM(SELECT FIELD_1, COUNT(FIELD_1) ALIAS1
FROM TABLENAME
GROUP BY FIELD_1
ORDER BY COUNT(FIELD_1) DESC)
WHERE ROWNUM = 1
If you have an ID column and you want to find most repetitive category from another column for each ID then you can use below query,
Table:
Query:
SELECT ID, CATEGORY, COUNT(*) AS FREQ
FROM TABLE
GROUP BY 1,2
QUALIFY ROW_NUMBER() OVER(PARTITION BY ID ORDER BY FREQ DESC) = 1;
Result:
Return all most frequent rows in case of tie
Find the most frequent value in mysql,display all in case of a tie gives two possible approaches:
Scalar subquery:
SELECT
"country",
COUNT(country) AS "cnt"
FROM "Sales"
GROUP BY "country"
HAVING
COUNT("country") = (
SELECT COUNT("country") AS "cnt"
FROM "Sales"
GROUP BY "country"
ORDER BY "cnt" DESC,
LIMIT 1
)
ORDER BY "country" ASC
With the RANK window function, available since MySQL 8+:
SELECT "country", "cnt"
FROM (
SELECT
"country",
COUNT("country") AS "cnt",
RANK() OVER (ORDER BY COUNT(*) DESC) "rnk"
FROM "Sales"
GROUP BY "country"
) AS "sub"
WHERE "rnk" = 1
ORDER BY "country" ASC
This method might save a second recount compared to the first one.
RANK works by ranking all rows, such that if two rows are at the top, both get rank 1. So it basically directly solves this type of use case.
RANK is also available on SQLite and PostgreSQL, I think it might be SQL standard, not sure.
In the above queries I also sorted by country to have more deterministic results.
Tested on SQLite 3.34.0, PostgreSQL 14.3, GitHub upstream.
Most frequent for each GROUP BY group
MySQL: MySQL SELECT most frequent by group
PostgreSQL:
Get most common value for each value of another column in SQL
https://dba.stackexchange.com/questions/193307/find-most-frequent-values-for-a-given-column
SQLite: SQL query for finding the most frequent value of a grouped by value
SELECT TOP 20 WITH TIES COUNT(Counted_Column) AS Count, OtherColumn1,
OtherColumn2, OtherColumn3, OtherColumn4
FROM Table_or_View_Name
WHERE
(Date_Column >= '01/01/2023') AND
(Date_Column <= '03/01/2023') AND
(Counted_Column = 'Desired_Text')
GROUP BY OtherColumn1, OtherColumn2, OtherColumn3, OtherColumn4
ORDER BY COUNT(Counted_Column) DESC
20 can be changed to any desired number
WITH TIES allows all ties in the count to be displayed
Date range used if date/time column exists and can be modified to search a date range as desired
Counted_Column 'Desired_Text' can be modified to only count certain entries in that column
Works in INSQL for my instance
One way I like to use is:
select *<given_column>*,COUNT(*<given_column>*)as VAR1 from Table_Name
group by *<given_column>*
order by VAR1 desc
limit 1
This question already has answers here:
Get most common value for each value of another column in SQL
(9 answers)
Closed 8 years ago.
I'm pretty new to SQL (I'm using MySQL) and need some help. I'm currently trying to select the most common age(s) from a table called PERSON. Suppose PERSON has an AGE column which has values: 10, 10, 20, 20, 30. The query should return the values 10 and 20.
The following query only retrieves the top row (20):
SELECT AGE FROM PERSON GROUP BY AGE ORDER BY COUNT(*) DESC LIMIT 1;
My other thought was to try something like:
SELECT AGE FROM PERSON GROUP BY AGE HAVING COUNT(AGE) = MAX(COUNT(AGE));
This returns an error, stating that it is invalid use of group function.
Any help would be greatly appreciated. Thanks!
This will do:
select age from persons
group by age
having count(*) = (
select count(*) from persons
group by age
order by count(*) desc
limit 1)
SELECT *, COUNT(AGE) as age_count
FROM PERSON
GROUP BY AGE
ORDER BY age_count DESC
LIMIT 1
Can't test it here but it should work.
WITH x AS (
SELECT age, COUNT(*) numOfAge
FROM person
GROUP BY age
)
SELECT age
FROM x
WHERE numOfAge = ( SELECT MAX(numOfAge) FROM x)
ORDER BY age
im stuck here and i don't know how to fix it.
I have a db table which has users ID, user grade and date when someone has voted for that user (3 fields).
Im trying to read the user that has the highest average grade for todays date, limited to one.
But the problem is that i want to read only users that have 5 or more votes.
My query looks like this, but im getting an error:
SELECT
idusers,
AVG(votes) AS Grade
FROM rank
WHERE (data = '{$dbDate}')
AND ((SELECT count(ID) + 1 FROM rank) AS tmpcount WHERE tmpcount>4)
GROUP BY idusers
ORDER BY Grade DESC
LIMIT 1
Without the tmpcount>4 clause this query is working ok, but I need to count the Id's.
You have to use HAVING to filter the result set on aggregated values such as COUNT (SUM, MIN, MAX, AVG, …):
SELECT idusers, AVG(votes) AS Grade
FROM rank
WHERE (data = '{$dbDate}')
GROUP BY idusers
HAVING COUNT(*) > 4
ORDER BY Grade DESC
LIMIT 1