2016-03-29 4 views
2

私のSQL演習をしていますが、 2つの最高給与の従業員を取得する必要がありますが、サブクエリまたは派生テーブルのタイプは使用できません。私はこのようなサブクエリでそれを行う:ORACLE SQLはサブクエリまたは派生テーブルなしでn行を取得します

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

また、私は、これはWITH句を使用して達成することができることを知っているが、これに任意の代替がある場合、私は思ったんだけど。

PS:私は、Oracleのバージョン12.1ですか、あなたが行制限句を使用することができます上記の場合

+0

技術的には、「サブクエリ」ではなく派生テーブルです。どのOracleのバージョンを使用していますか? Oracle 12では、ANSI SQLの '最初の3行のみを取得'を使用できます –

+0

インラインビューを使用しています。 where句でクエリを実行すると、サブクエリになります。 – Avani

+0

はい、わかっていますが、派生テーブルを使用することはできません(申し訳ありませんが、申し訳ありません)。私はOracleを使用しています –

答えて

1

...パイプライン化された機能でそれを行うことができますが、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; 

注:これは本当に同等ですa dense_rank()です。したがって、結びつきがある場合は、2つ以上の行が表示されます。これを修正するのは簡単です(各行に一意の識別子があると仮定します)。しかし、修正はロジックを複雑にし、基本的な考えを隠します。

+0

これは私が探していたものです!私は 'dense_rank()'関数とwhere節も試しましたが、それは連動していないので、これは 'dense_rank()'関数のようなものです。どうもありがとう! –

+1

本当に唯一の解決策です。 –

1

Oracleの11を使用しています。あなたのケースでは、ちょうどそうのようなサブクエリプラス行制限句を使用します。

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

+0

こんにちは、私はOracle 11を使用しています –

+0

こんにちはElias、私はanalytics関数を使用して答えを追加しました。それが動作するかどうか私に教えてください! –

+0

更新されたクエリにはfrom句がありません。修正すると 'Emp'に' sal_rank'カラムがなく 'WHERE'句が' ORA-00904: "SAL_RANK":invalid identifier'になります選択された列が生成される前に評価されます。 – MT0

0

これは浮気けど...代わりのビューを定義することができますサブクエリを使用している:

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)); 
+0

はい、これは 'WITH'節を使うようなものです。私たちはこのようにもできません... –

+0

@EliasGarciaMariñoは、パイプライン関数を使って解決法を追加しました。これが許可されていないかどうかはわかりません。 – MT0

1

良い運動は、実用的な問題を解決するための準備に役立つはずです。だから重要なものサブクエリの使用ではありませんが、2つのhighesの給与は従業員の繁栄を持つことができることを認識することです。 @のMT0 ビュー回避策を使用している間

が、これは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 
+0

サブクエリを使用します。 –

+0

@Gordonあなたは正しいですが、正しい答えにつながるならば、あまり意味のないルールは軽い違反になります*: –

+0

@Gordon要件を満たすためにサブクエリを削除することにしました。 –

0

何のサブクエリを使用していない。この解決策になることができます説明したように、クエリに

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 
; 

結果であるが、3つのステップが必要です:

-- 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の給与を得るためのクエリemps。

関連する問題