using join and group by...having giving error - sql

SELECT d.DEPARTMENT_NAME
FROM Department d,
Student s
WHERE d.DEPARTMENT_ID = s.DEPARTMENT_ID
GROUP BY d.DEPARTMENT_NAME
HAVING COUNT(s.STUDENT_ID) < MAX(COUNT(s.STUDENT_ID));
The code is for joining student and department table. The department_id is key from department to student. Need to find departments with not the max number of students. Error is group function nested too deeply. Isn't nesting allowed up to 3?
Here is the exact error
ORA-00935: group function is nested too deeply

upd. Oh, shi~! I just mentioned the question's related to Oracle. I don't know its syntax for rank() function, but I think it should be really close to Sql Server.
Here it is:
;with Department(DEPARTMENT_ID, DEPARTMENT_NAME) as (
select 1, 'first' union all
select 2, 'second' union all
select 3, 'third'
)
, Student(STUDENT_ID, DEPARTMENT_ID) as (
select 1, 1 union all
select 2, 2 union all
select 3, 2 union all
select 4, 2 union all
select 5, 3 union all
select 6, 3 union all
select 7, 3
)
, DepOrdered as (
select
d.DEPARTMENT_ID,
d.DEPARTMENT_NAME,
s.StudentCnt,
-- rank departments by the number of students
rank() over (order by s.StudentCnt desc) as Rnk
from Department d
cross apply (
-- for every department count its students
select
count(s.STUDENT_ID) StudentCnt
from Student s
where
d.DEPARTMENT_ID = s.DEPARTMENT_ID
) s
)
select
DEPARTMENT_ID,
DEPARTMENT_NAME,
StudentCnt
from DepOrdered
where
-- Rnk = 1 would have all departments with max number of students
Rnk > 1

Related

Find departments with no employees

We were given an assignment in class to provide at the minimum two different solutions to find departments, which don't have any employees. As you can see from below I completed the task successfully.
An additional solution is extra credit, which I like to get. Unfortunately, I can't think of a third solution and was hoping someone can point me in the right direction. Would something with a MINUS function work?
Below is my setup and 2 working test cases. Any suggestions and help would be greatly appreciated.
CREATE TABLE departments
(
department_id,
department_name
) AS
SELECT 1, 'IT' FROM DUAL UNION ALL
SELECT 3, 'Sales' FROM DUAL UNION ALL
SELECT 2, 'DBA' FROM DUAL;
CREATE TABLE employees
(
employee_id,
first_name, last_name,
hire_date,
salary,
department_id
) AS
SELECT 1, 'Lisa', 'Saladino', DATE '2001-04-03', 100000, 1 FROM DUAL UNION ALL
SELECT 2, 'Abby', 'Abbott', DATE '2001-04-04', 50000, 1 FROM DUAL UNION ALL
SELECT 3, 'Beth', 'Cooper', DATE '2001-04-05', 60000, 1 FROM DUAL UNION ALL
SELECT 4, 'Carol', 'Orr', DATE '2001-04-06', 70000,1 FROM DUAL UNION ALL
SELECT 5, 'Vicky', 'Palazzo', DATE '2001-04-07', 88000,2 FROM DUAL UNION ALL
SELECT 6, 'Cheryl', 'Ford', DATE '2001-04-08', 110000,1 FROM DUAL UNION ALL
SELECT 7, 'Leslee', 'Altman', DATE '2001-04-10', 66666, 1 FROM DUAL UNION ALL
SELECT 8, 'Jill', 'Coralnick', DATE '2001-04-11', 190000, 2 FROM DUAL UNION ALL
SELECT 9, 'Faith', 'Aaron', DATE '2001-04-17', 122000,2 FROM DUAL;
/* departments with no employees */
select
d.department_id,
d.department_name
from
employees e
right join
departments d on e.department_id = d.department_id
group by
d.department_id, d.department_name
having
count(e.employee_id) = 0;
Output:
DEPARTMENT_ID DEPARTMENT_NAME
--------------------------------
3 Sales
SELECT
d.department_id,
d.department_name
FROM
departments d
WHERE
NOT EXISTS (SELECT * FROM employees e
WHERE d.department_id = e.department_id)
Output:
DEPARTMENT_ID DEPARTMENT_NAME
--------------------------------
3 Sales
You may also use left join as the following:
select
d.department_id,
d.department_name
from departments d left join employees e
on e.department_id=d.department_id
where e.employee_id is null
Also, you may use a sub query as the following:
select department_id, department_name
from departments
where department_id not in (select department_id from employees)
And with minus you may try:
select department_id, department_name
from departments
minus
select
d.department_id,
d.department_name
from departments d join employees e
on e.department_id=d.department_id
See a demo.
You can try below query-
SELECT *
FROM departments
WHERE department_id in (SELECT department_id
FROM departments
minus
SELECT DISTINCT department_id
FROM employees
);
Demo.

get items from one-level tree postgresql [duplicate]

I have a table with the structure:
Employee_ID Employee_Name Manager_ID
And, for each employee, I need to show the top manager ID. I mean, if for example, I have the EmployeeID 2 whose manager is 3 and, therefore, the number 3 has the manager number 5, I would have to show:
Empoyee_ID--Top_Manager
2 5
I need to do this with a Recursive CTE in Postgres.
Something like (for the level 2 manager) :
WITH RECURSIVE T AS
(
SELECT EMPLOYEE_ID, EMPLOYEE_NAME, MANAGER_ID, 1 AS MANAGER_LEVEL
FROM MyTable
UNION ALL
SELECT T.EMPLOYEE_ID, T.EMPLOYEE_NAME, E.MANAGER_ID, MANAGER_LEVEL + 1
FROM MyTable AS E
JOIN T ON T.MANAGER_ID = E.EMPLOYEE_ID
WHERE T.MANAGER_LEVEL = 1 --> limiting to level 2 - 1
)
SELECT EMPLOYEE_ID, EMPLOYEE_NAME, MANAGER_ID
FROM T
WHERE MANAGER_LEVEL = 2 --> retrieving only level 2, not level 1 and 2
That's a typical recursive query. Here is one way to do it in Postgres:
with recursive cte as (
select 1 lvl, employee_id, manager_id from mytable
union all
select c.lvl + 1, c.employee_id, t.manager_id
from cte c
inner join mytable t on t.employee_id = c.manager_id
)
select distinct on (employee_id) employee_id, manager_id top_manager
from cte c
order by employee_id, lvl desc
The cte climbs up the hierarchy while keeping track of the original employee id and of the relationship level. The outer query filters on the top manager per employee.

SQL: Trying to find total of one column and who has the highest value in that column

Link of tables:
https://docs.google.com/document/d/1df4zUTI6e5Rw8mJxZKkOWLBuRYzjAOPkkf8zsC_2mRo/edit?usp=sharing
I'm trying to write a query that displays the total (sum) of all the salaries in the salary column and the name of the individual who has the highest salary.
I used:
select name as highest_paid,sum(salary) as total_salary
from uscis,employer
where uscis.alienno=employer.alienno and salary=(select max(salary) from employer) group by name
I did get the result of name of the highest salary paid but i did not get the sum of the salary columns. I instead got 280,000 which is the highest salary.
My apologies in advance if I worded this question poorly.
So you do not want just the one persons salary? You want to sum the whole salary column from the Employer table? Assuming a 1:1 relationship between USCIS table and Employer, try this.
SELECT name as highest_paid, sum(salary) OVER() as everybodys_total_salary
FROM uscis
INNER JOIN employer
on uscis.alienno=employer.alienno
ORDER BY salary DESC
FETCH FIRST ROW ONLY
Description of oracle sum as an analytic function found here https://oracle-base.com/articles/misc/sum-analytic-function
Want to get the sum(salary) and max(salary) together?
with total as (
select sum(salary) as sum_salary from employer
), max as (
select a.name, b.salary from uscis a, employer b where a.alienno = b.alienno and b.salary = (select max(salary) from employer)
)
select * from max, total;
look at the dbfiddle
Use SUM as an analytic function and the ORDER BY the salary in DESCending order and get only the first row:
SELECT name as highest_paid,
SUM(salary) OVER () as total_salary
FROM uscis
INNER JOIN employer
ON ( uscis.alienno=employer.alienno )
ORDER BY salary DESC
FETCH FIRST ROW WITH TIES;
-- or FETCH FIRST ROW ONLY if you only ever want one row.
So, for your test data:
CREATE TABLE uscis ( AlienNo, Name, Nationality, City ) AS
SELECT 'A1023', 'Jeff', 'India', 'Atlanta' FROM DUAL UNION ALL
SELECT 'A1024', 'David', 'China', 'NY' FROM DUAL UNION ALL
SELECT 'A1025', 'Mark', 'UK', 'Charlotte' FROM DUAL UNION ALL
SELECT 'A2050', 'Shown', 'Germany', 'Astoria' FROM DUAL;
CREATE TABLE employer ( AlienNo, SSN, Dept, Salary ) AS
SELECT 'A1023', '111-22-4567', 'EE', 280000 FROM DUAL UNION ALL
SELECT 'A1024', '333-32-8767', 'CS', 180000 FROM DUAL UNION ALL
SELECT 'A1025', '444-45-3454', 'CE', 140000 FROM DUAL UNION ALL
SELECT 'A2050', '234-34-2234', 'ME', 180.000 FROM DUAL;
This outputs:
HIGHEST_PAID | TOTAL_SALARY
:----------- | -----------:
Jeff | 600180
db<>fiddle here

Count id_employee in another column

Could someone help me how to count the number of times an employee
"id" is next to the another employee in the "executive" column?
In the first picture I am sending the table and the results I want. In the second picture the result I have
SELECT id_employee, lastname, COUNT(id_employee)
FROM employees
WHERE id_employee IN (SELECT executive FROM employees)
GROUP BY lastname, id_employee;
1
2
You need a self-join:
select iemp.d_employee, emp.last_name, subordinates
from employee as emp
join
( -- count per executive
select executive, count(*) as subordinates
from employee
group by executive
) as emp_count
on emp.id_employee = emp_count.executive
When you switch to an Outer Join you can include employees which are not executives:
select id_employee, last_name,
coalesce(subordinates, 0) -- to get zero instead of NULL
from employee as emp
left join
( -- count per executive
select executive, count(*) as subordinates
from employee
group by executive
) as emp_count
on emp.id_employee = emp_count.executive
You can try below query, simple and sweet.
SELECT * INTO #EMPLOYEE FROM
(SELECT 1001 as ID_EMP,'JAMES' as LASTNAME,NULL as EXECUTIVE
UNION
SELECT 1002 as ID_EMP,'JENSEN' as LASTNAME,1001 as EXECUTIVE
UNION
SELECT 1003 as ID_EMP,'RUDY' as LASTNAME,1001 as EXECUTIVE
UNION
SELECT 1004 as ID_EMP,'CZARNY' as LASTNAME,1002 as EXECUTIVE
UNION
SELECT 1005 as ID_EMP,'RAMBUS' as LASTNAME,1002 as EXECUTIVE
UNION
SELECT 1006 as ID_EMP,'ADAM' as LASTNAME,1003 as EXECUTIVE
)A
SELECT ID_EMP,A.COUNT FROM (SELECT EXECUTIVE,COUNT(*) AS COUNT FROM #EMPLOYEE GROUP BY EXECUTIVE)A LEFT JOIN #EMPLOYEE E
ON E.ID_EMP = A.EXECUTIVE

SQL Nested select in From caluse

I am confuse, can we write SELECT statement in FROM clause and if yes why can it be.
SELECT v.employee_id, v.last_name, v.lev
FROM
(SELECT employee_id, last_name, LEVEL lev
FROM employees v
START WITH employee_id = 100
CONNECT BY PRIOR employee_id = manager_id) v
WHERE (v.employee_id, v.lev) IN
(SELECT employee_id, 2 FROM employees);
The answer is yes, you can use. The select clause in the from will act as a inline view(consider it as a temporary table that databse creates to hold the results).
For example:
SELECT sdt sdat
FROM (SELECT SYSDATE sdt FROM dual);
In the above query, SELECT SYSDATE sdt FROM dual is executed first, and output would be like:
sdt
---
08-Dec-2016 16:20:56
Then, using this as a temp table(which is called an inline view in such cases), oracle will execute your outer select on this data. Hence SELECT sdt FROM... executes, giving the final output as:
sdat
----
08-Dec-2016 16:20:56
I think you are looking for a recursive cte in sql server which would be something like.....
WITH X (employee_id, last_name, lev )
AS (
SELECT employee_id, last_name, 0 AS lev
FROM employees
WHERE manager_id IS NULL
UNION ALL
SELECT e.employee_id, e.last_name , lev + 1
FROM employees e
INNER JOIN x ON x.employee_id = e.manager_id
)
SELECT v.employee_id, v.last_name, v.lev
FROM X
WHERE lev = 2