martes, 6 de septiembre de 2022

Funciones Analíticas de ORACLE

Desde la versión 8i, Oracle proporciona una serie de funciones que nos pueden facilitar bastante los informes analíticos: rankings, acumulados, porcentajes, etc.

Vamos a ver con una serie de ejemplos lo fácil que puede ser hacer consultas SQL para obtener rankings, listas "Top n", acumulados, etc. Usaremos la tabla EMPLEADOS para los ejemplos.

Supongamos que nos piden obtener el mayor salario de cada departamento y una lista de empleados por departamento. Para obtenerlo en lo primero que pensamos es en utilizar GROUP BY:


SELECT deptno, MAX(sal)

FROM scott.emp

GROUP BY deptno;


Pero necesitamos también una lista de los mejor pagados en cada departamento. Quizás necesitaríamos una subquery:


select

   a.deptno dp,

   a.ename,

   a.sal,

   b.dept_max_sal

from  scott.emp a,  (select deptno, max(sal) dept_max_sal

           from scott.emp

    group by deptno) b

where  a.deptno=b.deptno


Esto mismo que hemos resuelto con una join sobre la misma tabla, lo podemos obtener eliminando la join si hacemos uso de una función analítica:


select  a.deptno dp,

   a.ename,

   a.sal,

   max(sal) over (partition by deptno) dept_max_sal

from  scott.emp a


La función que hemos usado se compone de dos partes:

• En la primera le decimos qué queremos calcular: max(sal). De igual forma podríamos haber usado otras funciones como: SUM, AVG, MIN, MAX, COUNT, VARIANCE, STDDEV, FIRST_VALUE, LAST_VALUE, etc. Ver punto funciones agregadas.

• En la segunda le indicamos el ámbito o "ventana" de la operación (en este caso el departamento). Le hemos dicho que calcule el máximo salario para el departamento del empleado en cuestíón.

Siguiendo con el ejemplo anterior, lo podemos complicar más añadiendo el salario máximo para el tipo de trabajo de cada empleado:


select

   deptno dp,

   ename,

   job,

   sal,

    max(sal) over (partition by deptno) dept_max_sal,

   max(sal) over (partition by job) job_max_sal

from scott.emp


Hemos visto que podemos usar tantas funciones analíticas como queramos en la misma consulta, y además "particionando" por diferentes columnas en cada expresión.

Otra aplicación de las funciones analíticas es la generación de informes que incluyan rankings (como pueden ser los "Top n") y porcentajes. Siguiendo con el ejemplo sobre SCOTT.EMP,

Supongamos que tenemos que hacer un informe del salario de cada empleado, donde sólo aparezcan los tres de cada departamento con mayor sueldo:


select deptno,

   ename,

   sal,

   top3

from (select deptno,

       ename,

       sal,

        dense_rank() over (partition by deptno order by sal desc) top3

      from scott.emp)

where top3<=3


Analicemos la consulta anterior:

• La función analítica que nos sirve de base para obtener el "Top 3" es DENSE_RANK(). Hay otra función que nos permite obtener rankings: RANK(). La diferencia está en que RANK() genera huecos cuando hay valores iguales y DENSE_RANK() no. Para poder establecer el ranking, la función lleva una cláusula "order by" descendente; y por supuesto la cláusula "partition" que permite definir el ámbito en cuestión, en este caso el departamento.

• En la consulta interior (la del from de la principal), estamos generando el ranking; y en la consulta principal seleccionamos aquellos cuyo ranking sea igual o menor que 3.

Igual que hemos sacado un ranking podríamos obtener porcentajes (en tantos por 1), usando CUME_DIST(). Por ejemplo: listado del salario de los empleados que incluya el % que supone el salario de cada uno respecto al más alto de su departamento:


select

   deptno,

   ename,

   sal,

   (cume_dist() over (partition by deptno order by sal))*100 pct

from scott.emp


Para finalizar vamos a ver un ejemplo de informe con acumulados: listado de salarios ordenados por fecha, mostrando una columna con el salario acumulado:


select

   deptno dp,

   hiredate,

   sal,

   sum(sal) over (order by hiredate ROWS UNBOUNDED PRECEDING) acum

from  scott.emp


Supongamos que queremos comparar el salario de un empleado con el contratado inmediatamente posterior.

Para ello podemos utilizar las funciones LAG y LEAD que nos permiten acceder al registro anterior y posterior respectivamente del registro en el que estamos.

El siguiente ejemplo nos muestra si el salario del empleado, que entró en un determinado departamento, inmediatamente posterior a uno dado es mayor que el de este. Solamente queremos los 5 primeros de cada departamento con mayor sueldo.


SELECT

   deptno dept,

   job,

   ename name,

   sal,

   dept_rank,

   hiredate,

   CASE WHEN  sal < LEAD(sal) OVER(PARTITION BY deptno ORDER BY hiredate)

        THEN 'No'

        ELSE 'Yes'

   END seniority_sal

FROM (SELECT

       deptno,

       job,

       ename,

       hiredate,

       sal,

       DENSE_RANK() OVER(PARTITION BY deptno ORDER BY sal DESC) dept_rank

    FROM scott.emp )

WHERE dept_rank <= 5

ORDER BY  dept, dept_rank DESC;


Continua en el articulo original.

Enlace: https://sites.google.com/site/josepando/home/funciones-sql/funciones-analticas



Fuentes.

Artículo:   "Funciones Analíticas" Publicado en https://sites.google.com/ por José Pardo Rodriguez. Consultado el 04/09/2022.

URL: https://sites.google.com/site/josepando/home/funciones-sql/funciones-analticas

No hay comentarios:

Publicar un comentario