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
);
Related
im solving the following task with analytic functions and im stuck.
task: Write a query that shows the latest hired employee per department. In case of ties, use the lowest employee ID.
select a.EMPLOYEE_ID,
a.DEPARTMENT_ID,
a.FIRST_NAME,
a.LAST_NAME,
a.HIRE_DATE,
a.JOB_ID
from (select ROW_NUMBER() over (PARTITION by department_id order by hire_date desc)
from hr.EMPLOYEES a) A
where A = 1 ;
You need to include the columns you want to select in the outer query in the SELECT clause of the inner query and need to give an alias to the ROW_NUMBER computed value:
select EMPLOYEE_ID,
DEPARTMENT_ID,
FIRST_NAME,
LAST_NAME,
HIRE_DATE,
JOB_ID
from (
select EMPLOYEE_ID,
DEPARTMENT_ID,
FIRST_NAME,
LAST_NAME,
HIRE_DATE,
JOB_ID,
ROW_NUMBER() over (PARTITION by department_id order by hire_date desc) AS rn
from hr.EMPLOYEES
)
where rn = 1 ;
You still need to address the second part of the question:
In case of ties, use the lowest employee ID.
However, since this appears to be a homework question, I'll leave that for you to solve.
I am trying to compile a query which gives me the highest salary per each department and for each unique employee. The complexity is that 1 employee can be part of multiple departments.
In case the same employee has the highest salary in several departments, only the department with a lower salary should show. This is my start but I am not sure how to continue from here:
select max(salary) as salary, dd.dept_name,d.emp_no
from salaries s
inner join dept_emp d on
s.emp_no=d.emp_no
inner join departments dd on
d.dept_no=dd.dept_no
group by 2,3;
My output is:
What should I modify from here?
For an employee, you seem to only want to include the department with the smallest salary. I would recommend using window functions:
select s.*
from (select s.*,
rank() over (partition by dept_name order by salary desc) as seqnum_d
from (select s.*, d.dept_name,
rank() over (partition by dept_name order by salary) as seqnum_ed
from salaries s join
dept_emp d
on s.emp_no = d.emp_no join
departments dd
d.dept_no = dd.dept_no
) s
where seqnum_ed = 1
) s
where seqnum_d = 1;
Something like this?
select m.salary, m.emp_no, salary.dept_name from salary,
(select emp_no, min(salary) salary from salary group by emp_no) m
where
m.emp_no=salary.emp_no and m.salary=salary.salary;
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!
I'm working on Oracle SQL and HR database, I'm trying to select maximum salary in department like this:
SELECT MAX(salary), department_id
FROM employees GROUP BY department_id;
It works fine, but I want to know >who< is earning the most, so I simply change query this way:
SELECT first_name, last_name, MAX(salary), department_id
FROM employees GROUP BY department_id;
And it's wrong. Could you help me, please?
The most efficient way to do this sort of analysis is generally to use analytic functions (window functions). Something like
SELECT first_name,
last_name,
salary,
department_id
FROM (SELECT e.*,
rank() over (partition by department_id
order by salary desc) rnk
FROM employees e)
WHERE rnk = 1
Depending on how you want to handle ties (if two people in the department are tied for the maximum salary, for example, do you want both people returned or do you want to return one of the two arbitrarily), you may want to use the row_number or dense_rank functions rather than rank.
Create a view:
create view max_salary as select max(salary), department_id from employees group by department_id
Then create a query:
select first_name, last_name, salary, department_id
from employees a, max_salary b
where a.department_id = b.department_id
and a.salary = b.salary
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%'