[英]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.