Need Max values from the query? - sql

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

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 show values related to a max() grouped by another column

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;

How to count the number of members of different departments after executing a JOIN between two tables?

I have a table Emp and another table Dept
This is table Emp
This is table Dept
The query I have to execute is to display the average salary (i.e., sal) for all departments (i.e. DeptName) with more than 5 working people. So we'll have to do a JOIN or something and match the DeptID here with the DeptID there etc.
This is really confusing and I don't understand how to go about it.
you can use group by with having clause query for that.
group by Dept_id and check count using having clause.
SELECT
SUM(E.Sal) / COUNT(E.Dept_id) AS Avg_Sal,
E.Dept_Id
FROM EMP E
JOIN Dept D
ON D.DeptId = E.Dept_Id
GROUP BY E.DeptId
HAVING COUNT(E.Dept_Id) > 5
Select
DeptName,
AVG(sal) as averageSalary,
Count(EmpId) as NumberofEE
FROM Emp e
/*Left Join Because there are Nulls in the Dept_Id each Emp should belong to
1 dept*/
LEFT JOIN Dept d on e.Dept_Id = d.DeptId
GROUP BY
DeptName
Having Count(EmpId)> 5
This will give you the average salary (i.e., sal) for all departments (i.e. DeptName) with more than 5 working people
If i'm right with your requirement.

List the department name with the least number of employees

There are two tables, employee and dept:
How can I join the two tables and select the department with the least number of employees?
It would have been better to answer if you provided the table structure.
But give this a try:
SELECT deptname
FROM dept
WHERE deptid = (SELECT distinct deptid
FROM employee
ORDER BY COUNT(dept) limit 1);
Please try the following...
SELECT deptid,
deptname,
employeeCount
FROM
(
SELECT dept.deptid AS deptid,
dept.deptname,
COUNT( dept.deptid ) AS employeeCount
FROM dept
JOIN employee ON dept.deptid = employee.deptid
GROUP BY dept.deptid,
dept.deptname
)
GROUP BY deptid
HAVING employeeCount = MIN( employeeCount );
This statement starts with the inner query joining dept to employee on the shared field deptid. It then groups the resulting rows by department and returns to the outer query the department's id and name along with a count of employees for that department.
The outer query groups the data by department again, then selects the details of the department(s) having a count of employees equal to the minimum count of employees.
If you have any questions or comments, then please feel free to post a Comment accordingly.
I'm only answering because MIN isn't needed and LIMIT isn't Oracle:
select d.*
from (select deptid, count(*) as cnt
from employees e
group by deptid
order by count(*) asc
) d
where rownum = 1;
In Oracle 12C+, you don't need the subquery:
select deptid, count(*) as cnt
from employees e
group by deptid
order by count(*) asc
fetch first 1 row only;
Hi :) so my answer is a bit ugly, and full of nested queries. but I tested it and it worked for me...
-- First I created a couple of test tables and added a few records
drop table dept;
drop table employee;
create table dept (deptid number primary key, deptname varchar(20));
create table employee(employee_id number primary key, names varchar(20),
deptid number,foreign key (deptid) references dept(deptid));
insert into dept values(1,'HR');
insert into dept values(2,'Finance');
insert into dept values(3,'IT');
insert into employee values(1,'Tina',1);
insert into employee values(2,'Rob',1);
insert into employee values(3,'Lisa',1);
insert into employee values(4,'Will',2);
insert into employee values(5,'Lina',2);
insert into employee values(6,'Ethel',2);
insert into employee values(7,'Trevor',1);
insert into employee values(8,'Alanea',1);
insert into employee values(9,'Matthew',1);
insert into employee values(10,'Maddie',3);
insert into employee values(11,'Anna',1);
-- According to the added records, the answer we are looking for should be
the department name IT
-- select the department name from department table
select d.deptname from dept d,
/* This is where it gets ugly - basically, it counts the number of
employees in each department, then finds the id of the department that had
the smallest count */
(select deptid from
(select count(deptid) as counter, deptid from employee group by deptid)
where counter =( select min(counter)from
(select count(deptid) as counter, deptid from employee group by deptid))) minid
-- join the tables using deptid
where d.deptid = minid.deptid;
This query gave the correct answer for me even when I changed the records to make finance the correct answer.
If you have any questions give me a yell through the comments :)
select department_name, count(employee_id)
from department d
inner join employee e
on d.employee_id = e.employee_id
having count(employee_id) =
(
select min(count(employee_id)) /*This query returns minimum count*/
from department d
inner join employee e
on d.employee_id = e.employee_id
group by department_name
)
group by department_name;
WITH temp
AS
(SELECT e1.department_id, count(e1.employee_id) emp_count
FROM hr.employees e1
GROUP BY e1.department_id)
SELECT d1.department_name, t1.emp_count employee_count
FROM temp t1
,hr.departments d1
WHERE t1.department_id = d1.department_id(+)
AND NOT EXISTS
(SELECT 1
FROM temp t2
WHERE t2.emp_count < t1.emp_count)
ORDER BY 2,1 ;

Is there a way to make this SQL more efficient?

Consider the following tables:
department
deptid (type:INT)
deptname (type: TEXT)
hours (type:INT)
active (type:BIT)
employee
empid (type:INT)
empname (type: TEXT)
deptid (type: INT)
designation (type: TEXT)
salary (type: INT)
Write a query to return the columns empname and deptname of the employees belonging to those
departments that have a head count of 4 or more. The records should be returned in alphabetical order of empname
This was my take:
SELECT e1.empname, d.deptname from employee AS e1
FULL JOIN department AS d on e1.deptid = d.deptid
WHERE e1.deptid IN(
SELECT deptid FROM(
SELECT e2.deptid, COUNT(e2.empid)
FROM employee AS e2
GROUP BY e2.deptid
HAVING COUNT(e2.empid) >= 4
)
)
ORDER BY empname;
How would you improve on this?
This is shorter and probably performs faster too
SELECT e1.empname, d.deptname
from (
SELECT e2.deptid
FROM employee AS e2
GROUP BY e2.deptid
HAVING COUNT(e2.empid) >= 4
) G
inner join employee AS e1 on e1.deptid = G.deptid
INNER JOIN department AS d on d.deptid = G.deptid
ORDER BY e1.empname;
Start with the grouping. You don't need COUNT from the inner query.
Then, join to both tables just to get the names.
INNER JOIN is used because once the count is complete, we already know that
the employees exist
the department exists
Try this query, it will work properly.
select empname,deptname from employee,department
where
employee.deptid=department.deptid and employee.deptid
in
(
select deptId from employee group by deptid having count(*)>=4
)
order by empname