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

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.

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

what does count(*) do exactly? [duplicate]

This question already has answers here:
What is the difference between count(0), count(1).. and count(*) in mySQL/SQL?
(9 answers)
Closed 3 years ago.
I use oracle 11g. I want maximum and minimum salary, and count of employees for each department, so I do this :
select d.department_id, d.department_name, max(salary), min(salary), count(*)
from employees e ,
departments d
where e.department_id = d.department_id
group by d.department_id, d.department_name;
and it works :
DEPARTMENT_ID DEPARTMENT_NAME MAX(SALARY) MIN(SALARY) COUNT(*)
------------- ------------------------------ ----------- ----------- ----------
100 Finance 12008 6900 6
50 Shipping 8200 2100 45
70 Public Relations 10000 10000 1
30 Purchasing 11000 2500 6
90 Executive 24000 17000 3
10 Administration 4400 4400 1
110 Accounting 12008 8300 2
40 Human Resources 6500 6500 1
20 Marketing 13000 6000 2
60 IT 9000 4200 5
80 Sales 14000 6100 34
11 rows selected.
So what does count(*) mean? Count departments or what ?
count(*) returns the rows that match the where statement.
In your case its where e.department_id=d.department_id.
Because you applied a group by your count(*) will return the count of rows for each group (d.department_id).
This means you will get the count of employees (e.department_id) for each department (d.department_id).

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

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

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

About sql subquery

What to do when we want to select salary of a employee greater than many (lets say 12) employees's salary from a table. I know that we'll have to use a subquery but writing it as :-
Select ename,salary
from emp
where salary>( select salary
from emp
where ename='A'||ename='B'.....)
it could be written like that but its not a good approach. Please suggest some useful query for it.
If you know the 12 employees, I think you want to write the query as:
Select ename,salary
from emp
where salary> (select max(salary)
from emp
where ename in ('A', 'B', . . . )
)
IN is much more convenient than a bunch of or statements. And, the subquery needs to return one value, the maximum salary.
Select ename,salary
from emp
where salary > (
select salary
from
(
select
salary,
rownum as rn
from emp
order by salary
)
where rn = 12
)
This is not exact code that you may use, but it should help you.
You can use RANK() function.
Example from article at oracle-base.com:
SELECT empno,
deptno,
sal,
RANK() OVER (PARTITION BY deptno ORDER BY sal) "rank"
FROM emp;
EMPNO DEPTNO SAL rank
---------- ---------- ---------- ----------
7934 10 1300 1
7782 10 2450 2
7839 10 5000 3
7369 20 800 1
7876 20 1100 2
7566 20 2975 3
7788 20 3000 4
7902 20 3000 4
7900 30 950 1
7654 30 1250 2
7521 30 1250 2
7844 30 1500 4
7499 30 1600 5
7698 30 2850 6
I can see two different interpretations of your requirement.
1. What employees earn more than 12 other (random) employees
and
2. What employees earn more than 12 specific employees
This query solves the first requirement, although it will become slow as hell on larger datasets.
select *
from emp a
where 12 = (select count(*)
from emp b
where b.salary < a.salary);
This query solves the second requirement
select *
from emp
where salary > all(select salary
from emp
where emp_id in(1,2,3,4,5)
)