查询每个部门工资前两名的通用sql解析

emp表结构:

引用

名称                                             是否为空?  类型
----------------------------------------- -------- ----------------------------

EMPNO                                    NOT NULL NUMBER(4)
ENAME                                              VARCHAR2(10)
JOB                                                VARCHAR2(9)
MGR                                                NUMBER(4)
HIREDATE                                          DATE
SAL                                                NUMBER(7,2)
COMM                                              NUMBER(7,2)
DEPTNO                                            NUMBER(2)

引用

DEPTNO      ENAME           SAL
---------- ---------- ----------
        20 SMITH              860
        30 ALLEN             1750
        30 WARD             1400
        20 JONES             3035
        30 MARTIN           1400
        30 BLAKE            3000
        10 CLARK            2480
        20 SCOTT             3060
        10 KING              5030
        30 TURNER           1650
        20 ADAMS            1160
        30 JAMES             1100
        20 FORD              3060
        10 MILLER            1330

Oracle查询:(利用分区功能)
select * from 
(select deptno,ename,sal,row_number() over (partition by deptno
    order by sal desc) rn 
from emp) 
   where rn<3;

MS SQL:(top)
SELECT TOP 2(SELECT COUNT(*) FROM EMP 
      WHERE SAL>=A.SAL) AS mc,A.sal FROM EMP AS A
      GROUP BY DEPTNO ORDER BY deptno SAL desc;

通用sql:
select deptno, ename, sal 
from emp e1
where 
   (select count(1)
   from emp e2
   where e2.deptno=e1.deptno and e2.ename!=e1.ename and e2.sal>e1.sal)
   <2
order by deptno, sal desc;

现在开始分析这个通用的:
1、
select deptno, ename, sal from emp e1 
   order by deptno, sal desc; 

先不考虑查询条件,表 e1 按照deptno 正序、sal倒序排列
引用

                    E1
    DEPTNO     ENAME            SAL
        10     KING             5030
        10     CLARK            2480
        10     MILLER           1330
        20     SCOTT            3060
        20     FORD             3060
        20     JONES            3035
        20     ADAMS            1160
        20     SMITH             860
        30     BLAKE            3000
        30     ALLEN            1750
        30     TURNER           1650        
        30     MARTIN           1400
        30     WARD             1400
        30     JAMES            1100

2、要查询 e1表中的数据,且要参考e2中数据。e1是主表,e2是附表。
    下面来看
where e2.deptno=e1.deptno and e2.ename!=e1.ename and e2.sal>e1.sal 

这个条件,其中e2.ename!=e1.ename在这个表中基本可以忽略,因为emp表中没有
deptno、ename、sal都相同的记录,这里它只是起到个确保准确性的作用,不是这个问
题的关键条件。 
e2.deptno=e1.deptno and e2.sal>e1.sal 

抽取emp中deptno=10的记录,根据这个条件,你会发现:
引用

        E2                                         E1
DEPTNO=10 ENAME      SAL      DEPTNO=10    ENAME            SAL
                                      10     KING              5030
      10   KING      5030             10     CLARK             2480
      10   KING      5030             10     MILLER            1330
      10   CLARK     2480             10     MILLER            1330
      10   MILLER    1330
   
where (select count(1) from emp e2 where   
e2.deptno=e1.deptno and e2.ename!=e1.ename and e2.sal>e1.sal) 
   <2 

count(1)求的是满足条件的记录数。
当 count(1)=0 时,
引用

         E2                                     E1
DEPTNO=10 ENAME        SAL      DEPTNO=10     ENAME       SAL
                                       10     KING        5030

表 e2 中没有记录,表 e1中是该部门工资最高的。

当 count(1)=1 时,
引用

              E1                             E2
DEPTNO=10 ENAME        SAL      DEPTNO=10 ENAME          SAL
                          10 KING           5030
       10 KING         5030            10 CLARK          2480

表 e2 中是该部门工资最高的,表 e1中是该部门工资次高的。

当 count(1)=2 时,
引用

         E2                                    E1
DEPTNO=10 ENAME       SAL      DEPTNO=10 ENAME        SAL
                         10    KING         5030
       10 KING        5030            10    CLARK        2480

       10 KING        5030            10    MILLER       1330

表 e2 中是该部门工资最高的,表 e1中是该部门工资第三高的。

至于为什么会分组求 count(1),是因为相关子查询实现了分组。

你可能感兴趣的:(oracle,sql)