Consider I have two tables/columns:
Employee - > EmpId, DeptNo, EmpName, Salary
Department -> DeptNo, DeptName
Write a query to get employee names who is having maximum salary in all of the departments.
I have tried this:
Select max(salary),empname
from Employee
where deptno = (select deptno
from department
where deptname in('isd','it','sales')
Is it correct? Actually it's a interview question.
This is an example of groupwise max mysql pattern. One way to do it would be:
SELECT e.salary, e.name, d.deptname
FROM Employee AS e
JOIN (
SELECT max(salary) AS max_sal, deptno
FROM Employee
GROUP BY deptno
) AS d_max ON (e.salary=d_max.max_sal AND e.deptno=d_max.deptno)
JOIN Department AS d ON (e.deptno = d_max.deptno)
Though it will return more than one row for a department if more than one employee has a maximum salary in a department
Personally I'd use a cte and row_number for a question like this. For example:
with myCTE as
(
select e.empName, e.salary, d.deptName,
row_number() over (partition by e.deptNo order by e.salary desc) as rn
from Employee as e
inner join Department as d
on d.DeptNo=e.DeptNo
)
select m.empName, m.deptName, m.salary
from myCTE as m
where m.rn=1
In the case of ties (two employees in the same department have the same max salary) then this is non-deterministic (it will just return one of them). If you want to return both of them then change the row_number to a dense_rank.
Related
This question already has answers here:
Group by minimum value in one field while selecting distinct rows
(10 answers)
Closed 4 years ago.
I have a sql query that outputs employees who have the minimum salary across departments. It does so by finding the minimum salary for each department and finding people with salaries that match ANY of those. In this case, Person 1 can belong to department A and have a salary of 70k (even though her department's minimum is 45k) and be returned in the query if another department's minimum salary is 70k. However, what if I instead want to output names of people who have the minimum salary for their respective department (so Person 1 would not be returned anymore). Here is the current sql query:
SELECT first_name, last_name, salary, department_id
FROM employees
WHERE salary IN
( SELECT MIN(salary)
FROM employees
GROUP BY department_id
);
If you have MySQL 8.0 then the simplest approach is using window function:
SELECT *
FROM (SELECT *, RANK() OVER(PARTITION BY department_id ORDER BY salary DESC) AS r
FROM tab) sub
WHERE r = 1;
Or:
SELECT first_name, last_name, salary, department_id
FROM employees e
WHERE (department_id,salary) IN
( SELECT department_id, MIN(salary)
FROM employees
GROUP BY department_id);
Instead fo a IN clause you can also use an inner join
SELECT first_name, last_name, salary, department_id
FROM employees
INNER JOIN ( SELECT department_id, MIN(salary) min_sal
FROM employees
GROUP BY department_id
) t on t.department_id =employees.department_id
and employees.salary = t.min_sal;
this should be better for performance
SELECT department_id, MIN(salary)
FROM employees
WHERE department_id
HAVING AVG(salary) >= (SELECT MAX(AVG(salary))
FROM employees
GROUP BY department_id);
why it give me the invaild use of group function
If you want the minimum salary from departments whose average salary is the largest, then change the having clause:
HAVING AVG(salary) >= (SELECT AVG(salary)
FROM employees
GROUP BY department_id
ORDER BY AVG(salary) DESC
LIMIT 1
);
subquery - MAX(AVG()) you cannot do such a things, dont know what you want to achieve but if you want to hava a max of the departments averages you should do it with
SELECT MAX(avg_salary)
FROM (SELECT department_id, AVG(salary) AS avg_salary
FROM employees
GROUP BY department_id) AS a;
or easier:
SELECT TOP 1 AVG(salary) AS avg_salary
FROM employees
GROUP BY department_id
ORDER BY AVG(salary) DESC
main query - WHERE department_id should be specified what values should department_id be or WHERE clause should be skipped
main query - lack of GROUP BY department_id
but for me this query does not have any sense...I think it would be better if you explained what do you want to calculate, probably it is achivable much easier...
I am trying to do a join subquery to return just employee names that earn less than 46000 and I can get it to work by also returning the employee id but not without it.
This is how Im doing it.
Select e.eid, e.ename
From employee_table e
Inner Join (
Select salary, eid
from salary
Where salary > 46000
) as s
On e.eid = s.eid;
This beacuse you are using a dinamic temporary table and if you don't select the eid column your temporary dinamica table don't contain this values and the on clause in join fails
Select e.eid, e.ename
From employee_table e
Inner Join (
Select salary, eid
from salary
Where salary < 46000
) as s
On e.eid = s.eid;
you can use an inner join without dinamic temporary table
Select e.eid, e.ename
From employee_table e
INNER JOIN salary s On e.eid = s.eid
where s.salary < 46000
So the salary isn't stored in the employee table, but in a separate salary table. The salary table contains the employee ID. This makes this a 1:n relation, i.e. one employee can have more than one salary.
I don't know your tables, so I don't know the reason for this. Maybe an employee can have many jobs, or there are part salaries like a base salary and additional salaries, or there is a date range stored with the salary to indicate when it is/was valid. I don't know.
Let's say, we can simply add an employee's salaries to get the total. Then we select the employee names from the employee table where we find a salary less than 46000 in the salary table.
select ename
from employee
where eid in
(
select eid
from salary
group by eid
having sum(salary) < 46000
);
I have table like this.
I want to find the max salary department wise and the name of employee who has it.
I ran MySql query
select concat(First_name,' ',Last_name) as Name,max(SALARY)
from Employee
group by Department;
which gives result as shown below.
In which max(SALARY) is correct but Emplyoee name is wrong.How to get both correct?
Try this:
SELECT concat(First_name,' ',Last_name) as Name,SALARY FROM Employee WHERE salary IN (SELECT MAX(SALARY) FROM Employee GROUP BY Department);
this will help you.
Here is a correct solution:
SELECT concat(e.First_name, ' ', e.Last_name) as Name, e.SALARY
FROM Employee e
WHERE salary = (SELECT MAX(SALARY) FROM Employee e2 WHERE e2.Department = e.Department);
You have to find out what the max salary is per department, and then find the employee(s) in that department who have that salary.
Use a CTE or a Correlated SubQuery.
With myCTE (dept, maxsalary)
as (
Select dept, max(salary) over (partition by dept) from EmployeeTable)
Select concat(e.firstname, e.lastname), e. salary
from EmployeeTable e where e.Dept = myCTE.dept and e.Salary = myCTE.salary
If you want only max
SELECT first_name,department,salary FROM Employees WHERE salary IN (SELECT max(salary) From employees GROUP BY department)
If you want max and min
select department, first_name, salary from employees e1 where salary in ((select max(salary) from employees where department=e1.department), (select min(salary) from employees where department=e1.department)) order by department
SELECT t.name,t.dept_id,temp.max
FROM employee as t
JOIN (SELECT dept, MAX(salary) AS max
FROM employee
GROUP BY dept_id) as temp
on t.dept_id=temp.dept_id and t.salary=temp.max
So I have Two Tables called Emp and Dept..
Emp has ssn, name, supssn, salary, depno
Dept has Dno, name, mgrssn
I'm supposed to get names of those managers who are making less than some of his employees
Right now I have:
SELECT DISTINCT Emp.name
FROM Emp CROSS JOIN Dept
WHERE ((SELECT Emp.salary
FROM Emp, Dept)>(SELECT Emp.salary
FROM Emp, Dept
WHERE(Emp.name IN (SELECT Emp.name
FROM Emp CROSS JOIN Dept
WHERE ssn = mgrssn)))) AND (SELECT Emp.depno
FROM Emp, Dept)=(SELECT Emp.depno
FROM Emp, Dept
WHERE(Emp.name IN (SELECT Emp.name
FROM Emp CROSS JOIN Dept
WHERE ssn = mgrssn)));
What exactly am I missing or adding too much right now?
you really need to be patient and organize your question, sir..
but if I understand it correctly, you may try this..
(I assume supssn is the ssn of the manager)
SELECT DISTINCT sup.name
FROM emp e join emp sup on e.supssn = sup.ssn
WHERE sup.salary < e.salary