Тази публикация е част от урока на Oracle SQL и ние ще обсъждаме аналитичните функции в oracle(Over by partition) с примери, подробно обяснение.
Вече проучихме за Oracle Aggregate функцията като avg, sum, count. Да вземем пример
Първо нека създадем примерни данни
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;
Сега примерът за агрегатните функции ще бъде даден по-долу
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
Тук можем да видим, че намалява броя на редовете във всяка от заявките. Сега идват въпросите какво да правим, ако трябва всички редове да бъдат върнати и с count(*)
За този оракул е предоставил набор от аналитични функции. Така че, за да решим последния проблем, можем да запишем като
select empno ,deptno , count(*) over (partition by deptno) from emp group by deptno;
Тук count(*) over (partition by dept_no) е аналитичната версия на агрегатната функция count. Основната ключова работа, която се различава от агрегатната функция, е над разделяне по
Аналитичните функции изчисляват обобщена стойност въз основа на група редове. Те се различават от агрегатните функции по това, че връщат няколко реда за всяка група. Групата от редове се нарича прозорец и се дефинира от analytic_clause.
Ето общия синтаксис
analytic_function([ arguments ]) OVER ([ query_partition_clause ] [ order_by_clause [ windowing_clause ] ])
Пример
count(*) over (partition by deptno) avg(Sal) over (partition by deptno)
Нека разгледаме всяка част
клауза_за_раздел
Той дефинира групата от редове. Може да хареса по-долу
дял по deptno :група от редове от едно и също deptno
или
() :Всички редове
SQL> select empno ,deptno , count(*) over () from emp;
[ order_by_clause [ windowing_clause] ]
Тази клауза се използва, когато искате да подредите редовете в дяла. Това е особено полезно, ако искате аналитичната функция да вземе предвид реда на редовете.
Пример ще бъде функция row_number
SQL> select deptno, ename, sal, row_number() over (partition by deptno order by sal) "row_number" from emp;
Друг пример би бил
SQL> select deptno, ename,hiredate, sal,sum(sal) over (partition by deptno order by HIREDATE) running_sum from emp;
клауза_прозорец
Това винаги се използва с клауза за подреждане и дава повече контрол върху набора от редове в групата
С клауза Windowing, За всеки ред се дефинира плъзгащ прозорец от редове. Прозорецът определя обхвата от редове, използвани за извършване на изчисленията за текущия ред. Размерите на прозореца могат да се основават или на физически брой редове, или на логически интервал, като време.
Когато се използва поръчка по клауза и нищо не е дадено за windowing_clause, се приема под стойността по подразбиране на windowing_clause
ДИАПАЗОН МЕЖДУ НЕЗГРАНИЧЕН ПРЕДШЕСТВЕН И ТЕКУЩ РЕД или ДИАПАЗОН НЕОГРАНИЧЕН ПРЕДИШЕН
Това означава „Текущият и предишните редове в текущия дял са редовете, които трябва да се използват при изчислението”
Примерът по-долу ясно показва това. Това е средната стойност в отдела
SQL> select deptno, ename,hiredate, sal,sum(sal) over (partition by deptno order by HIREDATE) running_sum from emp;
Сега windowing_clause може да се дефинира по няколко начина
Нека първо разберем терминологията
РЕДОВЕ определя прозореца във физически единици (редове).
RANGE определя прозореца като логическо отместване. клаузата за прозорец RANGE може да се използва само с ORDER BY клаузи, съдържащи колони или изрази с числови или датови типове данни
PRECEDING – получаване на редове преди текущия.
СЛЕД – получаване на редове след текущия.
НЕОГРАНИЧЕН – когато се използва с PRECEDING или FOLLOWING, връща всичко преди или след. ТЕКУЩ РЕД
Така че обикновено се определя като
НЕОГРАНИЧЕНИ РЕДОВЕ ПРЕДИШНИ :Текущите и предишните редове в текущия дял са редовете, които трябва да се използват при изчислението
SQL> select deptno, ename,hiredate, sal,sum(sal) over (partition by deptno order by HIREDATE ROWS UNBOUNDED PRECEDING) running_sum from emp;
ОБХВАТ НЕОГРАНИЧЕН ПРЕДИШЕН :Текущите и предишните редове в текущия дял са редовете, които трябва да се използват при изчислението. Освен това, тъй като диапазонът е посочен, всичко приема тези стойности, които са равни на текущите редове.
SQL> select deptno, ename,hiredate, sal,sum(sal) over (partition by deptno order by HIREDATE RANGE UNBOUNDED PRECEDING) running_sum from emp;
Може да не видите разликата между диапазон и редове, тъй като hire_date е различна за всички. Разликата ще стане по-ясна, ако използваме sal като ред по клауза
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;
Можете да намерите разликата на ред 6
RANGE value_expr PRECEDING :Прозорецът започва с реда, чиято стойност ORDER BY е редове с числови изрази, по-малки от или предхождащи текущия ред и завършва с обработването на текущия ред.
SQL> select deptno, ename,hiredate, sal,sum(sal) over (partition by deptno order by HIREDATE RANGE 365 PRECEDING) running_sum from emp;
Тук се вземат всички редове, в които стойността за наемане попада в рамките на 365 дни, предхождащи стойността за наемане на текущия ред
ROWS value_expr ПРЕДИШНО :Прозорецът започва с дадения ред и завършва с текущия ред, който се обработва
SQL> select deptno, ename,hiredate, sal,sum(sal) over (partition by deptno order by HIREDATE ROWS 2 PRECEDING) running_sum from emp;
Тук прозорецът започва от 2 реда, предхождащи текущия ред
ДИАПАЗОН МЕЖДУ ТЕКУЩ РЕД и value_expr СЛЕД :Прозорецът започва с текущия ред и завършва с реда, чиято стойност ORDER BY е редове с числови изрази, по-малки от или следващи
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;
РЕДОВЕ МЕЖДУ ТЕКУЩ РЕД и value_expr СЛЕД :Прозорецът започва с текущия ред и завършва с редовете след текущия
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;
ДИАПАЗОН МЕЖДУ НЕОГРАНИЧЕНО ПРЕДШЕСТВАЩО И НЕОГРАНИЧЕНО СЛЕДВАНЕ
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;
ДИАПАЗОН МЕЖДУ value_expr ПРЕДИШЕН и value_expr СЛЕД
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.
Някои важни бележки
(1) Аналитичните функции са последният набор от операции, извършени в заявка, с изключение на крайната клауза ORDER BY. Всички обединявания и всички клаузи WHERE, GROUP BY и HAVING са завършени преди обработката на аналитичните функции. Следователно аналитичните функции могат да се показват само в списъка за избор или клаузата ORDER BY.
(2)Аналитичните функции обикновено се използват за изчисляване на кумулативни, преместващи, центрирани и отчетни агрегати.
Надявам се да ви хареса това подробно обяснение на аналитичните функции в oracle (над клауза за дял)
Сродни статии
Функция LEAD в Oracle
Функция DENSE в Oracle
Функция Oracle LISTAGG
Агрегиране на данни с помощта на групови функции
https://docs.oracle.com/cd/E11882_01/ server.112/e41084/functions004.htm