Calculate number of people over average - sql

I am trying to calculate how many people have a grade higher than average.
What I have currently instead returns the number of students and when I delete "=" from ">=" it returns 0.
SELECT count(*)
FROM data.students
WHERE grade IN (SELECT grade
FROM data.students
GROUP BY grade HAVING grade >= AVG(grade));
If I put an integer instead of avg() function I get good results.
What am I doing wrong?

Computing the avg in a subquery is probably fastest:
SELECT count(*)
FROM data.students
WHERE grade > (SELECT avg(grade) FROM data.students);
> instead of >=, since you said "a grade higher than average".
What am I doing wrong?
In your subquery, GROUP BY grade aggregates to one row per distinct value of grade. avg(grade) is bound to be exactly the same as grade for every row (except grade IS NULL). Explains what you saw.
Your query was needlessly complex to begin with.

Try this :
SELECT count(*)
FROM (
SELECT grade >= AVG(grade) OVER () AS tst
FROM data.students
) AS a
WHERE a.tst= True

Related

can you explain the logic of this query

I have this query that finds the name of the teacher with the 4-th highest salary. I don't understand this part
SELECT COUNT (DISTINCT T2.salary)
FROM teacher as T2
WHERE T2.salary > T1.salary
) = 3
from
SELECT name
FROM teacher as T1
WHERE (
SELECT COUNT (DISTINCT T2.salary)
FROM teacher as T2
WHERE T2.salary > T1.salary
) = 3;
The way I understand count is that it gives a final result, not that we can interrupt its work by specifying a number.
This is the teacher table: https://imgur.com/a/tZVk1O8
(I couldn't upload it here due to a server error)
Focusing on the subquery:
SELECT COUNT(DISTINCT T2.salary)
FROM teacher AS T2
WHERE T2.salary > T1.salary
This will return the count of distinct teachers having a salary greater than the teacher, in each row of the teacher table. Asserting that this count be equal to 3 means that any matching teacher would have the 4th highest salary (since first 3 positions excluded).
Note that your logic should behave identically to DENSE_RANK. You could also have used:
WITH cte AS (
SELECT *, DENSE_RANK() OVER (ORDER BY salary DESC) rnk
FROM teacher
)
SELECT name
FROM cte
WHERE rnk = 4;
I wouldn't write it that way, but what it does is count, for each teacher, how many salaries are higher than his/her salary.
If 3 salaries are higher than a given teacher's salary then that teacher must be ranked 4th.
The performance of this query will be disastrous with large tables. You should use the rank window function instead.

Oracle WHERE Clause/Searching

I'm a beginner to oracle. In recent search I've seen WHERE N-1,3-2 ..so on.
How does it work in searching data?
This is my code attemtp so far:
SELECT name, salary
FROM #Employee e1
WHERE N-1 = (SELECT COUNT(DISTINCT salary) FROM #Employee e2
WHERE e2.salary > e1.salary)
It's a classic( and pretty old ) SQL query to get nth highest salary. I assume It is no longer used( I haven't seen ) in any production codes, but could be a favourite question among the interviewers.
The N you are referring to is not a column or some unknown entity but a placeholder which should translate to a valid integer or bind argument in the working query. It is a correlated subquery, a subquery that is evaluated once for each row processed by the outer query. The way it works is that it takes a count of distinct list of salary values from employees that have a salary greater than each one of employees coming from the outer query and restricts the result where that count is equal to N-1.Which means you get those rows with nth highest salaries.
A more commonly used way to do this would be to use analytic function dense_rank() ( or rank depending on your need ). Read the documentation for these functions in case you aren't aware of them.
SELECT first_name,
salary
FROM (
SELECT e.*,
dense_rank() OVER(
ORDER BY salary desc
) rn
FROM employees e
)
WHERE rn = 6; -- ( n = 6 )
In Oracle 12c and higher versions, even though the above query works, a handy option to use is the FETCH..FIRST syntax.
SELECT *
FROM employees
ORDER BY salary DESC OFFSET 6 ROWS FETCH FIRST 1 ROWS WITH TIES; --n=6

Average grade in sql server manager studio (SSMS)

I have to calculate students with average grades bigger than 8 .
select students FROM table1
GROUP BY students
HAVING AVG(grade)>8;
When i run the code it doesn't get anything in return , no error , nothing , just column students with no values. I checked table1 to see if there're enough values to calculate and the values are there.
What is wrong with that , can you help me ?
You need to include the grade in your select statement. You can also provide a more accurate column name with as:
SELECT students, AVG(grade) as 'average'
FROM table1
GROUP BY Students
HAVING AVG(grade) > 8
The SELECT includes the values you want to see, while the HAVING filters the results down.
SELECT students, AVG(grade) "Average Grade" FROM table1
GROUP BY students
HAVING AVG(grade)>8;

Is this sql query correct? If incorrect how can I fix it?

Schema:
Student(studentid,name,age)
Course(coursename,dept)
enroll(studentid,course,grade)
I need to find , for students in each age group find their average grade for courses they have taken for Political Science and History, and return the names of student with max average grade for each age group
My attempt so far is :
select max(grade), age, name
from (
select name, age, grade
from student s, (
select avg(grade) as grade, e.studentid
from enroll e
where dname in ('Political Sciences', 'History')
group by studentid
) as temp
where s.studentid = temp.studentid
) temp1
group by temp1.age;
I want to know if logically it is correct, and not syntactically.
Here's a few tips regarding your query:
Be careful with your table aliases. Make sure that you carry them over to your SELECT
You can only include columns in your SELECT that are being used in your aggregate (GROUP BY). Therefore, you can't GROUP BY temp1.age and SELECT age, name
The logic behind your SQL looks solid to me, so long as "Age" correlates to "Age Group", and does not refer to the individual student's age.

How to group in fixed count ranges?

Let's say I have one table with two columns (student_id,grade).
student_id is an integer and grade is a decimal number.
In case I have 1000 students and want to group them ordered by grade in groups of 10 students each.
Just to be clear, this should produce 100 groups. The first group cointains the 10 highest grades and the last group contains the 10 lowest grades.
How should I do that ?
Optimization is always welcome.
Thank you very much.
Joao
ntile will give a ranking by an amount of buckets.
select student_id, ntile(100) over (order by grade desc) from student