SQL finding the maximum of all averaged results - sql

I have the relation instructor(ID, name, dept_name, salary).
How would I go about finding the name of the department with the highest average salary?

looks like a job for the HAVING clause

will this do the trick?
select top 1 id, name, avg (salary)
from instructor
group by id, name
order by avg (salary) desc

Given the homework tag, I won't spell it out for you, but you want to look into the AVG function and the GROUP BY clause.

select top 1 dept_name, avg(salary) as AvgSalary
from instructor
group by dept_name
order by AvgSalary desc

This will get you both if two deparments have the same average salary, use rownum=1 if this is not needed.
with averages as (select dept_name,avg(salary) aver from instructor group by dept_name)
select dept_name
from averages
where aver = (select max(aver) from averages)

Related

Find avg of Salary , Departmnent wise , SQL

I would like to find the avg salary from the below table, department wise without a join. The result should have Name, Age, Department, and avg_salary per department
Using a self join as below, is one way I can get the desired output. WOuld like to know option without using a self join.
SELECT name,age, department,avg.avg_salary
FROM Table1
LEFT JOIN
(SELECT department, avg(salary) as avg_salary
FROM Table1 GROUP by department) avg
ON avg.department = table1.department
No platform tagged, but I think most platforms have window functions that you can use like so:
Average Salary Using AVG() Window Function
SELECT name
,age
,department
,AVG(salary) OVER (PARTITION BY department) AS avg_salary
FROM Table1

min(count()) function not working

I want to display the name of the departments that has the least student count. This is my query:
select department_name, count(student_id)
from department d, student s
where d.department_id = s.department_id
group by department_name;
This query works fine and shows student count, but when I add the min function as min(count(student_id)), it fails with:
ERROR at line 1: ORA-00937: not a single-group group function
I don't know what I am doing wrong. Any help/suggestion?
As others have noted, when you wrapped the count in MIN that would have been getting the min PER DEPARTMENT. Because there is already only one row per department, this is a non-operation
What you say you want is a min over ALL DEPARTMENTS. Something like this:
Select department_name from(
select department_name, count(student_id), rank() over(order by count(student_id)) as x
from department d, student s
where d.department_id = s.department_id
group by department_name
)
Where x = 1
How it works? The rank() function assigns a position to rows in order, like winning a race. In this case the order is ascending count() of students, hence the minimum count is in position 1. What is special with rank is that rows with equal counts have an equal rank. We thus know that all rows that are ranked 1 are all equally the minimum count. To show only rows that are =1 we have to use a subquery, alas (I know you didn't want to see it) because oracle doesn't let us say something like where rank() over(...) =1. The subquery isn't really a performance penalty though, because the ranking is prepared at the same time as the rest of the data is single scanned, and then this passes through the filter of the outer where clause. This is different to the other posted answer that uses HAVING.. in that case the query is run, all the counts are found, the min of them all is found, then the query is run again, the counts are found again, and then the HAVING filters them down to the min that was found before
In this case, MIN() function works before GROUP BY function. So error came. You can try this.
SELECT TOP 1 department_name,count(student_id) as A
FROM department d,student s
WHERE d.department_id=s.department_id
GROUP BY department_name
ORDER BY A DESC
If I understand correctly, you need to find the department that has least number of students. Below query can give you the answer.
select department_name
from department d, student s
where d.department_id = s.department_id
group by department_name
having count(student_id) = (select min(a.cnt_std_id) from (select
department_name, count(student_id) cnt_std_id
from department d, student s
where d.department_id = s.department_id
group by department_name)a);
Here's another way:
select department_name, students
from ( select department_name, count(*) as students
, rank() over (order by count(*)) as seq
from department join student using(department_id)
group by department_name )
where seq = 1;
It is an easy way. Goodluck
SELECT department_name, MIN(A)
FROM (select department_name, count(student_id) as A
from department d, student s
where d.department_id = s.department_id
group by department_name)

Query to find No. of employees earning maximum salary

I am trying to find the number of employees in a table that earn exactly the maximum salary of all the employees in the table called tblPerson.
Select Max(x.[No of Employees]) as Number, x.Salary as Salary
from
(
Select Count(Id) as [No of Employees], Salary
from tblPerson
Group by Salary
Having Salary = MAX(Salary)
)x
where x.[No of Employees]=3
Now I know this is a kind of long and complex way of doing it, but I was trying to do it using a derived table. But I am getting the error:
"Column 'x.Salary' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause"
My question is, why am I getting this particular error since the main query is a simple Select statement with a where clause. Isn't it??
Mainly, aggregate functions work only with other aggregate functions or grouped by columns.
Why? Because an aggregate function needs to know the set of values to do calculation with.
In you case, the max() will want to use all the data available for the calculation and display a single result (single row) and the other column will want to be displayed row by row. So there's a conflict.
Thank you all. Every answer helped me. However, I think I found a pretty simple way to do it:
Select top 1 Count(Id) as [No of Employees], salary
from tblPerson
Group by Salary
Order by [No of Employees] DESC
select count(*) from tblPerson where salary=(select max(salary) from tblPerson)
You get the error because 'max' is an aggregation, while you have nothing to aggregate the number by.
Select Max(x.[No of Employees]) as Number, x.Salary as Salary
from
(
Select Count(Id) as [No of Employees], Salary
from tblPerson
Group by Salary
Having Salary = MAX(Salary)
)x
---------
Group by Salary -- all other items in your select statement
---------
where x.[No of Employees]=3
however, you can also use a temporary table or variable to find the persons.
To solve this via a variable, you could do the following
declare #maxSalary Decimal
set #maxSalary = (Select max(salary) from tblperson) --insert the max value into a variable
Then either aggregate the persons (or do some other logic):
Select ID from tblperson where salary = #maxSalary
The reason for not using a group by is that using a variable is more efficient, as you search the table instead of aggregating over it.
Create a CTE (RESULT), and using DENSE_RANK function, get the highest salary, together with the EmployeeID's.
The first row of the RESULT table will give the highest salary.
Using the aggregate function COUNT, get the number of Employees with the highest Salary.
with RESULT (EmployeeID, Salary, DenseRank) as
(select EmployeeID, Salary,
DENSE_RANK() over (ORDER BY SALARY DESC) AS DenseRank
from Employee)
select TOP 1 Salary,
(select COUNT(EmployeeID)
from Employee
where Salary = (select TOP 1 Salary)
from RESULT
where DenseRank = 1)
)
from RESULT
where DenseRank = 1;

Select records with maximum value

I have a table that is called: customers.
I'm trying to get the name and the salary of the people who have the maximum salary.
So I have tried this:
SELECT name, salary AS MaxSalary
FROM CUSTOMERS
GROUP BY salary
HAVING salary = max(salary)
Unfortunately, I got this error:
Column 'CUSTOMERS.name' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
I know I should add the name column to the group by clause, but I get all the records of the table.
I know that I can do it by:
SELECT name, salary
FROM CUSTOMERS
WHERE salary = (SELECT MAX(salary) FROM CUSTOMERS)
But I want to achieve it by group by and having clauses.
This requirement isn't really suited for a group by and having solution. The easiest way to do so, assuming you're using a modern-insh version of MS SQL Server, is to use the rank window function:
SELECT name, salary
FROM (SELECT name, salary, RANK() OVER (ORDER BY salary DESC) rk
FROM customers) c
WHERE rk = 1
Mureinik's answer is good with rank, but if you didn't want a windowed function for whatever reason, you can just use a CTE or a subquery.
with mxs as (
select
max(salary) max_salary
from
customers
)
select
name
,salary
from
customers cst
join mxs on mxs.max_salary = cst.salary
There was no need to use group by and having clause there, you know. But if you want to use them then query should be
SELECT name, salary
FROM CUSTOMERS
GROUP BY salary
having salary = (select max(salary) from CUSTOMERS)

How to write an SQL query for this scenario?

I have a table containing attributes Id, Emp_name, dept_name, salary. Now i want to write an SQL query that will give me the dept_name value for which the overall salary of all employees belonging to that department is the highest, i.e dept for which sum of salaries of all its employees is the highest...? If there is any similar question with answer on stackoverflow, please suggest.. I dint find one. Thanks :)
I tried group by with sum() function, but i could not get how to find the maximum and compare it with sum.
Can you do
SELECT TOP 1 dept_name FROM table GROUP BY dept_name ORDER BY SUM(salary) DESC
Seems like a textbook example for GROUP BY:
select dept_name, total_salary from (
Select dept_name, sum(salary) as total_salary
from my_table
group by dept_name
) order by total_salary desc
try this:
select top 1 dept_name from myTable group by dept_name order by sum(salary) desc
SELECT dept_name FROM table
GROUP BY dept_name
ORDER BY SUM(salary) DESC
LIMIT 1
And you would also better have you departments in another table linked to the first table via foregn keys. Just a note.
I don't know exactly know your requirements, but perhaps there is another point to be considered: Two (or more) departments could have the same sum of salary.
I have not tested the query, but this should give you all departments which have the maximum some of salary:
select dept_name FROM table_name GROUP BY dept_name HAVING SUM(salary)=(select MAX(sum_salary) FROM (select SUM(salary) AS sum_salary FROM table_name GROUP BY dept_name))