función de Oracle Analytic para el valor min en agrupación
-
20-09-2019 - |
Pregunta
Soy nuevo en el trabajo con funciones analíticas.
DEPT EMP SALARY ---- ----- ------ 10 MARY 100000 10 JOHN 200000 10 SCOTT 300000 20 BOB 100000 20 BETTY 200000 30 ALAN 100000 30 TOM 200000 30 JEFF 300000
Quiero que el departamento y empleado con el salario mínimo.
Los resultados deben ser:
DEPT EMP SALARY ---- ----- ------ 10 MARY 100000 20 BOB 100000 30 ALAN 100000
EDIT: Aquí está el SQL He (pero por supuesto, no funciona como quiera personal en el grupo por la cláusula también):
SELECT dept, emp, MIN(salary) KEEP (DENSE_RANK FIRST ORDER BY salary) FROM mytable GROUP BY dept
Solución
Creo que la función RANK () no es el camino a seguir con esto, por dos razones.
En primer lugar, es probable que sea menos eficiente que un Min () -. Método basado
La razón de esto es que la consulta tiene que mantener una lista ordenada de todos los salarios por departamento, ya que explora los datos y el rango a continuación, se asigna más tarde por volver a leer esta lista. Obviamente, en ausencia de índices que se puede aprovechar para esto, no se puede asignar un rango hasta que el último dato ha sido leído, y el mantenimiento de la lista es caro.
Así que el desempeño de la función Rango () depende del número total de elementos a escanear, y si el número es suficiente que los derrames de ordenar el disco entonces el rendimiento se colapsarán.
Esto es probablemente más eficiente:
select dept,
emp,
salary
from
(
SELECT dept,
emp,
salary,
Min(salary) Over (Partition By dept) min_salary
FROM mytable
)
where salary = min_salary
/
Este método sólo requiere que la consulta a mantener un solo valor por cada departamento del valor mínimo encontrado hasta ahora. Si un nuevo mínimo se encuentra a continuación, se modifica el valor existente, de lo contrario se descarta el nuevo valor. El número total de elementos que se tienen que mantiene en la memoria está relacionada con el número de departamentos, no el número de filas examinadas.
Podría ser que Oracle tiene una ruta de código de reconocer que el rango no necesita realmente a calcular en este caso, pero yo no apostaría por ello.
La segunda razón para tener aversión Rango () es que simplemente responde a la pregunta equivocada. La pregunta no es "registros que tienen el sueldo que es el primer ranking cuando los salarios por departamento están ascendiendo ordenaron", es "registros que tienen el sueldo que es el mínimo por departamento". Eso hace una gran diferencia para mí, al menos.
Otros consejos
Creo que eran bastante estrecha con su búsqueda original. El siguiente sería correr y hacer coincidir el caso de test:
SELECT dept,
MIN(emp) KEEP(DENSE_RANK FIRST ORDER BY salary, ROWID) AS emp,
MIN(salary) KEEP (DENSE_RANK FIRST ORDER BY salary, ROWID) AS salary
FROM mytable
GROUP BY dept
A diferencia de la RANK () soluciones, éste garantiza a lo sumo una fila por cada departamento. Pero que alude a un problema: lo que sucede en un departamento donde hay dos empleados en el salario más bajo? Los RANK () volverán soluciones tanto a los empleados - más de una fila para el departamento. Esta respuesta será elegir uno arbitrariamente y asegúrese de que sólo hay una para el departamento.
Puede utilizar la sintaxis RANK()
. Por ejemplo, esta consulta le dirá que un empleado se ubica dentro de su departamento con respecto a qué tan grande es su salario:
SELECT
dept,
emp,
salary,
(RANK() OVER (PARTITION BY dept ORDER BY salary)) salary_rank_within_dept
FROM EMPLOYEES
A continuación, puede consultar desde aquí donde salary_rank_within_dept = 1
:
SELECT * FROM
(
SELECT
dept,
emp,
salary,
(RANK() OVER (PARTITION BY dept ORDER BY salary)) salary_rank_within_dept
FROM EMPLOYEES
)
WHERE salary_rank_within_dept = 1
select e2.dept, e2.emp, e2.salary
from employee e2
where e2.salary = (select min(e1.salary) from employee e1)