sql >> Base de Datos >  >> RDS >> Oracle

Cómo usar funciones analíticas en Oracle (Sobre partición por palabra clave)

Esta publicación es parte del tutorial de Oracle SQL y estaríamos discutiendo las funciones analíticas en Oracle (por partición) con ejemplos, explicación detallada.

Ya hemos estudiado sobre la función Oracle Aggregate como avg, sum, count. Tomemos un ejemplo

Primero vamos a crear los datos de muestra

CREATE TABLE "DEPT"
( "DEPTNO" NUMBER(2,0),
"DNAME" VARCHAR2(14),
"LOC" VARCHAR2(13),
CONSTRAINT "PK_DEPT" PRIMARY KEY ("DEPTNO")
)

CREATE TABLE "EMP"
( "EMPNO" NUMBER(4,0),
"ENAME" VARCHAR2(10),
"JOB" VARCHAR2(9),
"MGR" NUMBER(4,0),
"HIREDATE" DATE,
"SAL" NUMBER(7,2),
"COMM" NUMBER(7,2),
"DEPTNO" NUMBER(2,0),
CONSTRAINT "PK_EMP" PRIMARY KEY ("EMPNO"),
CONSTRAINT "FK_DEPTNO" FOREIGN KEY ("DEPTNO")
REFERENCES "DEPT" ("DEPTNO") ENABLE
);

SQL> desc emp
Name Null? Type
---- ---- -----
EMPNO NOT NULL NUMBER(4)
ENAME VARCHAR2(10)
JOB VARCHAR2(9)
MGR NUMBER(4)
HIREDATE DATE
SAL NUMBER(7,2)
COMM NUMBER(7,2)
DEPTNO NUMBER(2)

SQL> desc dept
Name Null? Type
---- ----- ----
DEPTNO NOT NULL NUMBER(2)
DNAME VARCHAR2(14)
LOC VARCHAR2(13)


insert into DEPT values(10, 'ACCOUNTING', 'NEW YORK');
insert into dept values(20, 'RESEARCH', 'DALLAS');
insert into dept values(30, 'RESEARCH', 'DELHI');
insert into dept values(40, 'RESEARCH', 'MUMBAI');
commit;

insert into emp values( 7839, 'Allen', 'MANAGER', 7839, to_date('17-11-1981','dd-mm-yyyy'), 20, null, 10 );
insert into emp values( 7782, 'CLARK', 'MANAGER', 7839, to_date('9-06-1981','dd-mm-yyyy'), 0, null, 10 );
insert into emp values( 7934, 'MILLER', 'MANAGER', 7839, to_date('23-01-1982','dd-mm-yyyy'), 0, null, 10 );
insert into emp values( 7788, 'SMITH', 'ANALYST', 7788, to_date('17-12-1980','dd-mm-yyyy'), 800, null, 20 );
insert into emp values( 7902, 'ADAM, 'ANALYST', 7832, to_date('23-05-1987','dd-mm-yyyy'), 1100, null, 20 );
insert into emp values( 7876, 'FORD', 'ANALYST', 7566, to_date('3-12-1981','dd-mm-yyyy'), 3000, null, 20 );
insert into emp values( 7369, 'SCOTT', 'ANALYST', 7566, to_date('19-04-1987','dd-mm-yyyy'), 3000, null, 20 );
insert into emp values( 7698, 'JAMES', 'ANALYST', 7788, to_date('03-12-1981','dd-mm-yyyy'), 950, null, 30 );
insert into emp values( 7499, 'MARTIN', 'ANALYST', 7698, to_date('28-09-1981','dd-mm-yyyy'), 1250, null, 30 );
insert into emp values( 7844, 'WARD', 'ANALYST', 7698, to_date('22-02-1981','dd-mm-yyyy'), 1250, null, 30 );
insert into emp values( 7654, 'TURNER', 'ANALYST', 7698, to_date('08-09-1981','dd-mm-yyyy'), 1500, null, 30 );
insert into emp values( 7521, 'ALLEN', 'ANALYST', 7698, to_date('20-02-1981','dd-mm-yyyy'), 1600, null, 30 );
insert into emp values( 7900, 'BLAKE', 'ANALYST', 77698, to_date('01-05-1981','dd-mm-yyyy'), 2850, null, 30 );
commit;

Ahora el ejemplo de funciones agregadas se dará a continuación

select count(*) from EMP;
---------
13

select sum (bytes) from dba_segments where tablespace_name='TOOLS';
-----
100

SQL> select deptno ,count(*) from emp group by deptno;

DEPTNO COUNT(*)
---------- ----------
30              6
20              4
10              3

Aquí podemos ver que reduce el número de filas en cada una de las consultas. Ahora viene la pregunta de qué hacer si necesitamos que todas las filas se devuelvan con conteo (*) también

Para ese oráculo ha proporcionado un conjunto de funciones analíticas. Entonces, para resolver el último problema, podemos escribir como

select empno ,deptno , count(*) over (partition by deptno) from emp group by deptno;

Aquí count(*) over (partición por dept_no) es la versión analítica de la función agregada de conteo. El trabajo clave principal que es diferente según la función agregada es sobre la partición por

Las funciones analíticas calculan un valor agregado basado en un grupo de filas. Se diferencian de las funciones agregadas en que devuelven varias filas para cada grupo. El grupo de filas se denomina ventana y está definido por la cláusula_analítica.

Aquí está la sintaxis general

analytic_function([ arguments ]) OVER ([ query_partition_clause ] [ order_by_clause [ windowing_clause ] ])

Ejemplo

count(*) over (partition by deptno)

avg(Sal) over (partition by deptno)

Repasemos cada parte

cláusula_partición_consulta
Definía el grupo de filas. Puede gustar a continuación

partición por deptno :grupo de filas del mismo deptno
o
() :Todas las filas

SQL> select empno ,deptno , count(*) over () from emp;

[ order_by_clause [ windowing_clause ] ]

Esta cláusula se usa cuando desea ordenar las filas en la partición. Esto es particularmente útil si desea que la función analítica considere el orden de las filas.

El ejemplo será la función número_fila

SQL> select
deptno, ename, sal, 
 row_number() over (partition by deptno order by sal) "row_number" from emp;

Otro ejemplo sería

SQL> select deptno, ename,hiredate, sal,sum(sal) over (partition by deptno order by HIREDATE) running_sum from emp;

Cláusula_ventana

Esto siempre se usa con la cláusula order by y da más control sobre el conjunto de filas en el grupo

Con la cláusula Windowing, para cada fila, se define una ventana deslizante de filas. La ventana determina el rango de filas utilizadas para realizar los cálculos para la fila actual. Los tamaños de ventana se pueden basar en un número físico de filas o en un intervalo lógico como el tiempo.

Cuando se usa la cláusula order by y no se proporciona nada para la cláusula_ventana, se toma el valor predeterminado de la cláusula_ventana
RANGO ENTRE LA FILA PRECEDENTE SIN LÍMITES Y LA FILA ACTUAL o RANGO PRECEDENTE SIN LÍMITES
Significa "Las filas actual y anterior en la fila actual". partición son las filas que deben usarse en el cálculo”

El siguiente ejemplo lo establece claramente. Este es el promedio móvil en el departamento

SQL> select deptno, ename,hiredate, sal,sum(sal) over (partition by deptno order by HIREDATE) running_sum from emp;

Ahora windowing_clause se puede definir de varias maneras
Primero comprendamos la terminología

FILAS especifica la ventana en unidades físicas (filas).
RANGO especifica la ventana como un desplazamiento lógico. la cláusula de ventana RANGE solo se puede usar con cláusulas ORDER BY que contienen columnas o expresiones de tipos de datos numéricos o de fecha
ANTERIOR – obtener filas antes de la actual.
SIGUIENTE – obtener filas después de la actual.
SIN LÍMITES – cuando se usa con PRECEDING o FOLLOWING, devuelve todo antes o después. FILA ACTUAL

Por lo tanto, generalmente se define como

FILAS PRECEDENTES ILIMITADAS :Las filas actuales y anteriores en la partición actual son las filas que deben usarse en el cálculo

SQL> select deptno, ename,hiredate, sal,sum(sal) over (partition by deptno order by HIREDATE ROWS UNBOUNDED PRECEDING) running_sum from emp;

RANGO ILIMITADO PRECEDENTE :Las filas actual y anterior en la partición actual son las filas que deben usarse en el cálculo. Además, dado que se especifica el rango, todo toma los valores que son iguales a las filas actuales.

SQL> select deptno, ename,hiredate, sal,sum(sal) over (partition by deptno order by HIREDATE RANGE UNBOUNDED PRECEDING) running_sum from emp;

Es posible que no vea la diferencia entre el rango y las filas, ya que la fecha_contratación es diferente para todos. La diferencia será más clara si usamos sal como cláusula order by

SQL> select deptno, ename,hiredate, sal,sum(sal) over (partition by deptno order by sal RANGE UNBOUNDED PRECEDING) running_sum from emp;
SQL> select deptno, ename,hiredate, sal,sum(sal) over (partition by deptno order by sal ROWS UNBOUNDED PRECEDING) running_sum from emp;

Puede encontrar la diferencia en la línea 6

RANGO value_expr PRECEDENTE :La ventana comienza con la fila cuyo valor ORDER BY es filas de expresión numérica anteriores o anteriores a la fila actual y finaliza con la fila actual que se está procesando.

SQL> select deptno, ename,hiredate, sal,sum(sal) over (partition by deptno order by HIREDATE RANGE 365 PRECEDING) running_sum from emp;

Aquí toma todas las filas en las que el valor de la fecha de contratación se encuentra dentro de los 365 días anteriores al valor de la fecha de contratación de la fila actual

FILAS valor_expr PRECEDENTES :La ventana comienza con la fila dada y termina con la fila actual procesada

SQL> select deptno, ename,hiredate, sal,sum(sal) over (partition by deptno order by HIREDATE ROWS 2 PRECEDING) running_sum from emp;

Aquí la ventana comienza desde 2 filas que preceden a la fila actual

RANGO ENTRE LA FILA ACTUAL y value_expr SIGUIENTE :La ventana comienza con la fila actual y termina con la fila cuyo valor ORDER BY es filas de expresión numérica menores que o siguientes

SQL> select deptno, ename,hiredate, sal,sum(sal) over (partition by deptno order by HIREDATE ROWS between current row and 1 FOLLOWING) running_sum from emp;

FILAS ENTRE LA FILA ACTUAL y value_expr SIGUIENTE :La ventana comienza con la fila actual y termina con las filas posteriores a la actual

SQL> select deptno, ename,hiredate, sal,sum(sal) over (partition by deptno order by HIREDATE ROWS between current row and 1 FOLLOWING) running_sum from emp;

RANGO ENTRE PRECEDENTE SIN LÍMITES y SIGUIENTE SIN LÍMITES

SQL> select deptno, ename,hiredate, sal,sum(sal) over (partition by deptno order by HIREDATE RANGE BETWEEN UNBOUNDED PRECEDING and UNBOUNDED FOLLOWING
) running_sum from emp;

RANGO ENTRE value_expr PRECEDENTE y value_expr SIGUIENTE

SQL> select deptno, ename,hiredate, sal,sum(sal) over (partition by deptno order by HIREDATE RANGE BETWEEN 365 PRECEDING and 365 FOLLOWING
) running_sum from emp; 2

DEPTNO       ENAME      HIREDATE      SAL      RUNNING_SUM
---------- ---------- --------------- ---------- -----------
10           CLARK       09-JUN-81      0          0
10           ALLEN       17-NOV-81      0          0
10           MILLER      23-JAN-82      0          0
20           SMITH       17-DEC-80      800       3800
20           FORD        03-DEC-81      3000      3800
20           SCOTT       19-APR-87      3000      4100
20           ADAMS       23-MAY-87      1100      4100
30           ALLEN       20-FEB-81      1600      9400
30           WARD        22-FEB-81      1250      9400
30           BLAKE       01-MAY-81      2850      9400
30          TURNER       08-SEP-81      1500      9400
30          MARTIN       28-SEP-81      1250      9400
30          JAMES        03-DEC-81      950       9400

13 rows selected.

Algunas notas importantes
(1)Las funciones analíticas son el último conjunto de operaciones realizadas en una consulta, excepto la cláusula ORDER BY final. Todas las uniones y todas las cláusulas WHERE, GROUP BY y HAVING se completan antes de que se procesen las funciones analíticas. Por lo tanto, las funciones analíticas solo pueden aparecer en la lista de selección o en la cláusula ORDER BY.
(2) Las funciones analíticas se usan comúnmente para calcular agregados acumulativos, móviles, centrados y de generación de informes.

Espero que les guste esta explicación detallada de las funciones analíticas en Oracle (sobre la cláusula de partición)

Artículos relacionados
Función LEAD en Oracle
Función DENSE en Oracle
Función Oracle LISTAGG
Agregación de datos mediante funciones de grupo
https://docs.oracle.com/cd/E11882_01/ servidor.112/e41084/funciones004.htm