mic-kul
mic-kul

Reputation: 1009

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?

Upvotes: 1

Views: 37667

Answers (6)

sachin shejekar
sachin shejekar

Reputation: 21

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

Upvotes: 0

Robert Curtis
Robert Curtis

Reputation: 1

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);

Upvotes: -1

07sunburst
07sunburst

Reputation: 1

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

Upvotes: 0

user359040
user359040

Reputation:

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.

Upvotes: 1

Vincent Malgrat
Vincent Malgrat

Reputation: 67772

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 

Upvotes: 1

aF.
aF.

Reputation: 66727

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.

Upvotes: 1

Related Questions