How to show values related to a max() grouped by another column - sql

I'm using this code to join two tables and get the highest salary from each location
SELECT
max(sal) [Salary],
loc [Location]
FROM dept
INNER JOIN emp
ON dept.deptno = emp.dept
group by loc
how can i get the name of the person with the max salary together with the location?
tried this, but it shows all entries on table
SELECT
max(sal) [Salary],
loc [Location],
ename [names]
FROM dept
INNER JOIN emp
ON dept.deptno = emp.dept
group by loc,ename

Use window functions:
SELECT e.*
FROM (SELECT d.loc, e.*,
ROW_NUMBER() OVER (PARTITION BY d.loc ORDER BY salary DESC) as seqnum
FROM dept JOIN
emp
ON dept.deptno = emp.dept
) e
WHERE seqnum = 1;

Related

Retrieve the name of employee who is getting higher salary from each department

I have three different tables like department, employee and salary for SQL Server.
Its structure
CREATE TABLE department (DeptId INT,DeptName Varchar(100))
INSERT INTO department VALUES (1,'Accounts');
INSERT INTO department VALUES (2,'Package');
CREATE TABLE employee (EmpId INT,DeptId INT,EmpName varchar(20))
INSERT INTO employee VALUES (1,1,'Sachin');
INSERT INTO employee VALUES (2,1,'Vikas');
INSERT INTO employee VALUES (3,2,'Sikha');
INSERT INTO employee VALUES (4,2,'Disha');
CREATE TABLE salary(EmpId INT,Sal int)
INSERT INTO salary VALUES (1,400);
INSERT INTO salary VALUES (2,700);
INSERT INTO salary VALUES (3,700);
INSERT INTO salary VALUES (4,900);
Result will be:
DepName | EmpName
-----------------
Accounts | Vikas
Package | Disha
Please help me on this, I need a query to find the required result.
I have tried below query, but not able get EmpName.
select DeptName, max(Sal) as Salary from
(select dep.DeptName, emp.EmpName, sal.Sal from salary as sal
inner join employee emp on emp.EmpId = sal.EmpId
inner join department dep on dep.DeptId = emp.DeptId) as tbls
group by DeptName
You can use RANK() to query the salary.
Here is example:
select DeptName
,EmpName
from
(
select DeptName
,EmpName
,rank() over (partition by d.deptid order by sal desc) as ranknum
from employee as e
inner join salary as s
on e.EmpId=s.EmpId
left join department as d
on d.DeptId = e.DeptId
) as ranktable
where ranknum = 1
We can use CTE as well:
;WITH maxSalStaff AS (
SELECT
rnk = ROW_NUMBER() OVER (PARTITION BY d.DeptId ORDER BY s.Sal DESC),
d.DeptName,
e.EmpName,
s.Sal
--ItemID
FROM department d
INNER JOIN employee e ON e.DeptId = d.DeptId
INNER JOIN salary s ON s.EmpId = e.EmpId
)
SELECT * FROM maxSalStaff WHERE rnk = 1
try this
SELECT T.EmpName, D.DeptName
FROM
(
SELECT E.EmpId, E.DeptId, E.EmpName, S.Sal,
RANK() OVER (PARTITION BY E.DeptId ORDER BY S.Sal DESC)Rank
FROM employee E
INNER JOIN salary s ON E.EmpId = S.EmpId
)T
INNER JOIN department D ON (T.DeptId = D.DeptId)
WHERE T.Rank=1
Use DENSE_RANK() in case multiple people can have same salary. Like below
WITH cteRowNum AS (
select
e.EmpName,
d.DeptName,
sal,
DENSE_RANK() OVER (PARTITION BY DeptName order by sal desc) as RowNo
from employee e inner join
departments d on d.DeptId= e.DeptId inner join
salary s on e.EmpId= s.EmpId
)
SELECT EmpName, DeptName, Sal
FROM cteRowNum
WHERE RowNo = 1;

How to get result if exactly one match inner join

How can I write a query to join two tables and return result if exactly one match in there. I have to discard results if zero match and more than one match.
All I am looking for is to extend the INNER JOIN. Let me just get to the point. I have two tables Dept & Emp. One Dept can have multiple Emp's & not the other way around.
Table Dept
Table Emp
I need to JOIN it on Dept_id
Expected Results
You can join with a not exists condition:
select d.*, e.emp_id, e.emp_name
from dept d
inner join emp e
on d.dept_id = e.dept_id
and not exists (
select 1
from emp e1
where e1.dept_id = d.dept_id and e1.emp_id != e.emp_id
)
One alternative to existing solutions can be one using analytics (window functions),
instead of joining twice:
select dept_id, dept_name, emp_id, emp_name
from
(
SELECT
d.Dept_id, d.Dept_name, e.Emp_id, e.Emp_Name,
count(*) over (partition by d.dept_id) cnt1
FROM d
INNER JOIN e
ON d.Dept_id = e.Dept_id
) where cnt = 1;
You could use a subquery for group by dept_id haing count = 1
select t.dept_id, dept.dept_name, emp.Emp_name
from (
select dept_id
from emp
group by dept_id
having count(*) = 1
) t
INNER JOIN dept on t.dept_id = dept.dept_id
INNER JOIN emp ON t.dept_id = emp.dept_id
You can phrase this as an aggregation query in Oracle:
select d.dept_id, d.dept_name,
max(e.emp_id) as emp_id,
max(e.emp_name) as emp_name
from dept d inner join
emp e
using (dept_id)
group by d.dept_id, d.dept_name
having count(*) = 1;
This works because if there is only one match, then max() returns the value from the one row.
Also, try below query;
SELECT a.depid dept_id,dept_name,emp_id,emp_name
FROM
(SELECT case WHEN count(*)=1 THEN dept_id END depid FROM emp GROUP BY dept_id) a INNER JOIN emp ON depid=dept_id
INNER JOIN dept b ON a.depid = b.dept_id
WHERE depid IS NOT NULL
Another way would be
select d.dept_id, d.dept_name, e.emp_name
from emp e
join dept d on d.dept_id = e.dept_id
where e.dept_id in
( select dept_id from emp group by dept_id having count(*) = 1 )

Need to retrieve columns from 3 tables

There are three tables: dept, emp, sal . You can find their structure and data in the images.
I need to extract the list of employees who have location as pune and have max salary in their department. Since there are five departments, the final output will contain five rows and columns of emp_id, dept, dept_id, salary.
I've tried...
select e.emp_id, dept,e.dept_id, max(sal) as 'highest salary'
from sal s,emp e,dept d
where e.emp_id = s.emp_id and d.dept_id = e.dept_id and loc ='Pune'
group by e.emp_id,e.dept_id,dept
order by e.dept_id
I would use apply :
select t.emp_id, d.dept, d.dept_id, t.sal
from dept d
cross apply ( select top 1 e.emp_id, s.sal as sal
from emp e
inner join sal s on s.emp_id = e.emp_id
where d.dept_id = e.dept_id and e.loc = 'Pune'
order by s.sal desc
) t;
Unless you have window functions (that depends on whether you're using MySQL, Oracle, SQLite, etc) you will need to do it in two steps.
Find the highest salary per department (for employees in 'Pune'), then another set of joins to find out who those people are.
SELECT
dep.dept,
dep.dept_id,
emp.emp_id,
sal.sal
FROM
emp
INNER JOIN
sal
ON sal.emp_id = emp.emp_id
INNER JOIN
(
SELECT
emp.dept_id,
MAX(sal.sal) AS max_sal
FROM
emp
INNER JOIN
sal
ON sal.emp_id = emp.emp_id
WHERE
emp.loc = 'Pune'
)
dep_sal
ON dep_sal.dept_id = emp.dept_id
AND dep_sal.max_sal = sal.sal
INNER JOIN
dep
ON dep.dept_id = emp.dept_id
WHERE
emp.loc = 'Pune'
ORDER BY
dep.dept,
emp.emp_id
EDIT: With SQL Server 2008 on-wards it's a bit easier...
WITH
emp_sal_ranked AS
(
SELECT
emp.dept_id,
emp.emp_id,
sal.sal,
RANK(sal.sal) OVER (PARTITION BY emp.dept_id
ORDER BY sal.sal
)
AS rank_sal
FROM
emp
INNER JOIN
sal
ON sal.emp_id = emp.emp_id
WHERE
emp.loc = 'Pune'
)
SELECT
dep.dept,
dep.dept_id,
emp_sal_ranked.emp_id,
emp_sal_ranked.sal
FROM
emp_sal_ranked
INNER JOIN
dept
ON dept.dept_id = emp_sal_ranked.dept_id
WHERE
emp_sal_ranked.rank_sal = 1
ORDER BY
dep.dept,
emp_sal_ranked.emp_id

Display empno,ename,sal,deptno,dname,location, Display highest paid employee of every department

How to display highest paid employee of every department WITH empno,ename,sal,deptno,dname,location....
select e.empno,e.ename, max(e.Sal),d.Deptno
from DEPTNO d
inner join emp e
on d.Deptno = e.DEPTNO
group by d.DEPTNO;
Employee table:
Deptno table:
Using the row_number() analytic function makes this easy:
select e.empno,
e.ename,
e.sal,
d.deptno,
d.dname,
d.loc
from Deptno d
join (select e.*,
row_number() over (
partition by e.deptno
order by sal desc) as rn
from Employee e) e
on e.deptno = d.deptno
and e.rn = 1
In this case, the row_number() function will return a value of 1 for the highest paid employee of every department, so that's why the join condition includes e.rn = 1 to limit the results to those employees.
Try this :
select empno,ename,deptno,sal from
(
select e.empno,e.ename,d.Deptno,sal,max(sal) over (partition by d.deptno order by null) max_sal from Employee e,Deptno d where e.deptno = d.deptno
)where sal=max_sal
here max_sal return max salary with partition by department

Need Max values from the query?

I have two tables
Employee ( empid integer, mgrid integer, deptid integer, salary
integer)
Dept (deptid integer, deptname text),
I am trying find to departments that have maximum number of employees.
I tried this but i am getting all the dept Id's, how to get dept Id that has maximum employees.
SELECT dept.DeptName,
COUNT(emp.EmpId) AS NUM_OF_EMPLOYEES
FROM Dept dept
INNER JOIN Employee emp
ON dept.DeptId = emp.deptId
GROUP BY dept.DeptName;
It depends on your DB, but the logic is the same. You want to sort the results, then just grab the top of the results.
In sql-server, Access, Teradata and a few other DB's you would use TOP:
SELECT TOP 1 dept.DeptName,
COUNT(emp.EmpId) AS NUM_OF_EMPLOYEES
FROM Dept dept
INNER JOIN Employee emp
ON dept.DeptId = emp.deptId
GROUP BY dept.DeptName
ORDER BY NUM_OF_EMPLOYEES DESC
On MySQL or Postgres you would use LIMIT:
SELECT dept.DeptName,
COUNT(emp.EmpId) AS NUM_OF_EMPLOYEES
FROM Dept dept
INNER JOIN Employee emp
ON dept.DeptId = emp.deptId
GROUP BY dept.DeptName
ORDER BY NUM_OF_EMPLOYEES DESC
LIMIT 1
In Oracle you use RowNum:
SELECT dept.DeptName,
COUNT(emp.EmpId) AS NUM_OF_EMPLOYEES
FROM Dept dept
INNER JOIN Employee emp
ON dept.DeptId = emp.deptId
WHERE ROWNUM=1
GROUP BY dept.DeptName
ORDER BY NUM_OF_EMPLOYEES DESC