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
Related
I am learning SQl and I have a question in mind as follow:
I want to find minimum among the avg(salaries) of department.
Schema:
Department(dno, salary)
==================================================
what I tried is below query but I got error.
**select min(avg(salary)) from department groupby dno;**
Can anyone help me out with this, or any other possible solution?
Using TOP 1:
select top 1 avg(salary) AS avg_salary
from department
group by dno
order by avg_salary
Using a select from subquery approach:
select min(T.avg_salary) as min_salary
from
(
select avg(salary) as avg_salary
from department
group by dno
) T;
conceptually, both min and avg are a set operation. pendantically, the min(avg(salary)) == avg(salary), because, there's only one avg for a given set of numbers. You could obviously, calculate
select min(salary), avg(salary) from department
This would tell you the smallest salary in the depeartment which would by definition be less than the avg unless all the salaries would be the same. Which is an odd use case.
You might be thinking of something like:
select department, min(salary), max(salary), avg(salary)
from employee
group by department
To understand a new distrubution I will often use
select min(targetValue), max(targetValue), avg(targetvalue) from targetTable
To get a sense for the range in values.
So I have been trying to solve this for a while, and even though I have found many interesting things here I simply could not solve it the way it has been requested.
I have two tables:
PROFESSOR (ID, NAME, DEPARTMENT_ID and SALARY) and
DEPARTMENT (ID, NAME).
I have to write a query that shows the DEPARTMENT NAME that has the HIGHEST average SALARY. Also if more than one department have the highest average SALARY, should list all of then in any order.
I have tried so many things and in the end I created a monster, I think. i tried using HAVING but it did not work the way I did. I'm lost. The problem is that I need to use to aggregate functions.
SELECT b.nam, b.average
FROM ( SELECT DEPARTMENT.NAME AS nam, AVG(PROFESSOR.SALARY) AS average
FROM PROFESSOR JOIN DEPARTMENT ON (PROFESSOR.DEPARTMENT_ID =
DEPARTMENT.ID)
GROUP BY DEPARTMENT.NAME) AS b
GROUP BY b.nam, b.average
ORDER BY b.average DESC
But this query is bringing me all the departments with the average, not the maximum.
If someone could please assist me and explain in a easy way I would really appreciate it.
Thanks!
You can use this. If more than one row has same max avg value, with using WITH TIES you can bring all of them.
SELECT TOP 1 WITH TIES DEPARTMENT.NAME AS nam, AVG(PROFESSOR.SALARY) AS average
FROM PROFESSOR
JOIN DEPARTMENT ON (PROFESSOR.DEPARTMENT_ID = DEPARTMENT.ID)
GROUP BY DEPARTMENT.NAME
ORDER BY AVG(PROFESSOR.SALARY) DESC
;WITH x AS (
SELECT t.dept,
T.avg_sal,
rank() OVER(ORDER BY t.avg_sal DESC) AS rnk
FROM
(
SELECT d.name AS 'dept',
avg(p.salary) AS avg_sal
FROM department AS d
INNER JOIN
professor AS p ON p.department_id=d.id
GROUP BY d.name
) AS t
)
-- all depts with highest avg sal
SELECT dept, avg_sal
FROM x
WHERE rnk = 1
You can subquery for the MAX(avgSalary). The way I've done it here was to use a CTE.
WITH cte AS
(
SELECT DEPARTMENT_ID
,AVG(SALARY) [avgSalary]
FROM PROFESSOR
GROUP BY DEPARTMENT_ID
)
SELECT D.[NAME]
,cte.avgSalary
FROM cte INNER JOIN DEPARTMENT D
ON D.ID = cte.DEPARTMENT_ID
WHERE cte.avgSalary = (SELECT MAX(avgSalary)
FROM cte)
I think what you want is:
select
NAME,
max(avg_salary) as max_avg_salary
from
DEPARTMENT d inner join
(select
DEPARTMENT_ID ,
avg(SALARY) as avg_salary
from
PROFESSOR
group by
DEPARTMENT_ID) a on
d.DEPARTMENT_ID = a.DEPARTMENT_ID
there are other ways to do it as you see in the other answers, but I think you want the simplest solution possible using group by to determine both each avg and the max of all avgs. Only other thing you need is a subquery, which you're probably familiar with.
HTH
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;
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)
What is wrong with this SQL query?
SELECT
department_id, MAX(AVG(SALARY))
FROM
EMPLOYEES
GROUP BY
department_id;
It shows not a single-group group function
2 Aggregate functions in one Query can not be done, you should use a Subquery to achieve your result.
I've not possibility to test it right now so no guarantees on this query but you may get an idea.
select max (avg_salary)
from (select department_id, avg(SALARY) AS avg_salary
from EMPLOYEES
group by department_id);
The inner query selects deparment_id and average salary.
Avarage salary is selected using the alias avg_salary using the AS statement.
The outer query selects the maximum of avg_salary-
That's maybe not a complete solution to your problem and as I said, not tested so no guarantees, but you should have an idea now how to start. ;-)
You cant have more than one aggregate functions in one query. try this one
select dept, max(average) over (partition by dept)
from (SELECT department_id dept,
(AVG(SALary) OVER (PARTITION BY department_id)) average
FROM employees);
Alternative 1, double GROUP BY:
SELECT department_id, AVG(SALARY)
FROM EMPLOYEES
GROUP BY department_id
HAVING AVG(SALARY) = (select max(avg_sal)
from (select avg(salary) as avg_sal
from EMPLOYEES
group by department_id))
Will return both department_id's if there's a tie!
Alternative 2, use a cte (common table expression):
with
(
SELECT department_id, AVG(SALARY) as avg_sal
FROM EMPLOYEES
GROUP BY department_id
) as cte
select department_id, avg_sal
from cte
where avg_sal = (select max(avg_sal) from cte)
This too will return both department_id's if there's a tie!