Select EMP with max SAL from each DEPT - sql

I´m having a bad time with a SQL query. I´m using oracle default tables:
'EMP' TABLE
http://imageshack.us/photo/my-images/850/sinttuloxps.png/
AND
'DEPT' TABLE
http://imageshack.us/photo/my-images/19/assayp.png/
I wan´t to get the employee with the highest salary in each department.
I´m using SQLPLUS.
Thanks in advance!
ALSO CODE:
CREATE TABLE dept (
deptno numeric(2,0) NOT NULL,
dname character varying(14),
loc character varying(13),
CONSTRAINT dept_pkey PRIMARY KEY (deptno)
);
CREATE TABLE emp (
empno numeric(4,0) NOT NULL,
ename character varying(10),
job character varying(9),
mgr numeric(4,0),
hiredate date,
sal numeric(7,2),
comm numeric(7,2),
deptno numeric(2,0),
CONSTRAINT emp_pkey PRIMARY KEY (empno),
CONSTRAINT emp_deptno_fkey FOREIGN KEY (deptno) REFERENCES dept(deptno),
CONSTRAINT emp_mgr_fkey FOREIGN KEY (mgr) REFERENCES emp(empno)
);
INSERT INTO dept (deptno, dname, loc) VALUES (10, 'ACCOUNTING', 'NEW YORK');
INSERT INTO dept (deptno, dname, loc) VALUES (20, 'RESEARCH', 'DALLAS');
INSERT INTO dept (deptno, dname, loc) VALUES (30, 'SALES', 'CHICAGO');
INSERT INTO dept (deptno, dname, loc) VALUES (40, 'OPERATIONS', 'BOSTON');
insert into emp values (7839, 'KING' , 'PRESIDENT', NULL, to_date('17/11/81','dd/mm/yy') , 5000, NULL, 10);
insert into emp values (7566, 'JONES' , 'MANAGER' , 7839, to_date('02/04/81','dd/mm/yy') , 2975, NULL, 20);
insert into emp values (7902, 'FORD' , 'ANALYST' , 7566, to_date('03/12/81','dd/mm/yy') , 3000, NULL, 20);
insert into emp values (7369, 'SMITH' , 'CLERK' , 7902, to_date('17/12/80','dd/mm/yy') , 800, NULL, 20);
insert into emp values (7698, 'BLAKE' , 'MANAGER' , 7839, to_date('01/05/81','dd/mm/yy') , 2850, NULL, 30);
insert into emp values (7499, 'ALLEN' , 'SALESMAN' , 7698, to_date('20/02/81','dd/mm/yy') , 1600, 300, 30);
insert into emp values (7521, 'WARD' , 'SALESMAN' , 7698, to_date('22/02/81','dd/mm/yy') , 1250, 500, 30);
insert into emp values (7654, 'MARTIN' , 'SALESMAN' , 7698, to_date('28/09/81','dd/mm/yy') , 1250, 1400, 30);
insert into emp values (7782, 'CLARK' , 'MANAGER' , 7839, to_date('09/06/81','dd/mm/yy') , 2450, NULL, 10);
insert into emp values (7788, 'SCOTT' , 'ANALYST' , 7566, to_date('09/12/82','dd/mm/yy') , 3000, NULL, 20);
insert into emp values (7844, 'TURNER' , 'SALESMAN' , 7698, to_date('08/09/81','dd/mm/yy') , 1500, 0, 30);
insert into emp values (7876, 'ADAMS' , 'CLERK' , 7788, to_date('12/01/83','dd/mm/yy') , 1100, NULL, 20);
insert into emp values (7900, 'JAMES' , 'CLERK' , 7698, to_date('03/12/81','dd/mm/yy') , 950, NULL, 30);
insert into emp values (7934, 'MILLER' , 'CLERK' , 7782, to_date('23/01/82','dd/mm/yy') , 1300, NULL, 10);

You can also use the analytical RANK() function:
SELECT * FROM (
SELECT
Dept.DeptNo,
Dept.DName,
Emp.EName,
Emp.Sal,
RANK() OVER (PARTITION BY Dept.DeptNo ORDER BY Emp.Sal DESC) AS DeptSalRank
FROM Emp
INNER JOIN Dept ON Emp.DeptNo = Dept.DeptNo
)
WHERE DeptSalRank = 1

Classic greatest-n-per-group query. Here is what you want:
select dept.dname, emp.empno, emp.ename, emp.sal
from emp
inner join dept on emp.deptno = dept.deptno
inner join
(
select emp.deptno, max(emp.sal) sal
from emp
group by emp.deptno
) ss on emp.deptno = ss.deptno and emp.sal = ss.sal
order by emp.sal desc
Here is a working fiddle: http://sqlfiddle.com/#!4/7147b/6
Additionally, you might want to checkout a different approach. Look here (SQL Select only rows with Max Value on a Column) to see an interesting answer on the topic.

The following query will omit duplicate values
SELECT DEPTNO, MAX(SAL) FROM EMP GROUP BY DEPTNO;
The following query will include the duplicate values
SELECT * FROM EMP WHERE (DEPTNO,SAL) IN
( SELECT DEPTNO, MAX(SAL) FROM EMP GROUP BY DEPTNO)

As short as the question: SELECT DeptID, MAX(Salary) FROM Employees GROUP BY DeptID

Tested. Here is the query:
Select outemp.Employee_ID, outemp.First_Name, outemp.Last_Name
From Hr.Employees outemp,
HR.Departments outdept,
(Select Max(e.salary) maxsal, D.Department_ID Dept_ID From HR.EMPLOYEES e, HR.Departments d
WHERE e.Department_ID = d.Department_ID
Group By d.Department_ID) DummyTable
where outemp.Department_ID = outdept.Department_ID
AND outdept.Department_ID = DummyTable.Dept_ID
AND outemp.Salary = DummyTable.Maxsal

list of top 10 highest paid employee detail
(SELECT *, RANK() OVER (ORDER BY Emp.Sal DESC)AS DeptSalRank
FROM Emp INNER JOIN Dept ON Emp.DeptNo = Dept.DeptNo) LIMIT 10;

Related

How to know departments without male employes

We have two tables
Department
Emp
Department
CREATE TABLE department
(
deptno int NOT NULL,
dname varchar2(50) NOT NULL,
loc varchar2(13)
);
INSERT INTO DEPT (DEPTNO, DNAME, LOC)
VALUES (10, 'ACCOUNTING', 'NEW YORK');
INSERT INTO DEPT (DEPTNO, DNAME, LOC)
VALUES (20, 'RESEARCH', 'DALLAS');
INSERT INTO DEPT (DEPTNO, DNAME, LOC)
VALUES (30, 'SALES', 'CHICAGO');
INSERT INTO DEPT (DEPTNO, DNAME, LOC)
VALUES (40, 'OPERATIONS', 'BOSTON');
CREATE TABLE emp
(
empno number(4,0),
ename varchar2(10),
sex varchar2(10),
deptno number(2,0)
)
INSERT INTO emp
VALUES (7839, 'KING', 'PRESIDENT', Male, 10);
INSERT INTO emp
VALUES (7898, 'BLAKE', 'MANAGER', Male, 30);
INSERT INTO emp
VALUES (7782, 'CLARK', 'MANAGER', Female, 10);
INSERT INTO emp
VALUES (7566, 'JONES', 'ANALYST', Female, 20);
INSERT INTO emp
VALUES (7788, 'SCOTT', 'ANALYST', Male, 20);
INSERT INTO emp
VALUES (7902, 'FORD', 'ANALYST', Male, 20);
INSERT INTO emp
VALUES (7369, 'SMITH', 'CLERK', Female, 20);
INSERT INTO emp
VALUES (7369, 'Allen', 'Manager', Male, 40);
COMMIT;
Need a list of departments without a female employee....
Thanks
Raju
I got a list of departments with female employees and removed them from the entire list.
select deptno
from emp
where deptno not in (select deptno
from emp
where sex = 'Female');
I wanted to know if there is a better way to do it
You can use NOT EXISTS:
select *
from dept
where not exists (
select 1 from emp where emp.deptno = dept.deptno and emp.sex = 'Female'
)
Or the easier to read NOT IN, though probably less performant:
select *
from dept
where deptno not in (select deptno from emp where sex = 'Female')
Something like
SELECT
deptno,
sum(CASE sex WHEN 'Female' THEN 1 ELSE 0 END) AS number_female
FROM emp
GROUP BY deptno;
might work. You would need to select those department numbers with number_females = 0 But apart from that I can not come up with a solution that is shorter than yours. The table department seems to be irrelevant in this case, unless you need department names.

Find sum of salary from department where sum of salary is smaller than 20000

I'm trying to write a query that returns the total salary of every department.
So it needs to look who works in a department and count the salary up and do this for every department. Then it should only show me the departments that have a total salary lower than 20000.
My database looks like this
create table dept
(
deptno number(2,0),
dname varchar2(14),
loc varchar2(13),
constraint pk_dept primary key (deptno)
);
create table emp
(
empno number(4,0),
ename varchar2(10),
job varchar2(9),
mgr number(4,0),
hiredate date,
sal number(7,2),
comm number(7,2),
deptno number(2,0),
constraint pk_emp primary key (empno),
constraint fk_deptno foreign key (deptno) references dept (deptno)
);
insert into dept
values(10, 'ACCOUNTING', 'NEW YORK');
insert into dept
values(20, 'RESEARCH', 'DALLAS');
insert into dept
values(30, 'SALES', 'CHICAGO');
insert into dept
values(40, 'OPERATIONS', 'BOSTON');
insert into emp
values(7839, 'KING', 'PRESIDENT', null, to_date('17-11-1981','dd-mm-yyyy'), 5000, null, 10);
insert into emp
values(7698, 'BLAKE', 'MANAGER', 7839, to_date('1-5-1981','dd-mm-yyyy'), 2850, null, 30);
insert into emp
values(7782, 'CLARK', 'MANAGER', 7839, to_date('9-6-1981','dd-mm-yyyy'), 2450, null, 10);
insert into emp
values(7566, 'JONES', 'MANAGER', 7839, to_date('2-4-1981','dd-mm-yyyy'), 2975, null, 20);
insert into emp
values(7788, 'SCOTT', 'ANALYST', 7566, to_date('13-JUL-87','dd-mm-rr') - 85, 3000, null, 20);
insert into emp
values(7902, 'FORD', 'ANALYST', 7566, to_date('3-12-1981','dd-mm-yyyy'), 3000, null, 20);
insert into emp
values(7369, 'SMITH', 'CLERK', 7902, to_date('17-12-1980','dd-mm-yyyy'), 800, null, 20);
insert into emp
values(7499, 'ALLEN', 'SALESMAN', 7698, to_date('20-2-1981','dd-mm-yyyy'), 1600, 300, 30);
insert into emp
values(7521, 'WARD', 'SALESMAN', 7698, to_date('22-2-1981','dd-mm-yyyy'), 1250, 500, 30);
insert into emp
values(7654, 'MARTIN', 'SALESMAN', 7698, to_date('28-9-1981','dd-mm-yyyy'), 1250, 1400, 30);
insert into emp
values(7844, 'TURNER', 'SALESMAN', 7698, to_date('8-9-1981','dd-mm-yyyy'), 1500, 0, 30);
insert into emp
values(7876, 'ADAMS', 'CLERK', 7788, to_date('13-JUL-87', 'dd-mm-rr') - 51, 1100, null, 20);
insert into emp
values(7900, 'JAMES', 'CLERK', 7698, to_date('3-12-1981','dd-mm-yyyy'), 950, null, 30);
insert into emp
values(7934, 'MILLER', 'CLERK', 7782, to_date('23-1-1982','dd-mm-yyyy'), 1300, null, 10);
I tried using this query but it keeps telling me that name is an invalid identifier.
SELECT
(SELECT d.dname
FROM dept d
WHERE d.deptno = e.deptno) AS naam,
SUM(e.sal) AS sal
FROM
emp e
WHERE
sal < 20000
GROUP BY
naam;
Does anyone know what I'm doing wrong?
Use inner join and having
SELECT d.dname, sum(e.sal) sal
FROM dept d
INNER JOIN emp e on d.deptno = e.deptno
GROUP BY d.dname
HAVING sum(e.sal) < 20000

SQL developer Query

QUESTION: Write a SQL SELECT statement to display the name and address of all departments (except the departments in Dallas) having maximum number of employees. Sort your output in ascending order by department name.
Creating Department Table
CREATE TABLE department
( DEPARTMENT_ID NUMBER(4) PRIMARY KEY,
DEPARTMENT_NAME VARCHAR2(20) NOT NULL UNIQUE,
ADDRESS VARCHAR2(20) NOT NULL);
Populating Department Table
INSERT INTO department VALUES(10, 'ACCOUNTING', 'NEW YORK');
INSERT INTO department VALUES(20, 'RESEARCH', 'DALLAS');
INSERT INTO department VALUES(30, 'SALES', 'CHICAGO');
INSERT INTO department VALUES(40, 'IT', 'DALLAS');
INSERT INTO department VALUES(50, 'EXECUTIVE', 'NEW YORK');
INSERT INTO department VALUES(60, 'MARKETING', 'CHICAGO');
COMMIT;
Creating Employee Table
CREATE TABLE employee
( EMPLOYEE_ID NUMBER(4) PRIMARY KEY,
EMPLOYEE_NAME VARCHAR2(20) NOT NULL,
JOB VARCHAR2(50) NOT NULL,
MANAGER_ID NUMBER(4),
HIRE_DATE DATE NOT NULL,
SALARY NUMBER(9, 2) NOT NULL,
COMMISSION NUMBER(9, 2),
DEPARTMENT_ID NUMBER(4) REFERENCES department(DEPARTMENT_ID));
Populating Employee Table
INSERT INTO employee
VALUES(7839, 'KING', 'PRESIDENT', NULL, '20-NOV-01', 5000, NULL, 50);
INSERT INTO employee
VALUES(7596, 'JOST', 'VICE PRESIDENT', 7839, '04-MAY-01', 4500, NULL, 50);
INSERT INTO employee
VALUES(7603, 'CLARK', 'VICE PRESIDENT', 7839, '12-JUN-01', 4000, NULL, 50);
INSERT INTO employee
VALUES(7566, 'JONES', 'PUBLIC ACCOUNTANT', 7596, '05-APR-01', 3000, NULL, 10);
INSERT INTO employee
VALUES(7886, 'STEEL', 'PUBLIC ACCOUNTANT', 7566, '08-MAR-03', 2500, NULL, 10);
INSERT INTO employee
VALUES(7610, 'WILSON', 'ANALYST', 7596, '03-DEC-01', 3000, NULL, 20);
INSERT INTO employee
VALUES(7999, 'WOLFE', 'ANALYST', 7610, '15-FEB-02', 2500, NULL, 20);
INSERT INTO employee
VALUES(7944, 'LEE', 'ANALYST', 7610, '04-SEP-06', 2400, NULL, 20);
INSERT INTO employee
VALUES(7900, 'FISHER', 'SALESMAN', 7603, '06-DEC-01', 3000, 500, 30);
INSERT INTO employee
VALUES(7921, 'JACKSON', 'SALESMAN', 7900, '25-FEB-05', 2500, 400, 30);
INSERT INTO employee
VALUES(7952, 'LANCASTER', 'SALESMAN', 7900, '06-DEC-06', 2000, 150, 30);
INSERT INTO employee
VALUES(7910, 'SMITH', 'DATABASE ADMINISTRATOR', 7596, '20-DEC-01', 2900, NULL, 40);
INSERT INTO employee
VALUES(7788, 'SCOTT', 'PROGRAMMER', 7910, '15-JAN-03', 2500, NULL, 40);
INSERT INTO employee
VALUES(7876, 'ADAMS', 'PROGRAMMER', 7910, '15-JAN-03', 2000, NULL, 40);
INSERT INTO employee
VALUES(7934, 'MILLER','PROGRAMMER', 7876, '25-JAN-02', 1000, NULL, 40);
INSERT INTO employee
VALUES(8000, 'BREWSTER', 'TBA', NULL, '22-AUG-13', 2500, NULL, NULL);
COMMIT;
The Query That i wrote is below and it works perfectly in finding the maximum number of employees in DALLAS department but I want to eliminate DALLAS and find the other department which has the MAXIMUM number of employee's working in it which is by the data are (CHICAGO and NEW YORK). Can anyone please help me out?
SELECT d.department_id, d.department_name, COUNT(*)
FROM department d
INNER JOIN employee e
ON d.department_id = e.department_id
GROUP BY d.department_id, d.department_name
HAVING COUNT(*) = (SELECT MAX(COUNT(*))
FROM employee
GROUP BY department_id)
ORDER BY department_id;
Using your query:
SELECT d.department_id, d.department_name, COUNT(*)
FROM department d
INNER JOIN employee e
ON d.deptartment_id = e.department_id
where d.address != 'DALLAS'
GROUP BY d.department_id, d.department_name
HAVING COUNT(*) = (SELECT MAX(COUNT(*))
FROM employee
where department_id not in (select department_id from department where address = 'DALLAS')
GROUP BY department_id)
ORDER BY department_id;
;
You can use a rank analytic function:
select *
from (
select department_id, department_name, rank() over (order by cnt desc) rnk
from(
SELECT d.department_id, d.department_name, COUNT(*) cnt
FROM department d
INNER JOIN employee e
ON d.department_id = e.department_id
GROUP BY d.department_id, d.department_name
)
)
where rnk = 2 --here you may change to what position you want
;

Find the number of employees in each department - SQL Oracle

I have two tables Emp and Dept and I am trying to display how many people work in each department along with their department name, but I can't get it to work. I have tried this select count(ename) as count from emp group by deptno; but the output I am getting is this :
COUNT
----------
6
5
3
But I also want to show the names for each of those departments. Here are my tables :
Empt:
CREATE TABLE EMP
(EMPNO NUMBER(4) NOT NULL,
ENAME VARCHAR2(10),
JOB VARCHAR2(9),
MGR NUMBER(4),
HIREDATE DATE,
SAL NUMBER(7, 2),
COMM NUMBER(7, 2),
DEPTNO NUMBER(2));
INSERT INTO EMP VALUES
(7369, 'SMITH', 'CLERK', 7902,
TO_DATE('17-DEC-1980', 'DD-MON-YYYY'), 800, NULL, 20);
INSERT INTO EMP VALUES
(7499, 'ALLEN', 'SALESMAN', 7698,
TO_DATE('20-FEB-1981', 'DD-MON-YYYY'), 1600, 300, 30);
INSERT INTO EMP VALUES
(7521, 'WARD', 'SALESMAN', 7698,
TO_DATE('22-FEB-1981', 'DD-MON-YYYY'), 1250, 500, 30);
INSERT INTO EMP VALUES
(7566, 'JONES', 'MANAGER', 7839,
TO_DATE('2-APR-1981', 'DD-MON-YYYY'), 2975, NULL, 20);
INSERT INTO EMP VALUES
(7654, 'MARTIN', 'SALESMAN', 7698,
TO_DATE('28-SEP-1981', 'DD-MON-YYYY'), 1250, 1400, 30);
INSERT INTO EMP VALUES
(7698, 'BLAKE', 'MANAGER', 7839,
TO_DATE('1-MAY-1981', 'DD-MON-YYYY'), 2850, NULL, 30);
INSERT INTO EMP VALUES
(7782, 'CLARK', 'MANAGER', 7839,
TO_DATE('9-JUN-1981', 'DD-MON-YYYY'), 2450, NULL, 10);
INSERT INTO EMP VALUES
(7788, 'SCOTT', 'ANALYST', 7566,
TO_DATE('09-DEC-1982', 'DD-MON-YYYY'), 3000, NULL, 20);
INSERT INTO EMP VALUES
(7839, 'KING', 'PRESIDENT', NULL,
TO_DATE('17-NOV-1981', 'DD-MON-YYYY'), 5000, NULL, 10);
INSERT INTO EMP VALUES
(7844, 'TURNER', 'SALESMAN', 7698,
TO_DATE('8-SEP-1981', 'DD-MON-YYYY'), 1500, 0, 30);
INSERT INTO EMP VALUES
(7876, 'ADAMS', 'CLERK', 7788,
TO_DATE('12-JAN-1983', 'DD-MON-YYYY'), 1100, NULL, 20);
INSERT INTO EMP VALUES
(7900, 'JAMES', 'CLERK', 7698,
TO_DATE('3-DEC-1981', 'DD-MON-YYYY'), 950, NULL, 30);
INSERT INTO EMP VALUES
(7902, 'FORD', 'ANALYST', 7566,
TO_DATE('3-DEC-1981', 'DD-MON-YYYY'), 3000, NULL, 20);
INSERT INTO EMP VALUES
(7934, 'MILLER', 'CLERK', 7782,
TO_DATE('23-JAN-1982', 'DD-MON-YYYY'), 1300, NULL, 10);
Dept:
CREATE TABLE DEPT
(DEPTNO NUMBER(2),
DNAME VARCHAR2(14),
LOC VARCHAR2(13) );
INSERT INTO DEPT VALUES (10, 'ACCOUNTING', 'NEW YORK');
INSERT INTO DEPT VALUES (20, 'RESEARCH', 'DALLAS');
INSERT INTO DEPT VALUES (30, 'SALES', 'CHICAGO');
INSERT INTO DEPT VALUES (40, 'OPERATIONS', 'BOSTON');
Please try:
select count(*) as count,dept.DNAME
from emp
inner join dept on emp.DEPTNO = dept.DEPTNO
group by dept.DNAME
A request to list "Number of employees in each department" or "Display how many people work in each department" is the same as "For each department, list the number of employees", this must include departments with no employees. In the sample database, Operations has 0 employees. So a LEFT OUTER JOIN should be used.
SELECT dept.name, COUNT(emp.empno) AS count
FROM dept
LEFT OUTER JOIN emp ON emp.deptno = dept.deptno
GROUP BY dept.name;
select count(e.empno), d.deptno, d.dname
from emp e, dep d
where e.DEPTNO = d.DEPTNO
group by d.deptno, d.dname;
Try the query below:
select count(*),d.dname from emp e , dept d where d.deptno = e.deptno
group by d.dname
SELECT d.DEPTNO
, d.dname
, COUNT(e.ename) AS count
FROM emp e
INNER JOIN dept d ON e.DEPTNO = d.deptno
GROUP BY d.deptno
, d.dname;
select d.dname
,count(e.empno) as count
from dept d
left outer join emp e
on e.deptno=d.deptno
group by d.dname;
Try to do this:
SQL> select dept,count(*) "no of emp" from employee group by dept;
DEPT no of emp
-------------------- ----------
HR 2
Account 2
Admin 3
select count(EMPNO),DNAME from EMP e join DEPT d on e.DEPTNO = d.DEPTNO group by DNAME ;

Oracle SQL sample database

I'm trying to learn Oracle SQL by database Supplied by it.
I found somewhere tasks to be done.
Database structure is supplied by Oracle:
CREATE TABLE EMP
(EMPNO NUMERIC(4) NOT NULL,
ENAME VARCHAR(10),
JOB VARCHAR(9),
MGR NUMERIC(4),
HIREDATE DATETIME,
SAL NUMERIC(7, 2),
COMM NUMERIC(7, 2),
DEPTNO NUMERIC(2))
INSERT INTO EMP VALUES
(7369, 'SMITH', 'CLERK', 7902, '17-DEC-1980', 800, NULL, 20)
INSERT INTO EMP VALUES
(7499, 'ALLEN', 'SALESMAN', 7698, '20-FEB-1981', 1600, 300, 30)
INSERT INTO EMP VALUES
(7521, 'WARD', 'SALESMAN', 7698, '22-FEB-1981', 1250, 500, 30)
INSERT INTO EMP VALUES
(7566, 'JONES', 'MANAGER', 7839, '2-APR-1981', 2975, NULL, 20)
INSERT INTO EMP VALUES
(7654, 'MARTIN', 'SALESMAN', 7698, '28-SEP-1981', 1250, 1400, 30)
INSERT INTO EMP VALUES
(7698, 'BLAKE', 'MANAGER', 7839, '1-MAY-1981', 2850, NULL, 30)
INSERT INTO EMP VALUES
(7782, 'CLARK', 'MANAGER', 7839, '9-JUN-1981', 2450, NULL, 10)
INSERT INTO EMP VALUES
(7788, 'SCOTT', 'ANALYST', 7566, '09-DEC-1982', 3000, NULL, 20)
INSERT INTO EMP VALUES
(7839, 'KING', 'PRESIDENT', NULL, '17-NOV-1981', 5000, NULL, 10)
INSERT INTO EMP VALUES
(7844, 'TURNER', 'SALESMAN', 7698, '8-SEP-1981', 1500, 0, 30)
INSERT INTO EMP VALUES
(7876, 'ADAMS', 'CLERK', 7788, '12-JAN-1983', 1100, NULL, 20)
INSERT INTO EMP VALUES
(7900, 'JAMES', 'CLERK', 7698, '3-DEC-1981', 950, NULL, 30)
INSERT INTO EMP VALUES
(7902, 'FORD', 'ANALYST', 7566, '3-DEC-1981', 3000, NULL, 20)
INSERT INTO EMP VALUES
(7934, 'MILLER', 'CLERK', 7782, '23-JAN-1982', 1300, NULL, 10)
CREATE TABLE DEPT
(DEPTNO NUMERIC(2),
DNAME VARCHAR(14),
LOC VARCHAR(13) )
INSERT INTO DEPT VALUES (10, 'ACCOUNTING', 'NEW YORK')
INSERT INTO DEPT VALUES (20, 'RESEARCH', 'DALLAS')
INSERT INTO DEPT VALUES (30, 'SALES', 'CHICAGO')
INSERT INTO DEPT VALUES (40, 'OPERATIONS', 'BOSTON')
CREATE TABLE BONUS
(ENAME VARCHAR(10),
JOB VARCHAR(9),
SAL NUMERIC,
COMM NUMERIC)
CREATE TABLE SALGRADE
(GRADE NUMERIC,
LOSAL NUMERIC,
HISAL NUMERIC)
INSERT INTO SALGRADE VALUES (1, 700, 1200)
INSERT INTO SALGRADE VALUES (2, 1201, 1400)
INSERT INTO SALGRADE VALUES (3, 1401, 2000)
INSERT INTO SALGRADE VALUES (4, 2001, 3000)
INSERT INTO SALGRADE VALUES (5, 3001, 9999)
Now I would like to Select employees that earn most in their department and salgrade.
I wrote something like this one:
select ename, salgrade.grade, dept.dname from emp, salgrade, dept
WHERE emp.sal BETWEEN salgrade.losal AND salgrade.hisal
AND emp.deptno = dept.deptno group by salgrade.grade, dept.dname, emp.ename
But it's not working properly.
The output is:
ENAME GRADE DNAME
SMITH 1 RESEARCH
BLAKE 4 SALES
FORD 4 RESEARCH
KING 5 ACCOUNTING
SCOTT 4 RESEARCH
MILLER 2 ACCOUNTING
TURNER 3 SALES
WARD 2 SALES
MARTIN 2 SALES
ADAMS 1 RESEARCH
JONES 4 RESEARCH
JAMES 1 SALES
CLARK 4 ACCOUNTING
ALLEN 3 SALES
Note rows:
WARD 2 SALES
MARTIN 2 SALES
2 people from same department and salgrade.
Could you point me my mistakes?
You are not filtering your query this is why you have all the employees displayed.
This would filter the employees that earn less than the max for their dept/grade:
SELECT ename, salgrade.grade, dept.dname
FROM emp, salgrade, dept
WHERE emp.sal BETWEEN salgrade.losal AND salgrade.hisal
AND emp.deptno = dept.deptno
AND emp.sal = (SELECT MAX(sal)
FROM emp emp_in, salgrade grade_in
WHERE emp_in.sal BETWEEN grade_in.losal AND grande_in.hisal
AND emp_in.deptno = emp.deptno
AND grade_in.losal = salgrade.losal)
You will still find duplicates because for instance, two people in sales earn the max salary for grade 2 (both Martin and Ward earn 1250). Either this is acceptable or you need some other criteria to only select one of them.
You can use the row_number analytic function to ensure that only one row is returned by grade/dept (note that Oracle will select arbitrarily one row when there are duplicates) :
SELECT * FROM (
SELECT ename, salgrade.grade, dept.dname,
row_number() OVER (PARTITION BY dept.deptno, salgrade.grade
ORDER BY emp.sal DESC) rnk
FROM emp, salgrade, dept
WHERE emp.sal BETWEEN salgrade.losal AND salgrade.hisal
AND emp.deptno = dept.deptno
) WHERE rnk = 1;
ENAME GRADE DNAME RNK
---------- ------ -------------- ---
MILLER 2 ACCOUNTING 1
CLARK 4 ACCOUNTING 1
KING 5 ACCOUNTING 1
ADAMS 1 RESEARCH 1
FORD 4 RESEARCH 1
JAMES 1 SALES 1
MARTIN 2 SALES 1
ALLEN 3 SALES 1
BLAKE 4 SALES 1
With your `select:
select ename, salgrade.grade, dept.dname from emp, salgrade, dept
WHERE emp.sal BETWEEN salgrade.losal AND salgrade.hisal
AND emp.deptno = dept.deptno group by salgrade.grade, dept.dname, emp.ename
when you group by salgrade.grade, dept.dname, emp.ename the results will be grouped into those three values. You also put the results BETWEEN salgrade.losal AND salgrade.hisal so it will give all employees that have the salary in that interval. It's not restricting anything to the greater one got it? And that's why you have WARD 2 SALES and MARTIN 2 SALES.
You are grouping by employee name, as well as department and salary grade. That means you will return a row for every combination of employee name, department and salary grade in your dataset.
To ensure that you only return one row per department and salary grade, you will need to remove the employee name from the group by clause. This will enable you to find the maximum salary per grade and department, but not which employees have that salary - to do that, you need to join the results back to the employee table again, like so:
select e.ename, s.grade, d.dname, e.salary
from (select max(emp.salary) max_salary,
salgrade.grade,
emp.deptno
from emp, salgrade
WHERE emp.sal BETWEEN salgrade.losal AND salgrade.hisal
group by salgrade.grade, dept.dname) s
join emp e on e.salary = s.max_salary
join dept d on e.deptno = d.deptno
Note that if multiple employees in the same department are earning the same maximum salary within their grade, then both employees will be returned - this should happen with FORD and SCOTT in RESEARCH.
SELECT SUB2.ENAME , SUB2.DNAME , S.GRADE ,SUB2.SAL
FROM SALGRADE S,
(SELECT E.ENAME,E.SAL,D.DNAME
FROM EMP E, DEPT D,
(SELECT DEPTNO, MAX(SAL) AS "MAX"
FROM EMP
GROUP BY DEPTNO) SUB1
WHERE E.SAL=SUB1.MAX
AND E.DEPTNO=D.DEPTNO) SUB2
WHERE SUB2.SAL BETWEEN S.LOSAL AND S.HISAL
Screen Shot ////// Try this out
SELECT E.EMPNO, E.ENAME, E.JOB, D.DNAME, E.SAL, E.DEPTNO, S.GRADE
FROM EMP E, SALGRADE S, DEPT D
WHERE E.SAL IN (SELECT MAX(SAL) FROM EMP GROUP BY DEPTNO)
AND E.SAL BETWEEN S.LOSAL AND S.HISAL
AND E.DEPTNO = D.DEPTNO
ORDER BY E.SAL DESC
When I created this I used this format to make it easier to read and modify it is for an Oracle format
CREATE TABLE EMP
(EMP_NO NUMBER(4) NOT NULL PRIMARY KEY,
E_NAME VARCHAR2(10),
JOB VARCHAR2(9),
MGR NUMBER(4),
HIRE_DATE DATE,
SAL DECIMAL(7, 2),
COMM DECIMAL(7, 2),
DEPT_NO NUMBER(2));
SELECT *
FROM EMP
INSERT INTO EMP
(EMP_NO, E_NAME, JOB, MGR, HIRE_DATE, SAL, COMM, DEPT_NO)
VALUES
(7369, 'SMITH', 'CLERK', 7902, '17-DEC-1980', 800, NULL, 20);
INSERT INTO EMP
(EMP_NO, E_NAME, JOB, MGR, HIRE_DATE, SAL, COMM, DEPT_NO)
VALUES
(7499, 'ALLEN', 'SALESMAN', 7698, '20-FEB-1981', 1600, 300, 30);
INSERT INTO EMP
(EMP_NO, E_NAME, JOB, MGR, HIRE_DATE, SAL, COMM, DEPT_NO)
VALUES
(7521, 'WARD', 'SALESMAN', 7698, '22-FEB-1981', 1250, 500, 30);
INSERT INTO EMP
(EMP_NO, E_NAME, JOB, MGR, HIRE_DATE, SAL, COMM, DEPT_NO)
VALUES
(7566, 'JONES', 'MANAGER', 7839, '02-APR-1981', 2975, NULL, 20);
INSERT INTO EMP
(EMP_NO, E_NAME, JOB, MGR, HIRE_DATE, SAL, COMM, DEPT_NO)
VALUES
(7654, 'MARTIN', 'SALESMAN', 7698, '28-SEP-1981', 1250, 1400, 30);
INSERT INTO EMP
(EMP_NO, E_NAME, JOB, MGR, HIRE_DATE, SAL, COMM, DEPT_NO)
VALUES
(7698, 'BLAKE', 'MANAGER', 7839, '01-MAY-1981', 2850, NULL, 30);
INSERT INTO EMP
(EMP_NO, E_NAME, JOB, MGR, HIRE_DATE, SAL, COMM, DEPT_NO)
VALUES
(7782, 'CLARK', 'MANAGER', 7839, '09-JUN-1981', 2450, NULL, 10);
INSERT INTO EMP
(EMP_NO, E_NAME, JOB, MGR, HIRE_DATE, SAL, COMM, DEPT_NO)
VALUES
(7788, 'SCOTT', 'ANALYST', 7566, '09-DEC-1982', 3000, NULL, 20);
INSERT INTO EMP
(EMP_NO, E_NAME, JOB, MGR, HIRE_DATE, SAL, COMM, DEPT_NO)
VALUES
(7839, 'KING', 'PRESIDENT', NULL, '17-NOV-1981', 5000, NULL, 10);
INSERT INTO EMP
(EMP_NO, E_NAME, JOB, MGR, HIRE_DATE, SAL, COMM, DEPT_NO)
VALUES
(7844, 'TURNER', 'SALESMAN', 7698, '08-SEP-1981', 1500, 0, 30);
INSERT INTO EMP
(EMP_NO, E_NAME, JOB, MGR, HIRE_DATE, SAL, COMM, DEPT_NO)
VALUES
(7876, 'ADAMS', 'CLERK', 7788, '12-JAN-1983', 1100, NULL, 20);
INSERT INTO EMP
(EMP_NO, E_NAME, JOB, MGR, HIRE_DATE, SAL, COMM, DEPT_NO)
VALUES
(7900, 'JAMES', 'CLERK', 7698, '03-DEC-1981', 950, NULL, 30);
INSERT INTO EMP
(EMP_NO, E_NAME, JOB, MGR, HIRE_DATE, SAL, COMM, DEPT_NO)
VALUES
(7902, 'FORD', 'ANALYST', 7566, '03-DEC-1981', 3000, NULL, 20);
INSERT INTO EMP
(EMP_NO, E_NAME, JOB, MGR, HIRE_DATE, SAL, COMM, DEPT_NO)
VALUES
(7934, 'MILLER', 'CLERK', 7782, '23-JAN-1982', 1300, NULL, 10);
CREATE TABLE DEPT
(DEPT_NO NUMERIC(2),
D_NAME VARCHAR(14),
LOC VARCHAR(13) );
INSERT INTO DEPT
(DEPT_NO, D_NAME, LOC)
VALUES
(10, 'ACCOUNTING', 'NEW YORK');
INSERT INTO DEPT
(DEPT_NO, D_NAME, LOC)
VALUES
(20, 'RESEARCH', 'DALLAS');
INSERT INTO DEPT
(DEPT_NO, D_NAME, LOC)
VALUES
(30, 'SALES', 'CHICAGO');
INSERT INTO DEPT
(DEPT_NO, D_NAME, LOC)
VALUES
(40, 'OPERATIONS', 'BOSTON');
CREATE TABLE BONUS
(E_NAME VARCHAR(10),
JOB VARCHAR(9),
SAL NUMERIC,
COMM NUMERIC);
CREATE TABLE SAL_GRADE
(GRADE NUMERIC,
LO_SAL NUMERIC,
HI_SAL NUMERIC);
INSERT INTO SAL_GRADE
(GRADE, LO_SAL, HI_SAL)
VALUES
(1, 700, 1200);
INSERT INTO SAL_GRADE
(GRADE, LO_SAL, HI_SAL)
VALUES
(2, 1201, 1400);
INSERT INTO SAL_GRADE
(GRADE, LO_SAL, HI_SAL)
VALUES
(3, 1401, 2000);
INSERT INTO SAL_GRADE
(GRADE, LO_SAL, HI_SAL)
VALUES
(4, 2001, 3000);
INSERT INTO SAL_GRADE
(GRADE, LO_SAL, HI_SAL)
VALUES
(5, 3001, 9999);