Проблема с MINUS и подзапросами с ORDER BYs - PullRequest
0 голосов
/ 25 февраля 2020
select salary 
from (
        (select salary  
         from   employees 
         where rownum<=10 
         order by salary desc)
         minus
        (select salary 
         from   employees 
         where rownum<=4 
         order by salary desc)
      );

Ответы [ 3 ]

3 голосов
/ 25 февраля 2020

Вы не можете использовать ORDER BY там.

Попробуйте вместо этого:

select salary from (
    select salary, row_number() over ( order by salary desc ) rn
     from   employees )
where rn between 5 and 10;

Вкл. Oracle 12 c или выше, вы также можете сделать это:

select salary from employees
order by salary desc
offset 4 rows fetch next 6 rows only;
2 голосов
/ 25 февраля 2020

У вас есть несколько проблем в том, что вы написали. Непосредственная проблема заключается в том, что вы получите ошибку из-за наличия order by в первой ветви вашего союза, но простое удаление, которое вам не очень поможет.

Вы делаете (довольно часто ) ошибка с заказом и rownum; глядя на первый подзапрос, который у вас есть:

select salary  
from   employees 
where rownum<=10 
order by salary desc

Фильтр rownum будет применен до упорядочения, так что это фактически приведет к 10 неопределенным строкам из стол, который затем заказывается. Если я запускаю это, я получаю:

    SALARY
----------
     24000
     13000
     12000
     10000
      8300
      6500
      6000
      4400
      2600
      2600

, но вы увидите разные значения, даже из одной и той же схемы примера. Если вы посмотрите на всю таблицу, вы увидите более высокие значения, чем те; и даже выполнение второго запроса покажет, что что-то не так, как вы ожидаете - для меня это выглядит так:

    SALARY
----------
     13000
      4400
      2600
      2600

, которые не первые четыре строки из предыдущего запроса. (Опять же, вы увидите другие результаты, но, надеюсь, тот же эффект; если нет, посмотрите на всю таблицу, упорядоченную по зарплате.)

Вам необходимо упорядочить всю таблицу - в подзапросе - и затем отфильтровать :

select salary 
from (
  select salary  
  from employees 
  order by salary desc
)
where rownum<=10

, что дает гораздо более ощутимый и последовательный результат. Затем вы можете минус два запроса:

select salary 
from (
  select salary  
  from employees 
  order by salary desc
)
where rownum<=10
minus
select salary 
from (
  select salary 
  from employees 
  order by salary desc
)
where rownum<=4
order by salary desc;

    SALARY
----------
     13500
     13000
     12000
     11500

Возможно, вы ожидаете увидеть там шесть значений, но есть три сотрудника с зарплатой 12000, а minus устраняет дубликаты, поэтому сообщается только один раз. , Подход @ Мэтью (или @ Джеффа!) Даст вам все шесть, включая дубликаты, если вы этого хотите. Это также останавливает необходимость многократного попадания в таблицу.

Еще одна проблема связана со связями: если бы 4-й максимум был таким же, как 5-й, что бы вы ожидали? Использование minus исключит это значение; Подход @ Мэтью сохранит его.

Вам нужно определить, что вы на самом деле хотите получить - 5–10-е самые высокие значения заработной платы? Зарплаты 5–10-го высокооплачиваемых людей (небольшая, но важная разница)? Вы действительно хотите только цифры или кто эти сотрудники? В таком случае, как вы справляетесь со связями, еще важнее? Et c. Как только вы знаете, что вам действительно нужно найти, вы можете решить, как лучше всего добиться этого результата.

1 голос
/ 25 февраля 2020

Не имеет смысла упорядочивать строки в двух наборах, с которыми впоследствии оперируют, потому что наборы не имеют порядка. Если вам нужно решение, которое может выполняться на более старых версиях, и вы хотите вернуть 6 ранжированных из 10 ранжированных, то это будет работать. Если вы можете использовать более новые функции, то вы можете захотеть, потому что, возможно, им потребуется меньше выполнений машинных инструкций.

После внесения очевидных изменений, которые ускользнули от меня в моей спешке ...

select salary
from (
      select rownum rn, salary
      from (
            select salary
            from   employees
            order by salary desc
           )
      )
where rn between 5 and 10
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...