簡體   English   中英

獲取與 Oracle 中的最大和最小行相關的值

[英]Getting values relating to the max and min rows in Oracle

在 Oracle 11g 中,我們需要能夠查詢表以從某個組中具有最高和最低值的行中提取信息。 例如使用 EMP 表,我們想找到每個部門中薪水最高的人的姓名和薪水最低的人的姓名

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

(如果有兩個或更多員工的薪水最高或最低,我們希望始終按字母順序返回第一個)。

上一篇文章討論了如何僅獲取最大值而不是最大值和最小值的值。

基於上面的鏈接,我們目前有一個不整潔的解決方案,然后應用后續查詢,但性能對我們很重要。 我預測一個好的解決方案還需要分析函數,可能還需要一個 pivot 來將多行合並為單行。

非常感謝任何幫助! 理查德

這很容易用解析函數解決。 如您所見,有兩名員工在 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>

糟糕,我錯過了有關結果格式的重要細節。 我的數據不符合要求的 output,因為有兩名員工獲得最高工資。 因此,我承認這個查詢有點尷尬,它為我們提供了所需的布局。 員工姓名上的 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>

我不喜歡這個解決方案。 大多數數據集都會包含這樣的沖突,我們需要承認它們。 根據一些不相關的標准過濾結果以適應 Procrustean 報告布局是誤導性的。 我更喜歡反映整個數據集的報告布局。 最終,它取決於查詢服務的業務目的。 而且,當然,客戶永遠是對的 8-)

您可以使用以下查詢

SELECT
  dept,
  max_sal,
  (SELECT emp_name FROM emp WHERE salary = max_sal AND rownum =1) max_earner,
  min_sal,
  (SELECT emp_name FROM emp WHERE salary = min_sal AND rownum =1) min_earner
FROM
  (SELECT
    dept,
    MAX(salary) max_sal,
    MIN(salary) min_sal
  FROM emp
  GROUP BY dept);

假設您的表格如下所示:

CREATE TABLE emp
(
    dept NUMBER,
    emp_name VARCHAR2(20 BYTE),
    salary NUMBER
);

更新

為了滿足您的其他要求“如果有兩個或更多員工的薪水最高或最低,我們希望始終按字母順序返回第一個”,您可以稍微調整查詢如下(我確定有 scope這里的改進):

SELECT
  dept,
  max_sal,
  (select emp_name from (SELECT * FROM emp order by emp_name asc) WHERE salary = max_sal AND rownum =1) max_earner,
  min_sal,
  (select emp_name from (SELECT * FROM emp order by emp_name asc) WHERE salary = min_sal AND rownum =1) min_earner
FROM
  (SELECT
    dept,
    MAX(salary) max_sal,
    MIN(salary) min_sal
  FROM emp
  GROUP BY dept);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM