SQL: агрегатная функция и группировка по - PullRequest
3 голосов
/ 09 сентября 2008

Рассмотрим таблицу Oracle emp. Я хотел бы получить сотрудников с максимальной зарплатой с department = 20 и job = clerk. Также предположим, что столбец «empno» отсутствует, и что первичный ключ включает несколько столбцов. Вы можете сделать это с:

select * from scott.emp
where deptno = 20 and job = 'CLERK'
and sal =  (select max(sal) from scott.emp
            where deptno = 20 and job = 'CLERK')

Это работает, но мне нужно продублировать тест deptno = 20 и job = 'CLERK', которого я хотел бы избежать. Есть ли более элегантный способ написать это, возможно, используя group by? Кстати, если это имеет значение, я использую Oracle.

Ответы [ 6 ]

3 голосов
/ 09 сентября 2008

Следующее немного переработано, но является хорошим шаблоном SQL для запросов "top x".

SELECT 
 * 
FROM 
 scott.emp
WHERE 
 (deptno,job,sal) IN
 (SELECT 
   deptno,
   job,
   max(sal) 
  FROM 
   scott.emp
  WHERE 
   deptno = 20 
   and job = 'CLERK'
  GROUP BY 
   deptno,
   job
  )

Также обратите внимание, что это будет работать в Oracle и Postgress (я думаю), но не в MS SQL. Что-то похожее в MS SQL смотрите в вопросе Запрос SQL, чтобы получить последнюю цену

2 голосов
/ 09 сентября 2008

Если бы я был уверен в целевой базе данных, я бы выбрал решение Марка Нольда, но если вам когда-нибудь понадобится некий диалектический SQL *, попробуйте

SELECT * 
FROM scott.emp e
WHERE e.deptno = 20 
AND e.job = 'CLERK'
AND e.sal = (
  SELECT MAX(e2.sal) 
  FROM scott.emp e2
  WHERE e.deptno = e2.deptno 
  AND e.job = e2.job
)

* Я считаю, что это должно работать везде, но у меня нет среды, чтобы проверить это.

1 голос
/ 15 сентября 2008

В Oracle я бы делал это с помощью аналитической функции, поэтому вы бы запрашивали таблицу emp только один раз:

SELECT *
  FROM (SELECT e.*, MAX (sal) OVER () AS max_sal
          FROM scott.emp e
         WHERE deptno = 20 
           AND job = 'CLERK')
 WHERE sal = max_sal

Это проще, легче для чтения и более эффективно.

Если вы хотите изменить его, чтобы перечислить эту информацию для всех отделов, тогда вам нужно использовать предложение "PARTITION BY" в OVER:

SELECT *
  FROM (SELECT e.*, MAX (sal) OVER (PARTITION BY deptno) AS max_sal
          FROM scott.emp e
         WHERE job = 'CLERK')
 WHERE sal = max_sal
ORDER BY deptno
0 голосов
/ 12 сентября 2008

Есть много решений. Вы также можете сохранить исходный макет запроса, просто добавив псевдонимы таблиц и присоединившись к именам столбцов, в этом случае DEPTNO = 20 и JOB = 'CLERK' останутся в запросе один раз.

SELECT 
  * 
FROM 
  scott.emp emptbl
WHERE
  emptbl.DEPTNO = 20 
  AND emptbl.JOB = 'CLERK'
  AND emptbl.SAL =  
    (
      select 
        max(salmax.SAL) 
      from 
        scott.emp salmax
      where 
        salmax.DEPTNO = emptbl.DEPTNO
        AND salmax.JOB = emptbl.JOB
    )

Можно также отметить, что ключевое слово «ALL» может использоваться для этих типов запросов, которые позволят вам удалить функцию «MAX».

SELECT 
  * 
FROM 
  scott.emp emptbl
WHERE
  emptbl.DEPTNO = 20 
  AND emptbl.JOB = 'CLERK'
  AND emptbl.SAL >= ALL  
    (
      select 
        salmax.SAL
      from 
        scott.emp salmax
      where 
        salmax.DEPTNO = emptbl.DEPTNO
        AND salmax.JOB = emptbl.JOB
    )

Я надеюсь, что это помогает и имеет смысл.

0 голосов
/ 09 сентября 2008

В Oracle вы также можете использовать оператор EXISTS, который в некоторых случаях быстрее.

Например ... ВЫБЕРИТЕ имя, номер ОТ КУСТА ГДЕ КУСТ (ВЫБЕРИТЕ cust_id FROM big_table) И вошел> SYSDATE -1 будет медленным.

но ВЫБЕРИТЕ имя, номер ОТ Cust C ГДЕ СУЩЕСТВУЕТ (ВЫБЕРИТЕ cust_id ОТ big_table ГДЕ cust_id = c.cust_id ) И вошел> SYSDATE -1 будет очень быстро с правильной индексацией. Вы также можете использовать это с несколькими параметрами.

0 голосов
/ 09 сентября 2008

Отлично! Я не знал, что вы можете сделать сравнение (x, y, z) с результатом оператора SELECT. Это прекрасно работает с Oracle.

Как примечание для других читателей, в приведенном выше запросе отсутствует знак "=" после "(deptno, job, sal)". Может быть, форматировщик Stack Overflow съел его (?).

Еще раз спасибо, Марк.

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