Получение значений, относящихся к максимальным и минимальным строкам в Oracle - PullRequest
5 голосов
/ 04 мая 2011

В Oracle 11g нам нужно иметь возможность запрашивать таблицу для извлечения информации из строк с самыми высокими и самыми низкими значениями в определенной группе.Например, используя таблицу ПУОС, мы хотели бы найти имя человека с самой высокой зарплатой и имя человека с самой низкой зарплатой в каждом отделе

DEPTNO   MAX_SAL    MAX_EARNER    MIN_SAL    MIN_EARNER
-------------------------------------------------------
10       5000       KING          1300       MILLER
20       3000       FORD          2975       JONES
etc

(если есть два или более сотрудниковс наивысшим или наименьшим salaray мы хотим всегда возвращать первое в алфавитном порядке).

A Предыдущий пост обсуждал, как получить значение только для максимума, но не для max и min.

В настоящее время у нас есть неопрятное решение, основанное на приведенной выше ссылке, а затем применяющее последующие запросы, но для нас важна производительность.Я предсказываю, что для хорошего решения также потребуются аналитические функции и, возможно, стержень для объединения нескольких строк в отдельные строки.

Любая помощь очень ценится!Ричард

Ответы [ 2 ]

5 голосов
/ 04 мая 2011

Это легко разрешимо с аналитическими функциями. Как видите, в DEPT 20 есть два сотрудника, которые получают максимальную зарплату; это важная деталь, так как некоторые общие решения такого рода проблем пропускают эту информацию.

SQL> select ename
  2             , deptno
  3             , sal
  4  from (
  5      select ename
  6             , deptno
  7             , sal
  8             , max (sal) over (partition by deptno) max_sal
  9             , min (sal) over (partition by deptno) min_sal
 10      from emp
 11      )
 12  where sal = max_sal
 13  or    sal = min_sal
 14  order by deptno, sal
 15  /

ENAME          DEPTNO        SAL
---------- ---------- ----------
KISHORE            10       1300
SCHNEIDER          10       5000
CLARKE             20        800
RIGBY              20       3000
GASPAROTTO         20       3000
HALL               30        950
LIRA               30       3750
TRICHLER           50       3500
FEUERSTEIN         50       4500

9 rows selected.

SQL>

Упс, я пропустил важную деталь в формате результата. Мои данные не будут соответствовать запрошенному результату, потому что есть два сотрудника, получающие максимальную зарплату. Так что этот запрос, который я признаю, немного неловкий, дает нам необходимый макет. MIN () в именах сотрудников возвращает алфавитный порядок:

SQL> select
  2         deptno
  3         , max (case when sal = min_sal then min_sal else null end ) as min_sal
  4         , min (case when sal = min_sal then ename else null end ) as min_name
  5         , max (case when sal = max_sal then max_sal else null end ) as max_sal
  6         , min (case when sal = max_sal then ename else null end ) as max_name
  7  from (
  8      select ename
  9             , deptno
 10             , sal
 11             , max (sal) over (partition by deptno) max_sal
 12             , min (sal) over (partition by deptno) min_sal
 13      from emp
 14      )
 15  where sal = max_sal
 16  or    sal = min_sal
 17  group by deptno
 18  order by deptno
 19  /

    DEPTNO    MIN_SAL MIN_NAME      MAX_SAL MAX_NAME
---------- ---------- ---------- ---------- ----------
        10       1300 KISHORE          5000 SCHNEIDER
        20        800 CLARKE           3000 GASPAROTTO
        30        950 HALL             3750 LIRA
        50       3500 TRICHLER         4500 FEUERSTEIN

SQL>

Мне не нравится это решение. Большинство наборов данных будут содержать такие конфликты, и мы должны признать их. Фильтрация результатов на основе некоторых несвязанных критериев для соответствия макету прокрустова отчета вводит в заблуждение. Я бы предпочел макет отчета, который отражает весь набор данных. В конечном итоге это зависит от бизнес-цели, которой служит запрос. И, конечно же, клиент всегда прав 8 -)

1 голос
/ 04 мая 2011

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

SELECT
  dept,
  max_sal,
  (SELECT emp_name FROM emp WHERE salary = max_sal AND rownum =1) max_earner,
  min_sal,
  (SELECT emp_name FROM emp WHERE salary = min_sal AND rownum =1) min_earner
FROM
  (SELECT
    dept,
    MAX(salary) max_sal,
    MIN(salary) min_sal
  FROM emp
  GROUP BY dept);

при условии, что ваш стол выглядит так:

CREATE TABLE emp
(
    dept NUMBER,
    emp_name VARCHAR2(20 BYTE),
    salary NUMBER
);

Обновление

Чтобы выполнить ваше другое требование ", если есть два или более сотрудников с самым высоким или самым низким сараем, мы хотим всегда возвращать первое в алфавитном порядке ", вы можете настроить запрос немного как ниже (я уверен, что здесь есть возможности для улучшения):

SELECT
  dept,
  max_sal,
  (select emp_name from (SELECT * FROM emp order by emp_name asc) WHERE salary = max_sal AND rownum =1) max_earner,
  min_sal,
  (select emp_name from (SELECT * FROM emp order by emp_name asc) WHERE salary = min_sal AND rownum =1) min_earner
FROM
  (SELECT
    dept,
    MAX(salary) max_sal,
    MIN(salary) min_sal
  FROM emp
  GROUP BY dept);
...