簡體   English   中英

ORACLE SQL檢索n行而沒有子查詢或派生表

[英]ORACLE SQL retrieve n rows without subqueries or derived tables

我正在做我的SQL練習,但我陷入其中。 我需要檢索薪水最高的兩個員工,但不能使用任何類型的子查詢或派生表。 我用這樣的子查詢來做到這一點:

SELECT *
FROM (SELECT * FROM emp ORDER BY sal DESC) new_emp
WHERE ROWNUM < 3;

我也知道可以使用WITH子句來實現,但是我想知道是否還有其他選擇。

PS:我正在使用Oracle 11。

如果您使用的是Oracle 12.1或更高版本,則可以使用行限制子句。 在您的情況下,您將只使用子查詢加上行限制子句,如下所示:

SELECT * FROM emp 
ORDER BY sal DESC
FETCH FIRST 5 ROWS ONLY;

來源: https : //oracle-base.com/articles/12c/row-limiting-clause-for-top-n-queries-12cr1#top-n

我認為這實際上是一種可悲的方法,但是您可以使用join

select e.col1, e.col2, . . .
from emp e left join
     emp e2
     on e2.salary >= e.salary
group by e.col1, e.col2, . . .
having count(distinct e2.salary) <= 2;

注意:這實際上等效於dense_rank() ,因此,如果有聯系,您將獲得兩行以上。 修復此問題很容易(假設每行都有一個唯一的標識符),但是此修復使邏輯復雜化並隱藏了基本思想。

良好的鍛煉應該有助於准備解決實際問題。 因此,在這一過程中, 重要的 不是使用子查詢,而是要意識到這兩個最高的薪水可能會給員工帶來不利影響。

使用@ MT0 視圖解決方法時,這是查詢

CREATE VIEW sal_ordered_emps AS
  SELECT e.*,
  row_number() over (order by sal desc) as RN
  FROM   SCOTT.emp e
  ORDER BY sal DESC;

select e.* from scott.emp e join 
sal_ordered_emps soe on e.sal = soe.sal and rn <= 2
;

解釋的結果可能超過2條記錄

     EMPNO ENAME      JOB              MGR HIREDATE                   SAL       COMM     DEPTNO
---------- ---------- --------- ---------- ------------------- ---------- ---------- ----------
      7788 SCOTT      ANALYST         7566 19.04.1987 00:00:00       3000                    20 
      7839 KING       PRESIDENT            17.11.1981 00:00:00       5000                    10 
      7902 FORD       ANALYST         7566 03.12.1981 00:00:00       3000                    20 

這很騙人,但是...您可以定義視圖,而不是使用子查詢:

CREATE VIEW sal_ordered_emps AS
  SELECT *
  FROM   emp
  ORDER BY sal DESC;

然后,您可以執行以下操作:

SELECT * FROM sal_ordered_emps WHERE ROWNUM < 3;

另外,您也可以使用流水線函數來實現...

CREATE OR REPLACE PACKAGE emp_pkg
AS
  TYPE emp_table IS TABLE OF EMP%ROWTYPE;

  FUNCTION get_max_sals(
    n INT
  ) RETURN emp_table PIPELINED;
END;
/

CREATE OR REPLACE PACKAGE BODY emp_pkg
AS
  FUNCTION get_max_sals(
    n INT
  ) RETURN emp_table PIPELINED
  AS
    cur SYS_REFCURSOR;
    in_rec EMP%ROWTYPE;
    i INT := 0;
  BEGIN
    OPEN cur FOR SELECT * FROM EMP ORDER BY SAL DESC;
    LOOP
      i := i + 1;
      FETCH cur INTO in_rec; 
      EXIT WHEN cur%NOTFOUND OR i > n;
      PIPE ROW(in_rec);
    END LOOP;
    CLOSE cur;
    RETURN;
  END;
END;
/

SELECT *
FROM   TABLE( emp_pkg.get_max_sals( 2 ) );

此解決方案不使用子查詢,但是需要三個步驟:

-- Q1
select max(sal) from scott.emp;
-- Q2
select max(sal) from scott.emp where sal < {result of Q1}; 

select * from scott.emp where sal in ({result of Q1},{result of Q2});

通常,您需要N + 1個查詢才能獲得前N名的薪水經驗。

暫無
暫無

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

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