Disconnected from the rest of the join graph - sql

My task is to query a database, selecting the number of persons that work in the most numerous department. I do the following:
select count(*) from Persons join Departments using (Department_id)
where Department_id =
(select Department_id from Persons join Departments using (Department_id)
group by Department_id having count(*) =
(select max(count(*)) from Persons
join Departments using (Department_id) group by Department_id)
);
And it works fine, but I get a warning, that Persons is disconnected from the rest of the join graph. Is there something faulty with this solution? Or perhaps it could be done easier?

I'm not a fan of the max(count(*)) construct. It is an Oracle extension and it changes the semantics of group by (which in all other cases returns one row per group). How about just:
with d as (
select count(*) as cnt
from persons
group by department_id
)
select *
from d
where cnt = (select max(cnt) from d);

You are right, the join is in fact redundant. Here is my new proposed solution:
select count(*) from Persons
where Department_id is not null
group by Department_id
having count(*) = (select max(count(*)) from Persons
where Department_id is not null
group by Department_id);

Related

Department has Maximum Staff

Write a query to display the name of the department that has the maximum staff count order by department name.
This is the schema of my problem:
I tried this:
select d.department_name
from department d
inner join staff s on d.department_id=s.department_id
group by d.department_name
having count(s.staff_id) >= all
( select count(s.staff_id) as cnt
from department d
inner join staff s on d.department_id=s.department_id
group by department_name )
order by d.department_name desc;
and I was able to pass one test case which results in 'SE' department, but I wasn't able to pass another test case.I don't know what second testcase want. I am not sure what I have done wrong in my code above.
You can use the windows function as follows:
select department_name, cnt
from
(select department_name, rank() over (order by cnt desc) as rn, cnt
from
(select d.department_name, count(1) cnt
from department d inner join staff s
on d.department_id=s.department_id
group by d.department_name))
where rn = 1
order by department_name

Missing expression problem in SQL using Oracle

I want to get the number of employees by department and I wrote this script using Oracle but it always says that there is a missing expression
The columns used in my tables :
department :name (the name of the department) -
depnum (the id of the department"primary key"),
employee : empnum (the id of the employee) -
depnum (the id of the department in which the employee in question is working "foreign key")
Query:
select
s.name
from
department s
inner join
employee p on s.depnum = p.depnum
group by
s.name
having
count(p.empnum) = max(select count(p.empnum)
from employee p, department s
where s.depnum = p.depnum
group by s.name) ;
If you want the number of employees by department, I would expect something like this:
select s.name, count(*) as num_employees
from department s inner join
employe p
on s.depnum = p.depnum
group by s.name ;
If you want the department names with the maximum number of names, you can use a having clause:
select s.name, count(*) as num_employees
from department s inner join
employe p
on s.depnum = p.depnum
group by s.name
having count(*) = (select max(cnt)
from (select count(*) as cnt
from employee e2
group by e2.depnum
) e2
);
The problem with your query is that you are attempting to take the max() of a subquery. That syntax is not allowed -- and not necessary.
you sql statement is not correct that's why it thrown that error. I think you tried something like below
select s.name
from department s
inner join employe p on s.depnum=p.depnum
group by s.name
having count(p.empnum)=
select max(cnt) from
(
select count(p.empnum) as cnt
from employe p join department s
on s.depnum=p.depnum
group by s.name
) t;

The best way to find the Department with the maximum total salary Postgresql

Lets we have 2 standard tables Employees and Departments
CREATE TABLE departments (
id SERIAL PRIMARY KEY,
name VARCHAR
);
CREATE TABLE employees (
id SERIAL PRIMARY KEY,
department_id INTEGER,
name VARCHAR,
salary NUMERIC(13,2)
);
What is the best way to find the name of the department with the maximum employees' total salary.
I've found two solutions and they looks too complicated for such simple task.
Using rank()
SELECT name FROM (
SELECT name, rank() OVER ( ORDER BY salary DESC ) AS rank
FROM (
SELECT
departments.name,
sum(salary) AS salary
FROM employees
JOIN departments ON department_id = departments.id
GROUP BY departments.name
) AS t1
) AS t2
WHERE rank = 1;
Using subquery
WITH t1 AS (SELECT
departments.name,
sum(salary) AS salary
FROM employees
JOIN departments ON departments.id = employees.department_id
GROUP BY departments.name
)
SELECT name FROM t1
WHERE t1.salary = (SELECT max(salary) FROM t1);
At first glance using rank should be less efficient as it performs unnecessary sorting. Though EXPLAIN shows that the first option is more efficient.
Or maybe someone suggests another solution.
So, what is the best way to find the Department with the maximum total salary using postgres?
I would write the rank() as:
SELECT *
FROM (SELECT d.name, SUM(e.salary) AS salary,
RANK() OVER (ORDER BY SUM(e.salary)) as rnk
FROM employees e JOIn
departments d
ON e.department_id = d.id
GROUP BY d.name
) d
WHERE rnk = 1;
(The additional subquery should not affect performance, but it adds nothing to clarify the query either.)
Because window functions are built-in to the database, the database has methods for making them more efficient. And there is overhead for getting the MAX() as well. But, to be honest, I would expect both methods to have similar performance.
I should note that if you want only one department returned -- even when there are ties -- then the simplest method is:
SELECT d.name, SUM(e.salary) AS salary
FROM employees e JOIn
departments d
ON e.department_id = d.id
GROUP BY d.name
ORDER BY SUM(e.salary) DESC
FETCH FIRST 1 ROW ONLY

SQL Oracle - optimum query

I have three tables with the following schemas:
Persons(Person_id, Department_id, Sure_name, Name, Birthyear, Height, Manager_id)
Departments (Department_id, Department_Name, Code)
Salaries (Salary_id, Person_id, Salary)
I need to run a query which will display the name of the department, for which the difference between the workers' minimum and maximum heights is the greatest.
I have done it the following way:
select Department_Name
from Departments
where Department_id = (select Department_id
from Departments
join Persons
using (Department_id)
group by Department_id
having max(height) - min(height) = (select max(max(height) - min(height))
from Departments
join Persons
using (Department_id)
group by Department_id));
And it works fine, just I'm not really sure if the solution is optimum, there are two nested queries here, I wonder if I could achieve the same in a simpler way.
Try this.
SELECT Department_Name
FROM Departments D
INNER JOIN (SELECT Department_id,
Max(height) - Min(height) AS diff
FROM Departments
JOIN Persons
ON using (Department_id)
WHERE ROWNUM = 1
GROUP BY Department_id
ORDER BY diff DESC) B
ON d.Department_id = b.Department_id
or use Window Function
SELECT Department_id,
Department_Name
FROM (SELECT Row_number()OVER(ORDER BY Max(height)- Min(height) desc ) rn,
Department_id,
Department_Name
FROM Departments
JOIN Persons
ON using(Department_id)
GROUP BY Department_id,
Department_Name)a
WHERE rn = 1
This might work for you, a bit complicated but using the analytic function RANK() probably simplifies things a bit over using nothing but aggregates:
SELECT d.department_id, d.department_name, d.code, p1.height_diff
FROM departments d INNER JOIN (
SELECT department_id, height_diff, RANK() OVER ( ORDER BY height_diff DESC ) AS rn
FROM (
SELECT department_id, MAX(height) - MIN(height) AS height_diff
FROM Persons
GROUP BY department_id
)
) p1
ON d.department_id = p1.department_id
WHERE p1.rn = 1;
Please see SQL Fiddle demo here. N.B. I had previously ordered incorrectly, now corrected to DESC.

SELECT specific information

My tables are structured like this (there are more values in the tables but I only wrote the ones relevant to this):
Department(dep_id, dep_name)
Employee(dep_id)
I need to display dep_name and the number of employees in every department, except once specific department (let's call it DepX) and only the departments with more than one employee.
I tried multiple methods to solve this but none of them worked.
Some methods I tried:
SELECT department.dep_name, COUNT(employee.dep_id) AS NumberOfEmployees FROM employee
INNER JOIN department ON employee.dep_id=department.dep_id
WHERE dep_name<>'DepX'
GROUP BY dep_id
HAVING COUNT(employee.dep_id) > 1;
SELECT dep_name FROM department
WHERE dep_name <>'DepX'
UNION
SELECT COUNT(*) FROM employee
WHERE COUNT(*) > 1
GROUP BY dep_id;
I can't figure this out. Thanks!
The first example does now work because you're including dep_name in your results without an aggregation but not grouping on it.
You can either use the department name in your grouping instead of the ID:
SELECT department.dep_name, COUNT(employee.dep_id) AS NumberOfEmployees FROM employee
INNER JOIN department ON employee.dep_id=department.dep_id
WHERE dep_name<>'DepX'
GROUP BY department.dep_name
HAVING COUNT(employee.dep_id) > 1;
or do the COUNT in a subquery:
SELECT department.dep_name,
e.NumberOfEmployees
FROM department
INNER JOIN (SELECT dep_id,
COUNT(*) NumberOfEmployees
FROM employee
GROUP BY dept_id
HAVING COUNT(dept_id) > 1
) e
ON department.dep_id = e.dep_id
WHERE dep_name<>'DepX'
SELECT department.dep_name, COUNT(employee.dep_id) AS NumberOfEmployees FROM employee
INNER JOIN department ON employee.dep_id=department.dep_id
WHERE department.dep_name not in('DepX')
GROUP BY department.dep_name
HAVING COUNT(employee.dep_id) > 1;
update your table alias per your need
TEST this. This query help you return not only dept_name, it can return all fields from Department if you want:
SELECT d.*, A.numOfEmployees
FROM Department d,
(
SELECT e.dep_id, COUNT(*) numOfEmployees
FROM Employee e
GROUP BY e.dep_id
HAVING COUNT(*) > 1
) A
WHERE d.dep_id = A.dep_id
AND d.dep_name != 'DepX'