#sql #oracle #average
#sql #Oracle #средняя
Вопрос:
Использование схемы СКОТТА. Я пытаюсь найти человека, у которого зарплата ближе всего к средней.
SELECT sal
FROM ( SELECT sal
FROM emp
ORDER BY ABS ( (SELECT AVG (SAL) FROM EMP) - sal))
WHERE ROWNUM = 1;
Можно ли улучшить приведенное выше решение?
Ответ №1:
Вы используете нестандартную функцию Oracle. Данные в подзапросах изначально не имеют порядка, но в Oracle вы можете его упорядочить, чтобы иметь возможность применить критерии ROWNUM позже. ROWNUM также специфичен для Oracle.
Более того, может быть несколько сотрудников с одинаковой зарплатой, когда вы выбираете одного из них произвольно, а не показываете их всех.
Вот как выбрать сотрудника (сотрудников) с зарплатой, наиболее близкой к средней в стандартном SQL:
select *
from emp
order by abs(sal - avg(sal) over())
fetch first row with ties;
Эта последняя строка доступна только начиная с Oracle 12c.
В более старых версиях (то есть Oracle 9i, 10i или 11g) вместо этого вы бы ранжировали свои строки:
select empno, ename, sal
from
(
select empno, ename, sal, rank() over (order by diff) as rnk
from
(
select emp.*, abs(sal - avg(sal) over()) as diff
from emp
) evaluated
) ranked
where rnk = 1;
Комментарии:
1. Привет, в моей базе данных 12c ваше предложение об ограничении строк выдает ошибку. Когда я меняю ваше предложение на
FETCH FIRST ROW WITH TIES
, оно работает.
Ответ №2:
Извлечение данных сотрудника с помощью подзапроса:
select empno, sal, SalDif
from
(
select empno, sal, abs(sal - (select avg(sal) from emp)) as SalDif
from emp
order by SalDif
)
where rownum = 1;
или как CTE:
with CTE as
(
select empno, sal, abs(sal - (select avg(sal) from emp)) as SalDif
from emp
order by SalDif
)
select empno, sal, SalDif
from CTE
where rownum = 1;
Ответ №3:
with av as (select avg(sal) avgsal from scott.emp)
select emp.*, abs(emp.sal-av.avgsal) dist
from scott.emp, av
order by dist;
Для меня это выглядит лучше, но, вероятно, вы можете получить это лучше всего с помощью аналитической функции. Что-то вроде:
select * from (
select emp.*, abs(avg(emp.sal) over () - sal) diff
from scott.emp order by diff)
where rownum = 1;