Question

I am fairly new to SQL and have been struggling with a complex multiple join using aggregate functions.

Here is the result set I am seeking:

Write a query to display department names with salary grade (minimum), minimum salary and average commission. For departments with null commission, you should display 0. (salgrade table can be used for getting salary grade).

I have three tables:

  • emp - represents employees, their name, associated departments and salaries
  • dept - represents departments, their associated title and location
  • salgrade - represents multiple ranges of salaries

Here are table descriptions and data sets:

SQL> desc emp
 Name                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 EMPNO                     NOT NULL NUMBER(4)
 ENAME                          CHAR(10)
 JOB                            CHAR(9)
 MGR                            NUMBER(4)
 HIREDATE                       DATE
 SAL                            NUMBER(7,2)
 COMM                           NUMBER(7,2)
 DEPTNO                    NOT NULL NUMBER(2)

SQL> select empno, ename, sal, deptno from emp;

     EMPNO ENAME         SAL     DEPTNO
---------- ---------- ---------- ----------
      7839 KING         5000     10
      7698 BLAKE        2850     30
      7782 CLARK        2450     10
      7566 JONES        2975     20
      7654 MARTIN       1250     30
      7499 ALLEN        1600     30
      7844 TURNER       1500     30
      7900 JAMES         950     30
      7521 WARD         1250     30
      7902 FORD         3000     20
      7369 SMITH         800     20

     EMPNO ENAME         SAL     DEPTNO
---------- ---------- ---------- ----------
      7788 SCOTT        3000     20
      7876 ADAMS        1100     20
      7934 MILLER       1300     10
      1456 JOHN SMITH       3000     20

15 rows selected.

SQL> desc dept
 Name                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 DEPTNO                    NOT NULL NUMBER(2)
 DNAME                          CHAR(14)
 LOC                            CHAR(13)

SQL> select * from dept
  2  ;

    DEPTNO DNAME      LOC
---------- -------------- -------------
    50 TRAINING   SAN FRANCISCO
    10 ACCOUNTING     NEW YORK
    20 RESEARCH   DALLAS
    30 SALES      CHICAGO
    40 OPERATIONS     BOSTON

SQL> desc salgrade;
 Name                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 GRADE                          NUMBER
 LOSAL                          NUMBER
 HISAL                          NUMBER

SQL> select * from salgrade;

     GRADE  LOSAL      HISAL
---------- ---------- ----------
     1    700       1200
     2   1201       1400
     3   1401       2000
     4   2001       3000
     5   3001       9999

DDL for Salgrade Table:

CREATE TABLE SALGRADE ( 
GRADE NUMBER, 
LOSAL NUMBER, 
HISAL NUMBER); 

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

I have written the following query but I am struggling to calculate the minimum salgrade of each department. How would I achieve this?

Here is what I have so far (I have duplicate the MIN() function to supply dumby data to return a result without errors):

SELECT  d.dname         AS "DEPARTMENT",
    MIN(NVL(e.sal,0))   AS "SALARY GRADE",
    MIN(NVL(e.sal,0))   AS "MINIMUM_SALARY",
    AVG(NVL(e.comm,0))  AS "AVERAGE COMMISSION"
FROM    dept d
FULL JOIN   emp e
ON      d.deptno = e.deptno
GROUP BY
    d.dname, d.deptno
ORDER BY d.deptno ASC

DEPARTMENT     SALARY GRADE MINIMUM_SALARY AVERAGE COMMISSION
-------------- ------------ -------------- ------------------
ACCOUNTING         1300       1300          0
RESEARCH        800        800          0
SALES           950        950     366.666667
OPERATIONS        0      0          0
TRAINING          0      0          0

Please provide an brief explanation so that I can grow my knowledge of SQL and understand any response. Thanks in advance for your help! :)

Was it helpful?

Solution

You need to join to the SALGRADE table using BETWEEN:

SELECT dt.*,
    sg.GRADE AS "SALARY GRADE"
FROM
 (
   SELECT  d.dname         AS "DEPARTMENT",
       MIN(NVL(e.sal,0))   AS "MINIMUM_SALARY",
       AVG(NVL(e.comm,0))  AS "AVERAGE COMMISSION"
   FROM    dept d
   LEFT JOIN   emp e
   ON      d.deptno = e.deptno
   GROUP BY
       d.dname, d.deptno
 ) dt
JOIN SALGRADE sg 
ON "MINIMUM_SALARY" BETWEEN sg.LOWSAL AND sg.HIGHSAL
ORDER BY dt.deptno ASC

Remarks:

  • You don't need a FULL join, LEFT is enough
  • If there's a salary lower than the lowest LOWSAL range you might change the 2nd join to LEFT also
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top