【问题标题】:Aggregate across multiple tables in SQL using Oracle使用 Oracle 在 SQL 中跨多个表进行聚合
【发布时间】:2014-06-28 00:40:33
【问题描述】:

我对 SQL 还很陌生,并且一直在使用聚合函数处理复杂的多重连接。

这是我正在寻找的结果集:

编写查询以显示部门名称和薪水等级(最低), 最低工资和平均佣金。对于具有 null 的部门 佣金,你应该显示0。(salgrade表可用于 获得工资等级)。

我有三张桌子:

  • emp - 代表员工、他们的姓名、相关部门和 工资
  • dept - 代表部门及其相关的头衔和位置
  • salgrade - 代表多个薪水范围

这里是表格描述和数据集:

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

Salgrade 表的 DDL:

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

我已经编写了以下查询,但我正在努力计算每个部门的最低 Salgrade。我将如何实现这一目标?

这是我目前所拥有的(我复制了 MIN() 函数来提供哑数据以返回没有错误的结果):

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

请提供一个简短的解释,以便我可以增加我的 SQL 知识并理解任何响应。在此先感谢您的帮助! :)

【问题讨论】:

  • 您也可以显示salgradetable 的DDL 吗?
  • 是的,没问题。我已经加了,你是这个意思吗?

标签: sql oracle join aggregate-functions


【解决方案1】:

您需要使用 BETWEEN 加入 SALGRADE 表:

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

备注:

  • 你不需要 FULL 连接,LEFT 就足够了
  • 如果工资低于最低 LOWSAL 范围,您也可以将 2nd join 更改为 LEFT

【讨论】:

  • 我刚刚使用 SQL*Plus 在 sqlplus 中尝试了查询:版本 11.2.0.1.0 生产并收到错误:FROM (SELECT d.dname AS "DEPARTMENT", * ERROR at line 3: ORA-00936: 缺少表达式
  • 感谢您的快速回复
  • 此查询应该按原样工作。似乎在您的查询中的错误位置有一个 * :-)
  • 我必须进行一些细微的更改才能获得我想要的确切结果,但您的回答很棒。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-09-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-22
  • 1970-01-01
相关资源
最近更新 更多