sql - 在 Oracle 中获取与最大和最小行相关的值

标签 sql oracle oracle11g analytic-functions

在 Oracle 11g 中,我们需要能够查询表以从特定组中具有最高值和最低值的行中提取信息。例如使用 EMP 表,我们想找到每个部门中薪水最高的人的姓名和薪水最低的人的姓名

DEPTNO   MAX_SAL    MAX_EARNER    MIN_SAL    MIN_EARNER
-------------------------------------------------------
10       5000       KING          1300       MILLER
20       3000       FORD          2975       JONES
etc

(如果有两个或更多员工的最高或最低工资,我们希望总是按字母顺序返回第一个)。

一个 Previous Post讨论了如何获得最大值而不是最大值和最小值的值。

我们目前基于上面的链接有一个不整洁的解决方案,然后应用后续查询,但性能对我们很重要。我预测一个好的解决方案还需要分析函数,并且可能需要一个将多行合并为单行的支点。

非常感谢任何帮助!
理查德

最佳答案

这很容易用解析函数解决。如您所见,在 DEPT 20 中,有两名员工的工资最高;这是一个重要的细节,因为此类问题的一些常见解决方案会忽略该信息。

SQL> select ename
  2             , deptno
  3             , sal
  4  from (
  5      select ename
  6             , deptno
  7             , sal
  8             , max (sal) over (partition by deptno) max_sal
  9             , min (sal) over (partition by deptno) min_sal
 10      from emp
 11      )
 12  where sal = max_sal
 13  or    sal = min_sal
 14  order by deptno, sal
 15  /

ENAME          DEPTNO        SAL
---------- ---------- ----------
KISHORE            10       1300
SCHNEIDER          10       5000
CLARKE             20        800
RIGBY              20       3000
GASPAROTTO         20       3000
HALL               30        950
LIRA               30       3750
TRICHLER           50       3500
FEUERSTEIN         50       4500

9 rows selected.

SQL>

糟糕,我错过了一个关于结果格式的重要细节。我的数据不符合要求的输出,因为有两名员工的工资最高。所以这个我承认有点尴尬的查询为我们提供了所需的布局。员工姓名上的 MIN() 返回字母顺序:
SQL> select
  2         deptno
  3         , max (case when sal = min_sal then min_sal else null end ) as min_sal
  4         , min (case when sal = min_sal then ename else null end ) as min_name
  5         , max (case when sal = max_sal then max_sal else null end ) as max_sal
  6         , min (case when sal = max_sal then ename else null end ) as max_name
  7  from (
  8      select ename
  9             , deptno
 10             , sal
 11             , max (sal) over (partition by deptno) max_sal
 12             , min (sal) over (partition by deptno) min_sal
 13      from emp
 14      )
 15  where sal = max_sal
 16  or    sal = min_sal
 17  group by deptno
 18  order by deptno
 19  /

    DEPTNO    MIN_SAL MIN_NAME      MAX_SAL MAX_NAME
---------- ---------- ---------- ---------- ----------
        10       1300 KISHORE          5000 SCHNEIDER
        20        800 CLARKE           3000 GASPAROTTO
        30        950 HALL             3750 LIRA
        50       3500 TRICHLER         4500 FEUERSTEIN

SQL>

我不喜欢这个解决方案。大多数数据集都会包含这样的冲突,我们需要承认它们。根据一些不相关的标准过滤结果以适应 Procrustea 报告布局是一种误导。我更喜欢反射(reflect)整个数据集的报告布局。最终,它取决于查询服务的业务目的。而且,当然,客户永远是对的 8-)

关于sql - 在 Oracle 中获取与最大和最小行相关的值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5880708/

相关文章:

database - Oracle 11g 首选项不存在 : CTXSYS. AUTO_FILTER

sql - PostgreSQL:约束行中没有重复的单元格

sql - 如何为动态生成 Select 语句的 30 列表创建索引

mysql - SQL,难以获取数据查询

mysql - SQL查询/查找基于排名的百分位数

c++ - 在 C++ 中保持 SYSDBA 连接打开

mysql - 左连接并显示非外键

sql - Oracle 12.2 中使用 BIND 变量和 OR 条件的 QUERY 的性能问题

java - ORA-00904 : : invalid identifier Issue with Hibernate Dependent objects program

java - 更改现有数据的 Hibernate 序列生成