подзапрос для получения 3 верхних строк не работает в pl/sql

DECLARE
    CURSOR EMPCUR 
      SELECT EMPNO,ENAME,SAL,ROWNUM 
        FROM (SELECT * 
                FROM EMP 
               ORDER BY SAL DESC) 
       WHERE ROWNUM<=3 
       ORDER BY ROWNUM;
BEGIN
  FOR EMPREC IN EMPCUR
  LOOP
    DBMS_OUTPUT.PUT_LINE('RANK '||EMPREC.ROWNUM);
    DBMS_OUTPUT.PUT_LINE(EMPREC.EMONO||' - '||EMPREC.ENAME||' - '||EMPREC.SAL);
  END LOOP;
END;
/

Этот код не работает:

ОШИБКА в строке 2: ORA-06550: строка 2, столбец 17: PLS-00103: Обнаружен символ "ВЫБОР" при ожидании одного из следующих: ( ; возвращается Символ "есть" был заменен на "ВЫБРАТЬ", чтобы продолжить.


person Dharmin    schedule 27.11.2013    source источник
comment
В объявлении курсора EMPCUR пропущено ключевое слово IS. Более того, в этой конкретной ситуации нет необходимости использовать ORDER BY ROWNUM.   -  person Nick Krasnov    schedule 27.11.2013


Ответы (2)


Вы пропустили IS в объявлении курсора, а в строке 7 EMPREC.EMONO есть опечатка.

Попробуйте так,

DECLARE
    CURSOR EMPCUR IS  SELECT EMPNO,ENAME,SAL,ROWNUM FROM (SELECT * FROM EMP ORDER BY SAL DESC) WHERE ROWNUM<=3 ORDER BY ROWNUM;
BEGIN
    FOR EMPREC IN EMPCUR
    LOOP
        DBMS_OUTPUT.PUT_LINE('RANK '||EMPREC.ROWNUM);
        DBMS_OUTPUT.PUT_LINE(EMPREC.EMPNO||' - '||EMPREC.ENAME||' - '||EMPREC.SAL);
    END LOOP;
END;
/
person Dba    schedule 27.11.2013

Я хотел бы предположить, что ранжирование вещей с использованием псевдостолбца rownum в подзапросе в лучшем случае является ошибочным подходом, редко достигающим реальной цели. Например, вам нужны сотрудники с тремя самыми высокими зарплатами? Или вы всегда хотите до трех записей? Как это уравнение справляется с работниками с одинаковыми зарплатами? И так далее.

Лучше использовать аналитические функции, явно определять ранжирование в этих функциях и возвращать результаты, которые действительно отвечают на вопрос.

begin
    for rec in ( select sq.*
                   from ( select e.employee_id
                               , e.first_name ||' '|| e.last_name as full_name 
                               , e.salary
                               , rank() over (order by e.salary desc) as salary_rank
                            from hr.employees e ) sq
                  where sq.salary_rank <= 3
                  order by sq.salary desc )
    loop
        dbms_output.put_line('RANK ' || rec.salary_rank);
        dbms_output.put_line(rec.employee_id || ' - ' || rec.full_name || ' - ' || rec.salary);
    end loop;
end;
person Michael O'Neill    schedule 27.11.2013