SQL - counting max number of employees and excluding string using subqueries - sql

These are my two tables:
employee
employee_id employee_name job manager_id hire_date salary commission department_id
----------------------------------------------------------------------- -------------------------------------
7839 KING PRESIDENT 20-NOV- 01 5000 50
7596 JOST VICE PRESIDENT 7839 04-MAY- 01 4500 50
7603 CLARK VICE PRESIDENT 7839 12-JUN- 01 4000 50
7566 JONES PUBLIC ACCOUNTANT 7596 05-APR- 01 3000 10
7886 STEEL PUBLIC ACCOUNTANT 7566 08-MAR- 03 2500 10
7610 WILSON ANALYST 7596 03-DEC- 01 3000 20
7999 WOLFE ANALYST 7610 15-FEB- 02 2500 20
7944 LEE ANALYST 7610 04-SEP- 06 2400 20
7900 FISHER SALESMAN 7603 06-DEC- 01 3000 500 30
7921 JACKSON SALESMAN 7900 25-FEB- 05 2500 400 30
7952 LANCASTER SALESMAN 7900 06-DEC- 06 2000 150 30
7910 SMITH DATABASE ADMINISTRATOR 7596 20-DEC- 01 2900 40
7788 SCOTT PROGRAMMER 7910 15-JAN- 03 2500 40
7876 ADAMS PROGRAMMER 7910 15-JAN- 03 2000 40
7934 MILLER PROGRAMMER 7876 25-JAN- 02 1000 40
8000 BREWSTER TBA 22-AUG- 13 2500
department
department_id department_name address
------------- -------------------- --------------------
10 ACCOUNTING NEW YORK
20 RESEARCH DALLAS
30 SALES CHICAGO
40 IT DALLAS
50 EXECUTIVE NEW YORK
60 MARKETING CHICAGO
I need to write a statement using subqueries (not joins) to display the name and address of all departments (excluding departments in Dallas) having the maximum number of employees. I cannot have any hard coding except the string 'DALLAS'
The result should look like this:
DEPARTMENT_NAME ADDRESS
-------------------- --------------------
EXECUTIVE NEW YORK
SALES CHICAGO
I'm at a loss on doing this without joins. Here are my three tries:
SELECT department_name, address
FROM department
WHERE department_id NOT IN
(SELECT department_id
FROM department
WHERE UPPER(address) + 'DALLAS')
ORDER BY department_name;
SELECT department_name, address
FROM department
WHERE department_id NOT IN
(SELECT department_id
FROM department
WHERE UPPER(address) = 'DALLAS')
AND department_id > ALL
(select COUNT(department_id) FROM employee GROUP BY department_id)
ORDER BY department_id;
select *
from department
where department_id in (select department_id
from employee
group by department_id
having count(*) = (select max(num)
from (select department_id,
count(*) as num
from employee_tbl
where address != 'DALLAS'
group by department_id)));
Can anyone PLEASE tell me if I'm even getting close and guide me in the right direction? Thanks

The departments with the maximum number of employees (using a single table scan):
SELECT department_id
FROM (
SELECT department_id,
RANK() OVER ( ORDER BY num_employees DESC ) AS rnk
FROM (
SELECT department_id,
COUNT(1) AS num_employees
FROM employees
GROUP BY department_id
)
)
WHERE rnk = 1;
Finding the departments not in DALLAS:
SELECT department_id
FROM departments
WHERE address <> 'DALLAS'
So combining the two:
SELECT department_id
FROM (
SELECT department_id,
RANK() OVER ( ORDER BY num_employees DESC ) AS rnk
FROM (
SELECT department_id,
COUNT(1) AS num_employees
FROM employees
WHERE department_id IN (
SELECT department_id
FROM departments
WHERE address <> 'DALLAS'
)
GROUP BY department_id
)
)
WHERE rnk = 1;

maybe something like this?
select department_name, address
from department
where department_id in
(SELECT e.department_id
FROM employee e
group by e.department_id
having count(*) = (
select max(count(e2.employee_id))
FROM employee e2
WHERE department_id NOT IN (SELECT department_id
FROM department
WHERE UPPER(address) = 'DALLAS')
group by e2.department_id
)
)
and UPPER(address) != 'DALLAS'
but it is not the best query in plane :) very strange
In your query Ellen I did not understand where from the table
employee_tbl

Related

Cube SQL ORA-00936 missing expression

im trying using cube in my query but it didnt work
this is my query
select department_id, job_id , salary/12 as "monthly_salary"
from employees
where department_id
(select department_id from departments)
group by cube(department_id,job_id)
order by department_id,job_id;
by using 2 tables which is employees and departments
forgive me if im asking too much,im still new to this :)
Not entirely sure what you are asking, but here is an example of a cube to get totals by deptno, job and the combination of the two
SQL> select deptno,job,sum(sal) from scott.emp
2 group by CUBE(deptno,job)
3 order by deptno,job;
DEPTNO JOB SUM(SAL)
---------- --------- ----------
10 CLERK 1300
10 MANAGER 2450
10 PRESIDENT 5000
10 8750
20 ANALYST 6000
20 CLERK 1900
20 MANAGER 2975
20 10875
30 CLERK 950
30 MANAGER 2850
30 SALESMAN 5600
30 9400
ANALYST 6000
CLERK 4150
MANAGER 8275
PRESIDENT 5000
SALESMAN 5600
29025
You're missing
IN keyword (for list of departments)
SUM function for salaries
I included ROUND so that it looks prettier
So:
SELECT department_id,
job_id,
ROUND (SUM (salary) / 12) monthly_salary
FROM employees
WHERE department_id IN (SELECT department_id FROM departments)
GROUP BY CUBE (department_id, job_id)
ORDER BY department_id, job_id

find emp_names,max,min salary and number of employees on each department?

I use oracle 11g , so i have 2 tables(employees,departments):
desc employees: desc departments
EMPLOYEE_ID DEPARTMENT_ID
FIRST_NAME DEPARTMENT_NAME
LAST_NAME MANAGER_ID
EMAIL LOCATION_ID
PHONE_NUMBER
HIRE_DATE
JOB_ID
SALARY
COMMISSION_PCT
MANAGER_ID
DEPARTMENT_ID
and i want to get
employee_name,emp_names,emp_salary,dep_id,dep_names,max salary on each
dep , and min salary on each dep , and number of employees on each
department .
so i do this qouery:
select FIRST_NAME,DEPARTMENT_ID,max(SALARY),min(SALARY),count(EMPLOYEE_ID)
from employees join departments on employees.department_id = departments.departm
ent_id group by first_name,department_id;
but its give an error:
ERROR at line 1: ORA-00918: column ambiguously defined
however does my sql query right ?
I don't have your tables so I created views out of Scott's ones, to simulate what you have.
SQL> create or replace view employees as
2 select empno employee_id,
3 ename last_name,
4 deptno department_id,
5 sal salary
6 from emp;
View created.
SQL> create or replace view departments as
2 select deptno department_id,
3 dname department_name
4 from dept;
View created.
SQL>
Here's how I understood the question: list of employees per department should be separated from the rest (minimums, maximums, counts).
So: list of employees:
SQL> select d.department_name, e.last_name
2 from departments d join employees e on d.department_id = e.department_id
3 order by d.department_name;
DEPARTMENT_NAM LAST_NAME
-------------- ----------
ACCOUNTING CLARK
ACCOUNTING KING
ACCOUNTING MILLER
RESEARCH JONES
RESEARCH FORD
RESEARCH ADAMS
RESEARCH SMITH
RESEARCH SCOTT
SALES WARD
SALES TURNER
SALES ALLEN
SALES JAMES
SALES BLAKE
SALES MARTIN
14 rows selected.
Aggregates: outer join for departments that don't have any employees:
SQL> select d.department_name,
2 min(e.salary) min_sal,
3 max(e.salary) max_sal,
4 count(e.employee_id) cnt_emp
5 from departments d left join employees e on d.department_id = e.department_id
6 group by d.department_name
7 order by d.department_name;
DEPARTMENT_NAM MIN_SAL MAX_SAL CNT_EMP
-------------- ---------- ---------- ----------
ACCOUNTING 1300 5000 3
OPERATIONS 0
RESEARCH 800 3000 5
SALES 950 2850 6
LISTAGG allows you to list all employees per department in the same statement, though; see line 5. I, somehow, doubt that you learnt about that function yet (as you struggle with such a problem).
SQL> select d.department_name,
2 min(e.salary) min_sal,
3 max(e.salary) max_sal,
4 count(e.employee_id) cnt_emp,
5 listagg(e.last_name, ', ') within group (order by e.last_name) employees
6 from departments d left join employees e on d.department_id = e.department_id
7 group by d.department_name
8 order by d.department_name;
DEPARTMENT_NAM MIN_SAL MAX_SAL CNT_EMP EMPLOYEES
-------------- ---------- ---------- ---------- -------------------------------------------
ACCOUNTING 1300 5000 3 CLARK, KING, MILLER
OPERATIONS 0
RESEARCH 800 3000 5 ADAMS, FORD, JONES, SCOTT, SMITH
SALES 950 2850 6 ALLEN, BLAKE, JAMES, MARTIN, TURNER, WARD
SQL>

Aggregate function and join on 2 conditions

I have this task for Oracle. It requires me to display the departments names(department is a table containing the manager_id for that table, department_id and department_name), the manager_id for that department, the name of the manager(found in employees table) and the average salary for that department(salary of each employee is also found in employees). As soon as I try to retrieve the manager name(I suppose by comparing his id in dept with the one in employees) it messes up my averages. Without it(Like following) it works just fine
SELECT d.department_name, AVG(e.salary) as "Salaries"
FROM employees e join departments d on e.department_id=d.department_id
WHERE d.manager_id=e.employee_id
GROUP BY e.department_id, d.department_name,d.manager_id
ORDER BY AVG(e.salary)
Can someone help me solve this and perhaps explain why I mess it up?
WITH factoring clause selects average salary; it is then joined to other tables
SQL> with avgsal as
2 (select e.department_id, round(avg(e.salary)) avg_sal
3 from employees e
4 group by e.department_id
5 )
6 select d.department_id,
7 d.department_name,
8 m.last_name manager,
9 a.avg_sal
10 from departments d
11 join employees m on m.department_id = d.department_id
12 and m.employee_id = d.manager_id
13 join avgsal a on a.department_id = d.department_id
14 order by a.avg_sal;
DEPARTMENT_ID DEPARTMENT_NAME MANAGER AVG_SAL
------------- -------------------- ------------------------- ----------
50 Shipping Fripp 3476
30 Purchasing Raphaely 4150
10 Administration Whalen 4400
60 IT Hunold 5760
40 Human Resources Mavris 6500
100 Finance Greenberg 8601
80 Sales Russell 8956
20 Marketing Hartstein 9500
70 Public Relations Baer 10000
110 Accounting Higgins 10154
90 Executive King 19333
11 rows selected.
SQL>
A quick check for 2 departments:
SQL> select department_id, round(avg(salary)) avg_sal, count(*) "# of employees"
2 from employees
3 where department_id in (20, 30)
4 group by department_id
5 order by 1;
DEPARTMENT_ID AVG_SAL # of employees
------------- ---------- --------------
20 9500 2
30 4150 6
SQL>
Introduce a correlated subquery in select for manager name in your query.
SELECT d.department_name,
AVG(e.salary) AS "Salaries",
(SELECT first_name
||' '
||last_name
FROM employees i
WHERE i.employee_id = d.manager_id) AS manager_name
FROM employees e
join departments d
ON e.department_id = d.department_id
GROUP BY e.department_id,
d.department_name,
d.manager_id
ORDER BY Avg(e.salary);

SQL - select name and address of all departments having max number of employees

I have these tables:
department
DEPARTMENT_ID DEPARTMENT_NAME ADDRESS
------------- -------------------- --------------------
10 ACCOUNTING NEW YORK
20 RESEARCH DALLAS
30 SALES CHICAGO
40 IT DALLAS
50 EXECUTIVE NEW YORK
60 MARKETING CHICAGO
employee
Employee_ID employee_name job manager_ID hire_date salary commission department_ID
------------------------------------------------------------------------------------------------------------
7839 KING PRESIDENT 20-NOV-01 5000 50
7596 JOST VICE PRESIDENT 7839 04-MAY-01 4500 50
7603 CLARK VICE PRESIDENT 7839 12-JUN-01 4000 50
7566 JONES PUBLIC ACCOUNTANT 7596 05-APR-01 3000 10
7886 STEEL PUBLIC ACCOUNTANT 7566 08-MAR-03 2500 10
7610 WILSON ANALYST 7596 03-DEC-01 3000 20
7999 WOLFE ANALYST 7610 15-FEB-02 2500 20
7944 LEE ANALYST 7610 04-SEP-06 2400 20
7900 FISHER SALESMAN 7603 06-DEC-01 3000 500 30
7921 JACKSON SALESMAN 7900 25-FEB-05 2500 400 30
7952 LANCASTER SALESMAN 7900 06-DEC-06 2000 150 30
7910 SMITH DATABASE ADMINISTRATOR 7596 20-DEC-01 2900 40
7788 SCOTT PROGRAMMER 7910 15-JAN-03 2500 40
7876 ADAMS PROGRAMMER 7910 15-JAN-03 2000 40
7934 MILLER PROGRAMMER 7876 25-JAN-02 1000 40
8000 BREWSTER TBA 22-AUG-13 2500
I need to display the name and address with the exception of Dallas, having the maximum number of employees.
I have written this:
SELECT department_name, address
FROM department
WHERE department_id IN
(SELECT MAX(department_id)
FROM department
WHERE UPPER(address) != 'DALLAS')
ORDER BY department_name;
But I'm only getting one line
DEPARTMENT_NAME ADDRESS
-------------------- --------------------
MARKETING CHICAGO
What am I doing wrong?
Not sure I understood your question, but I think you want this:
with emp_count as (
select d.department_name,
d.address,
count(*) as num_emps,
max(count(*)) over () as max_count
from department d
join employee e on d.department_id = e.department_id
where address <> 'DALLAS'
group by d.department_name, d.address
)
select *
from emp_count
where num_emps = max_count;
This returns:
DEPARTMENT_NAME | ADDRESS | NUM_EMPS
----------------+----------+---------
SALES | CHICAGO | 3
EXECUTIVE | NEW YORK | 3
SQLFiddle example: http://sqlfiddle.com/#!4/05db83/1
Based on your sample data the city seems to be recorded in the address column of the department table, and that more than one department can have the same city.
Given this, and the fact that you want to "exclude Dallas," as you say, I would assume you want to filter out all departments where the associated address column is 'Dallas'.
However, I don't know if...
you want to exclude departments at Dallas if they happen to be tied with other department(s) for the most employees, or
if you want to exclude departments at Dallas from being considered when determining what the highest number of employees is at any department.
If (1) is true:
select *
from department_tbl
where department_id in (select department_id
from employee_tbl
group by department_id
having count(*) = (select max(num_emps)
from (select department_id,
count(*) as num_emps
from employee_tbl
group by department_id)))
and address <> 'DALLAS';
If (2) is true:
select *
from department_tbl
where department_id in (select department_id
from employee_tbl
group by department_id
having count(*) = (select max(num_emps)
from (select department_id,
count(*) as num_emps
from employee_tbl
where address <> 'DALLAS'
group by department_id)));
Try this.
SELECT d.department_name,
d.address
FROM department d
JOIN employee e
ON ( d.department_id = e.department_id )
WHERE d.address <> 'DALLAS'
GROUP BY d.department_name,
d.address
HAVING Count(*) = (SELECT Max(cnt)
FROM (SELECT Count(*) CNT
FROM employee e
WHERE NOT EXISTS (SELECT 'x'
FROM department d
WHERE d.department_id =
e.department_id
AND d.address = 'DALLAS')
GROUP BY department_id))
select e.department_id, d.department_name, count(e.department_id)
from employee e, department d
where e.department_id = d.department_id
group by e.department_id, d.department_name
having count(e.department_id)=(select max(count(department_id))
from employee
group by department_id);
Hope it helps

SQL - oracle - how to select specific department from join results

Can you guys help me with this query? I want to modify it so that it only shows me those departments with at least 3 employees from this query (with the 78%), and not from (the original table of employees/department). Every time i try " having COUNT (department_ID) or # the WHERE clause it gives me an error. Do i need to do a 2nd join? Thank you
select *
from
(
SELECT b.employee_id, b.employee_name,b.salary, a.department_id,
NVL(a.department_name, 'N/A') as dept_name,
max(b.salary) over (partition by a.department_id) as max_sal
FROM department a, employee b
WHERE a.department_id(+) = b.department_id
) z
WHERE salary > (max_sal*.78 )
Results:
EMPLOYEE_ID EMPLOYEE_NAME SALARY DEPARTMENT_ID DEPT_NAME MAX_SAL
7566 JONES 3000 10 ACCOUNTING 3000
7886 STEEL 2500 10 ACCOUNTING 3000
7944 LEE 2400 20 RESEARCH 3000
7999 WOLFE 2500 20 RESEARCH 3000
7610 WILSON 3000 20 RESEARCH 3000
7921 JACKSON 2500 30 SALES 3000
7900 FISHER 3000 30 SALES 3000
7788 SCOTT 2500 40 IT 2900
7910 SMITH 2900 40 IT 2900
7603 CLARK 4000 50 EXECUTIVE 5000
7596 JOST 4500 50 EXECUTIVE 5000
7839 KING 5000 50 EXECUTIVE 5000
8000 BREWSTER 2500 N/A 2500
13 rows selected
This are RESULTS I need to get:
EMPLOYEE_ID EMPLOYEE_NAME SALARY DEPARTMENT_ID DEPT_NAME MAX_SAL
7944 LEE 2400 20 RESEARCH 3000
7999 WOLFE 2500 20 RESEARCH 3000
7610 WILSON 3000 20 RESEARCH 3000
7603 CLARK 4000 50 EXECUTIVE 5000
7596 JOST 4500 50 EXECUTIVE 5000
7839 KING 5000 50 EXECUTIVE 5000
6 rows selected
You can do the calculation using an analytic function in another subquery:
select de.*
from (select de.*, count(*) over (partition by department_id) as cnt
from (SELECT e.employee_id, e.employee_name, d.salary, d.department_id,
NVL(d.department_name, 'N/A') as dept_name,
max(e.salary) over (partition by d.department_id) as max_sal
FROM department d JOIN
employee e
ON d.department_id = e.department_id
) de
where salary > max_sal*.78
) de
where cnt >= 3;
The outer join doesn't seem necessary so I replaced it with an inner join and modern join syntax. I also changed the table aliases to be abbreviations for the tables. It makes the code easier to read.