Oracle SQL query issue - sql

I am using oracle's SQL Developer. To begin with, I have this table:
Name Null Type
-------------- -------- ------------
EMPLOYEE_ID NOT NULL NUMBER(6)
FIRST_NAME VARCHAR2(20)
LAST_NAME NOT NULL VARCHAR2(25)
DEPARTMENT_ID NUMBER(4)
I would like to retrieve(select) the ID of the department in which are the most employees.
I managed through a statement to retrieve all the numbers of the employees in every department:
select count(employee_id), department_id
from employees
group by department_id;
It gives me something like:
count(employee_id) | department_id
---------------------|------------------
6 100
16 30
1 12
What I would like to do is ONLY to retrieve the department_id 30, which (in this case) has the most employees.

A typical way to do this in Oracle:
select department_id
from (select count(employee_id), department_id
from employees
group by department_id
order by count(employee_id) desc
) t
where rownum = 1;
If you have potential duplicates and want all the department ids, then a join to the max or analytic function is a better approach. For example:
select department_id
from (select count(employee_id), department_id,
rank() over (order by count(employee_id) desc) as seqnum
from employees
group by department_id
) t
where seqnum = 1;

Related

SQL COUNT modify

From the SQL Oracle HR scheme I used the folowing:
SELECT DEPARTMENT_ID, ROUND(AVG(SALARY),2)
FROM EMPLOYEES
WHERE DEPARTMENT_ID IS NOT NULL
GROUP BY DEPARTMENT_ID
ORDER BY DEPARTMENT_ID
To get:
DEPARTMENT_ID ROUND(AVG(SALARY),2)
10 4400
20 9500
30 4150
40 6500
50 3475,56
60 5760
...
How do I change it so: it only count the departments that have the max avg salary (in my case 1) and show also the max avg salary?
Thank you for your time!
If I understood you, this is one possible way:
SELECT DEPARTMENT_ID, ROUND(AVG(SALARY),2) AS AVG_SALARY
FROM EMPLOYEES
WHERE DEPARTMENT_ID IS NOT NULL
AND ROUND(AVG(SALARY),2) = (
SELECT MAX(T.AVG_SALARY)
FROM (
SELECT DEPARTMENT_ID, ROUND(AVG(SALARY),2) AS AVG_SALARY
FROM EMPLOYEES
WHERE DEPARTMENT_ID IS NOT NULL
GROUP BY DEPARTMENT_ID) AS T)
GROUP BY DEPARTMENT_ID
ORDER BY DEPARTMENT_ID
This will show you ALL THE DEPARTMENTS that have max avg salary. If you want only the count:
SELECT COUNT(A.*), AVG(A.AVG_SALARY)
FROM (
SELECT DEPARTMENT_ID, ROUND(AVG(SALARY),2) AS AVG_SALARY
FROM EMPLOYEES
WHERE DEPARTMENT_ID IS NOT NULL
GROUP BY DEPARTMENT_ID) A
WHERE A.AVG_SALARY = (
SELECT MAX(T.AVG_SALARY) AS MAX_AVG_SALARY
FROM (
SELECT DEPARTMENT_ID, ROUND(AVG(SALARY),2) AS AVG_SALARY
FROM EMPLOYEES
WHERE DEPARTMENT_ID IS NOT NULL
GROUP BY DEPARTMENT_ID) AS T)
Another way that should work, using joins:
SELECT t1.DEPARTMENT_ID, ROUND(AVG(t1.SALARY),2) AS AVG_SALARY
FROM EMPLOYEES t1
LEFT JOIN (SELECT MAX(AVG_SALARY) AS MAX_AVG_SALARY FROM EMPLOYEES) t2
ON AVG_SALARY=t2.MAX_AVG_SALARY
WHERE t1.DEPARTMENT_ID IS NOT NULL
AND AVG_SALARY=t2.MAX_AVG_SALARY
ORDER BY t1.DEPARTMENT_ID ASC;
I tested the idea on a sample table of mine using oracle, and on a w3schools sql testing page with this code:
SELECT Customers.CustomerName, Orders.maxid
FROM Customers
LEFT JOIN (select max(Orders.CustomerID) as maxid from Orders) orders
ON Customers.CustomerID=Orders.maxid
where customers.customername is not null and customers.customerid=orders.maxid
ORDER BY orders.maxid desc;
It should grab only the departments that match their average salary with the max average salary that was selected in the join statement.
If you are only looking for the count of the departments, and not a list of the department names, then this slight modification should work for you:
SELECT COUNT(t1.DEPARTMENT_ID) as Num_Of_Depts, ROUND(AVG(t1.SALARY),2) AS AVG_SALARY
FROM EMPLOYEES t1
LEFT JOIN (SELECT MAX(AVG_SALARY) AS MAX_AVG_SALARY FROM EMPLOYEES) t2
ON AVG_SALARY=t2.MAX_AVG_SALARY
WHERE t1.DEPARTMENT_ID IS NOT NULL
AND AVG_SALARY=t2.MAX_AVG_SALARY
GROUP BY AVG_SALARY;

Ora-00935 error group nested too deeply

The following sql query keeps throwing an error that group function is nested too deeply
select department_name
from department
where department_id in (select department_id
from student
group by department_id
having count(student_id)=max(count(student_id)));
Can someone suggest how to correct this without making other table ??
I do not see what the in buys you. I find this easier to write and to follow with the calculation in the from clause:
select d.department_name
from (select s.department_id, count(*) as num_students,
rank() over (order by count(*) desc) as seqnum
from student s
group by s.department_id
) s join
department d
on s.department_id = d.department_id
where seqnum = 1;
This also makes it easy to add the number of students in the most populous departments.
Try using the MAX analytics function
SELECT department_name
FROM department
WHERE department_id IN
( SELECT
department_id
FROM
( SELECT
department_id,
COUNT(student_id) students,
MAX(COUNT(student_id)) OVER () max_students
FROM student
GROUP BY department_id
)
WHERE students=max_students
);
Not tested.
Or in Oracle 12c onwards you could use the FECTH clause
SELECT department_name
FROM department
WHERE department_id IN
( SELECT department_id
FROM student
GROUP BY department_id
ORDER BY COUNT(student_id) DESC
FETCH FIRST ROW WITH TIES
);

Get the minimum employees with a given job

I have this table:
Name Null? Type
-------------------------- -------- ------------
EMPLOYEENO NOT NULL NUMBER(4)
ENAME VARCHAR2(15)
JOB VARCHAR2(15)
MGR NUMBER(4)
HIREDATE DATE
SAL NUMBER
COMM NUMBER
DEPTNO NUMBER(2).
I want to get the department with minimum employees who have a given job (for example all the employees with 'Analyst' job).
Can you please help me with the query?
Here the key is to get the count of Employee doing particular job in each department. In below query, this is achieved by subquery. Then, we want to get the Department with minimum no. of employee doing that job so we ordered the records returned by subquery in ascending and then select the first result by using rownum = 1
SELECT DEPTNO from (
SELECT COUNT(*) AS NO_OF_EMP , DEPTNO
FROM EMPLOYEE EMP
WHERE EMP.JOBNAME = 'Analyst'
GROUP BY DEPTNO
ORDER BY NO_OF_EMP ASC )
where ROWNUM = 1;
Given that the minimum number of such employees could be 0, you need to be a bit clever about how you do this:
select d.*
from (select deptno,
sum(case when jobname = 'Analyst' then 1 else 0 end) as numAnalysts
from employees
group by deptno
order by numAnalysts asc
) d
where rownum = 1;

employee department wise and count of employees more than 5

i want to display department_id's along with count,and count should be more than 5, and i want to have employees who are not hired in January.
i tried the below query
SELECT * FROM EMPLOYEES
WHERE DEPARTMENT_ID IN
(
SELECT DEPARTMENT_ID
FROM EMPLOYEES
GROUP BY DEPARTMENT_ID
HAVING COUNT(*)>5
)
AND HIRE_DATE NOT LIKE '%JAN%';
but here I didnt get count.I want count Also.
SELECT department_ID, count(employee_id) as '# of Employees' FROM EMPLOYEES
WHERE DEPARTMENT_ID IN
(
SELECT DEPARTMENT_ID
FROM EMPLOYEES
GROUP BY DEPARTMENT_ID
HAVING COUNT(*)>5
)
AND HIRE_DATE NOT LIKE '%JAN%'
group by department_ID;
This query returns the department_id and because I group by department_id, the count of employees that belong to each department will be returned
Output will look something like this
Department_Id | # of Employees
1 7
2 6
4 9
If you want the dept id and count of employees (where employee hire date is not in Jan) then something like the following should work. I say "something like the following" because I suspect the WHERE hire_date NOT LIKE '%JAN%' could be improved, but it would just depend on the format of that column.
SELECT
DEPARTMENT_ID,
COUNT(*)
FROM EMPLOYEES
WHERE HIRE_DATE NOT LIKE '%JAN%'
GROUP BY DEPARTMENT_ID
HAVING COUNT(*)>5;
If you also want to list the individual employees along with these departments, then something like this might work:
SELECT a.*, b.count(*)
FROM EMPLOYEES AS a
INNER JOIN (
SELECT
DEPARTMENT_ID,
COUNT(*)
FROM EMPLOYEES
WHERE HIRE_DATE NOT LIKE '%JAN%'
GROUP BY DEPARTMENT_ID
HAVING COUNT(*)>5) AS b
ON a.department_id = b.department_id
WHERE a.HIRE_DATE NOT LIKE '%JAN%';
Again, though, I think you can leverage your schema to improve the where clause on HIRE_DATE. A like/not-like clause is generally going to be pretty slow.
Select the count from your inner query and join to it:
SELECT E.*, DEPT_COUNT
FROM EMPLOYEES E
JOIN (
SELECT DEPARTMENT_ID, COUNT(*) DEPT_COUNT
FROM EMPLOYEES
GROUP BY DEPARTMENT_ID
HAVING COUNT(*) > 5
) DC ON E.DEPARTMENT_ID = DC.DEPARTMENT_ID
AND HIRE_DATE NOT LIKE '%JAN%'

SQL group type of query

I am using SQL Developer and I have this table structure:
Name Null Type
-------------- -------- ------------
EMPLOYEE_ID NOT NULL NUMBER(6)
FIRST_NAME VARCHAR2(20)
LAST_NAME NOT NULL VARCHAR2(25)
DEPARTMENT_ID NUMBER(4)
SALARY NUMBER(8,2)
What I want to do is print out the department_id which has AT LEAST 2 employees with salaries greater than 10000.
I though this would be the query
select department_id
from employees
having count(select * from employees where salary > 10000) > 2
group by department_id;
but, from what I found out, you can't put a SELECT statement inside COUNT so now I an stuck and I don't know how else am I supposed to do this query. Any suggestion is welcome.
UPDATE: Please note that I want AT LEAST 2 employees to have salary > 10000, not all of them
SELECT Department_Id,
COUNT(*)
FROM Employee
WHERE Salary > 10000
GROUP BY Department_Id
HAVING COUNT(*) > 1
SQL Fiddle example.
SELECT department_id FROM employees
WHERE salary > 10000 GROUP BY department_id HAVING COUNT(*) >= 2;