UNICORN COLLEGE BAKALÁŘSKÁ PRÁCE

Podobné dokumenty
XMW4 / IW4 Pokročilé SELECT dotazy. Štefan Pataky

KIV/ZIS cvičení 5. Tomáš Potužák

6. blok část B Vnořené dotazy

6. blok část C Množinové operátory

Gymnázium a Střední odborná škola, Rokycany, Mládežníků 1115

Základní přehled SQL příkazů

Databázové systémy I

Operátory ROLLUP a CUBE

Databáze SQL SELECT. David Hoksza

Informační systémy 2008/2009. Radim Farana. Obsah. Dotazy přes více tabulek

Úvod do databázových systémů

Úvod do databázových systémů

Úvod do databázových systémů

2. blok část B Základní syntaxe příkazů SELECT, INSERT, UPDATE, DELETE

Jaký je rozdíl v definicicíh VARCHAR2(20 BYTE) a VARCHAR2(20 CHAR):

Dotazy tvorba nových polí (vypočítané pole)

Databázové systémy. Cvičení 6: SQL

Kurz Databáze. Obsah. Dotazy. Zpracování dat. Doc. Ing. Radim Farana, CSc.

Gymnázium a Střední odborná škola, Rokycany, Mládežníků 1115

12. blok Pokročilé konstrukce SQL dotazů - část II

Databáze I. Přednáška 6

Gymnázium a Střední odborná škola, Rokycany, Mládežníků 1115

Ukládání a vyhledávání XML dat

5. blok Souhrnné a skupinové dotazy

Marketingová komunikace. 2. soustředění. Mgr. Pavel Vávra Kombinované studium Skupina N9KMK1aPH/N9KMK1bPH (um1a1ph/um1b1ph)

4. blok část A Logické operátory

KIV/ZIS - SELECT, opakování

Informační systémy ve zdravotnictví. 10. cvičení

Databázové systémy a SQL

Návrh a tvorba WWW stránek 1/14. PHP a databáze

Dotazování v relačním modelu a SQL

DATA CUBE. Mgr. Jiří Helmich

Co bude výsledkem mého SELECTu? RNDr. David Gešvindr MVP: Data Platform MCSE: Data Platform MCSD: Windows Store MCT

Databázové systémy. - SQL * definice dat * aktualizace * pohledy. Tomáš Skopal

MS Access Dotazy SQL

8. Posloupnosti, vektory a matice

Tiskové sestavy. Zdroj záznamu pro tiskovou sestavu. Průvodce sestavou. Použití databází

Dotazovací jazyky I. Datová krychle. Soběslav Benda

Popis ovládání. Po přihlášení do aplikace se objeví navigátor. Navigátor je stromově seřazen a slouží pro přístup ke všem oknům celé aplikace.

Úvod do databází. Modelování v řízení. Ing. Petr Kalčev

Dotaz se souhrny a dotaz křížový

KAPITOLA 9 - POKROČILÁ PRÁCE S TABULKOVÝM PROCESOREM

Tabulkový procesor. Základní rysy

Databázové systémy a SQL

Marketingová komunikace. 2. a 3. soustředění. Mgr. Pavel Vávra 9103@mail.vsfs.cz. Kombinované studium Skupina N9KMK3PH (vm3aph)

Úvod do databázových systémů 3. cvičení

45 Plánovací kalendář

Obsah. SQL konstrukce select join Rekurze (rekurzivní with) Analytické funkce, group by Pivoting

Multi-dimensional expressions

Databázové systémy Cvičení 5.2

SQL SQL-SELECT. Informační a znalostní systémy. Informační a znalostní systémy SQL- SELECT

Gymnázium a Střední odborná škola, Rokycany, Mládežníků 1115

8 Třídy, objekty, metody, předávání argumentů metod

Novinky v PostgreSQL 9.4. Tomáš Vondra, 2ndQuadrant

Sada 1 - PHP. 15. Výběr dat z databáze. Příkaz SELECT

RELAČNÍ DATABÁZE ACCESS

DATABÁZE A SYSTÉMY PRO UCHOVÁNÍ DAT 61 DATABÁZE - ACCESS. (příprava k vykonání testu ECDL Modul 5 Databáze a systémy pro zpracování dat)

Databázové systémy. Datová integrita + základy relační algebry. 4.přednáška

Jazyk PL/SQL Úvod, blok

Marketingová komunikace. 3. soustředění. Mgr. Pavel Vávra Kombinované studium Skupina N9KMK3PH (vm3bph)

VZORCE A VÝPOČTY. Autor: Mgr. Dana Kaprálová. Datum (období) tvorby: září, říjen Ročník: sedmý

Úvod do databázových systémů

Databáze. Velmi stručný a zjednodušený úvod do problematiky databází pro programátory v Pythonu. Bedřich Košata

Osnova je orientační pro FIT, u FEKTu se dá předpokládat, že budou zohledněny předchozí znalosti studentů, kde většina s databází nikdy přímo

B0M33BDT Technologie pro velká data. Supercvičení SQL, Python, Linux

Gymnázium a Střední odborná škola, Rokycany, Mládežníků 1115

Informační systémy ve zdravotnictví. 6. cvičení

5. Lokální, vázané a globální extrémy

Instalace. Produkt je odzkoušen pro MS SQL server 2008 a Windows XP a Windows 7. Pro jiné verze SQL server a Windows nebyl testován.

Úvod do databázových systémů

KIV/ZIS cvičení 6. Tomáš Potužák

Databázové systémy I. 4. přednáška

PG 9.5 novinky ve vývoji aplikací

Jazyk SQL 1. Michal Valenta. Katedra softwarového inženýrství FIT České vysoké učení technické v Praze c Michal Valenta, 2012 BI-DBS, ZS 2011/12

Jak používat statistiky položkové v systému WinShop Std.

Univerzita Pardubice Fakulta ekonomicko-správní. Analytické funkce Oracle. Josef Pirkl

Databázové systémy Cvičení 5.3

Kontingenční tabulky v MS Excel 2010

Inovace a zkvalitnění výuky prostřednictvím ICT. Základní seznámení s MySQL Ing. Kotásek Jaroslav

8.2 Používání a tvorba databází

Řazení řádků ve vzestupném pořadí (A až Z nebo 0 až 9) nebo sestupném pořadí (Z až A nebo 9 až 0)

DJ2 rekurze v SQL. slajdy k přednášce NDBI001. Jaroslav Pokorný

1. Umístěte kurzor do sloupce Datový typ na řádek s polem, ve kterém vytvořit chcete seznam.

Stored Procedures & Database Triggers, Tiskové sestavy v Oracle Reports

Řešení úloh z TSP MU SADY S 1

Excel tabulkový procesor

Jazyk SQL 2. Michal Valenta. Katedra softwarového inženýrství FIT České vysoké učení technické v Praze c M.Valenta, 2011 BI-DBS, ZS 2011/12

MySQL sežere vaše data

Informační systémy 2006/2007

Excel - pokračování. Př. Porovnání cestovních kanceláří ohraničení tabulky, úprava šířky sloupců, sestrojení grafu

Databázové systémy a SQL

Databáze I. Přednáška 4

Vkládání, aktualizace, mazání

KOMBINATORIKA (4.ročník I.pololetí DE, 2.ročník I.pololetí NS)

Copyright 2013 Martin Kaňka;

Databázové systémy Cvičení 5

Oborové číslo Hodnocení - část A Hodnocení - část B Hodnocení - část A+B

DATABÁZE MS ACCESS 2010

Microsoft Access. Typy objektů databáze: Vytvoření a návrh nové tabulky. Vytvoření tabulky v návrhovém zobrazení

Transkript:

UNICORN COLLEGE Katedra informačních technologií BAKALÁŘSKÁ PRÁCE Pokročilé dotazování v databázích Oracle pomocí analytických funkcí Michael Remiš Ing. Miroslav Žďárský 2013, Praha

Čestné prohlášení Prohlašuji, že jsem svou bakalářskou práci na téma Pokročilé dotazování v databázích Oracle pomocí analytických funkcí vypracoval samostatně pod vedením vedoucího bakalářské práce a s použitím výhradně odborné literatury a dalších informačních zdrojů, které jsou v práci citovány a jsou také uvedeny v seznamu literatury a použitých zdrojů. Jako autor této bakalářské práce dále prohlašuji, že v souvislosti s jejím vytvořením jsem neporušil autorská práva třetích osob a jsem si plně vědom následků porušení ustanovení 11 a následujících autorského zákona č. 121/2000 Sb. V. dne... (Michael Remiš)

Poděkování Děkuji vedoucímu bakalářské práce Ing. Miroslavu Žďárskému za účinnou metodickou, pedagogickou a odbornou pomoc a další cenné rady při zpracování mé bakalářské práce.

Pokročilé dotazování v databázích Oracle pomocí analytických funkcí Advanced SQL queries with analytic functions in Oracle - 5 -

Abstrakt Analytické funkce jsou rozšířením jazyka SQL, které nám umožňují vyřešit složitá zadání dotazů jednoduchým zápisem namísto komplikovaného skládání SQL dotazů či procedurálního řešení. V rámci tohoto tématu bude popsáno, jak jsou analytické funkce řešeny, jejich pohled na data a využití jednotlivých funkcí v různých případech spolu s ukázkami. Cílem práce by měl být vznik tutoriálu, který člověku se znalostí SQL rozšíří znalosti i o tuto oblast. Klíčová slova: analytické funkce, reportování, optimalizace, SQL Abstract Analytic functions are SQL extension that allows developers to solve difficult task using simple SQL query instead of complicated constructions or usage of procedural language. This text contains the description of basic principles of analytic functions, description of how they work with data and usage of analytic functions in different situations with simple examples. The goal of this work is to create tutorial that can help anyone with basic knowledge of SQL to understand this topic. Key words: analytic functions, reporting, optimization, SQL - 6 -

1 Obsah 1 Obsah... - 7-2 Úvod... - 9-2.1 Analytické funkce... - 9-2.2 Výhody analytických funkcí... - 11-2.3 Základní terminologie... - 11-2.3.1 Zpracování SQL dotazu... - 11-2.3.2 Základy analytických dotazů... - 13-2.3.3 Oblasti (partitions)... - 16-2.3.4 Řazení oblasti (ORDER BY)... - 18-2.3.5 Okna (windows)... - 20-2.3.6 Zpracování SQL dotazu s analytickou funkcí... - 25-3 Přehled analytických funkcí... - 26-3.1 Ranking family... - 26-3.1.1 ROW_NUMBER, RANK, DENSE_RANK... - 26-3.1.2 PERCENT_RANK... - 27-3.1.3 CUME_DIST... - 28-3.2 Window aggregate family... - 29-3.2.1 AVG, SUM, MIN, MAX, COUNT... - 29-3.2.2 RATIO_TO_REPORT... - 31-3.3 LEAD/LAG family... - 31-3.3.1 LEAD, LAG... - 31-3.4 FIRST/LAST family... - 33-3.4.1 FIRST, LAST... - 33-3.4.2 FIRST_VALUE, LAST_VALUE... - 34-3.4.3 NTH_VALUE... - 36-3.5 Statistické funkce... - 38-3.5.1 NTILE... - 38-3.5.2 PERCENTILE_CONT, PERCENTILE_DISC... - 39-3.5.3 VARIANCE, VAR_SAMP, VAR_POP... - 40-3.5.4 STDDEV, STDDEV_SAMP, STDDEV_POP... - 41-3.6 Další funkce... - 42-3.6.1 LISTAGG... - 42 - - 7 -

4 Rozdíly mezi dotazy s analytickou funkcí a bez... - 45-4.1 AVG... - 45-4.2 Nevhodné použití analytické funkce... - 48-5 Závěr... - 50-6 Seznam použité literatury... - 51-7 Seznam tabulek... - 52-8 Příloha 1: Instalace testovacích dat... - 53-8.1 Schéma HR... - 53-8.2 Testovací tabulka EMPLOYEES_TEST... - 53 - - 8 -

2 Úvod Cílem této práce je vytvořit přehled nejpoužívanějších analytických funkcí v prostředí Oracle a vysvětlit jejich základy. Text předpokládá čtenářovu základní znalost SQL a je určen především začátečníkům v oblasti analytických dotazů, ale i těm, kteří si chtějí své znalosti rozšířit, případně hledají příručku, návod či příklad. V první části této práce je popsán základní princip analytických funkcí a jejich výhody. V druhé části jsou pak jednotlivé funkce detailně vysvětleny. Následuje soubor příkladů, kde jsou analytické funkce porovnány s jejich protějšky bez použití analytických funkcí. Součástí instalace RDBMS Oracle je schéma HR, které obsahuje několik ukázkových tabulek i s daty. Většina příkladů SQL dotazů je právě nad tabulkami (zejména tabulka EMPLOYEES) z tohoto schématu. V tomto textu uvádím strukturu tabulky vždy při jejím prvním použití. Text obsahuje řadu příkladů konkrétních SQL dotazů spolu s výpisem vrácených řádků. Ve výsledcích dotazů je vždy uvedeno zpravidla jen prvních deset záznamů, ačkoliv příslušný SQL dotaz pro názornost takové omezení neobsahuje. 2.1 Analytické funkce I přesto, že podstatou jazyka SQL je jednoduchost a co největší podoba s běžným jazykem (angličtinou) (1), poskytuje obrovské možnosti při dotazování v relačních databázích. Jednoduché dotazy mají přímočarou konstrukci. Například seznam všech zaměstnanců z tabulky ZAMESTNANCI získáme dotazem: * FROM ZAMESTNACI; Jazyk SQL nám ale umožňuje pokládat daleko složitější dotazy. Pokud budeme chtít u zaměstnanců zobrazit i průměrný plat v jeho oddělení a rozdíl proti tomuto průměru, dotaz bude sice mírně složitější, ale stále bude poměrně přímočarý. Zajímá-li nás seznam všech zaměstnanců ve společnosti seřazený podle jejich platu navíc ještě s informací o rozdílu proti předchozímu zaměstnanci, dostáváme se do situace, kterou stále půjde řešit dotazem SQL, nicméně jeho zápis bude nečitelný a složitý. Databázový server Oracle 8.1.6. (2) v sobě poprvé obsahoval skupinu funkcí, které nám v podobných případech pomohou. Jedná se o sadu analytických funkcí (anglicky - 9 -

analytical functions). Tyto funkce jsou někdy označovány jako windowing nebo reporting functions (2). Analytické funkce (AF) jsou podobné agregačním funkcím, které vracejí vždy jednu hodnotu pro právě definovanou skupinu záznamů. Mějme tabulku EMPLOYEES, která obsahuje informace o zaměstnancích (tabulka ze schématu HR). DESCRIBE EMPLOYEES; NAME NULL TYPE -------------- -------- ------------ EMPLOYEE_ID NOT NULL NUMBER(6) FIRST_NAME VARCHAR2(20) LAST_NAME NOT NULL VARCHAR2(25) EMAIL NOT NULL VARCHAR2(25) PHONE_NUMBER VARCHAR2(20) HIRE_DATE NOT NULL DATE JOB_ID NOT NULL VARCHAR2(10) SALARY NUMBER(8,2) COMMISSION_PCT NUMBER(2,2) MANAGER_ID NUMBER(6) DEPARTMENT_ID NUMBER(4) Pro zjištění průměrného platu podle oddělení (DEPARTMENT_ID) nám postačí jednoduchá agregační funkce AVG: DEPARTMENT_ID, AVG(SALARY) GROUP BY DEPARTMENT_ID; Agregační funkce nám seznam zaměstnanců rozdělila na skupiny podle oddělení, ve kterém zaměstnanec pracuje a pro každé oddělení spočítala aritmetický průměr. Analytické funkce se liší v tom, že vytvářejí skupinu pro každý řádek (1). Tato skupina se označuje jak oblast (angl. partition). Pokud dotaz obsahuje více analytických funkcí, bude sestaveno i více oblastí 1 pro jeden řádek. To je rozdíl oproti použití GROUP BY, kde je pouze jedna oblast 2. I to je důvod, proč mnoho agregačních funkcí má svůj analytický protějšek. Funkce jsou totiž v mnohém podobné (1). V případě GROUP BY je možné nad oblastí volat několik funkcí (zajímá nás např. průměrný a maximální plat v jednotlivých odděleních). 1 Oblast můžeme dále členit použitím oken. Pak může funkce v rámci oblasti vracet různé hodnoty pro různé řádky. Takovou hodnotou je např. kumulovaný součet. Podrobně viz kapitola 2.3.5. 2 GROUP BY může obsahovat více sloupců, neznamená to ale, že je sestaveno více oblastí. Více sloupců v klauzuli GROUP BY znamená jemnější dělení do oblastí. Např. GROUP BY DEPARTMENT_ID vytvoří oblasti zaměstnanců ve stejném oddělení, kdežto GROUP BY DEPARTMENT_ID, JOB_ID vytvoří oblasti zaměstnanců se stejným oddělením a na stejné pracovní pozici. - 10 -

Analytické funkce rozšiřují možnosti Business Inteligence a poskytují výkonný nástroj pro analýzu dat, která hraje důležitou roli při obchodním rozhodování. Důležitosti datové analýzy si Oracle byl vždy vědom a již od verze Oracle8i Release 1 přináší podporu pro dotazy CUBE a ROLLUP, které jsou rozšířením konstrukce GROUP BY a poskytuje tak poměrně silný reportovací nástroj. Postupně pak přidává další analytické a agregační funkce(3). 2.2 Výhody analytických funkcí Vedle významu pro Business Inteligence mají analytické funkce význam i pro samotné vývojáře. Složité konstrukce lze velmi snadno přepsat na jednoduché dotazy. Jednak dochází ke zvýšení produktivity, neboť analytické funkce nabízejí jednodušší řešení složitých dotazů. V druhé řadě jsou pak dotazy více čitelné, což usnadňuje spolupráci. Vývojáři tak nejsou nuceni doplňovat dotazy o komentáře a mohou se soustředit na psaní samotného dotazu (3). V určitých situacích dokonce není ani možné úlohu řešit využitím prostého SQL a je nutné využít možností procedurálního zpracování. Použití analytických funkcí má rovněž dopad i na výkon. Tedy na rychlost zpracování dotazu a tedy i na celkovou rychlost či odezvu celého systému. V moderních databázových systémech dochází před vykonáním dotazu k řadě procesů, které mají za úkol optimalizovat výsledný prováděcí plán. Při použití analytických funkcí může databázový server lépe dotaz pochopit a lépe tak naplánovat jeho provedení. Složité dotazy obsahující mnoho spojování tabulek (JOIN), poddotazů či volání procedur jsou nahrazeny mnohem výkonnějším dotazem (3). Analytické funkce jsou ale vhodné jen v určitých situacích a samotné použití analytické funkce nemusí vést ke zvýšení výkonu. Naopak špatné použití analytické funkce může systém výrazně zpomalit (viz kapitola 4.2). 2.3 Základní terminologie V následující kapitole jsou nejprve popsány základní principy zpracování jednoduchého SQL dotazu. Dále je popsán syntax a konstrukty analytických funkcí. 2.3.1 Zpracování SQL dotazu Pro pochopení analytických funkcí je důležité nejdříve znát způsob, jakým je každý SQL dotaz zpracován. Mějme jednoduchý dotaz do tabulky EMPLOYEES: - 11 -

EMPLOYEE_ID, LOWER(FIRST_NAME) AS NAME ; Server dotaz zpracuje a vrátí výslednou množinu řádku. Ve výsledné množině budou všechny řádky z tabulky a bude obsahovat dva sloupce EMPLOYEE_ID a NAME. Výsledný dotaz můžeme seřadit nejen podle libovolného sloupce v tabulce (tedy nejen podle vybraných), ale i podle sloupce NAME, který obsahuje návratovou hodnotu funkce LOWER. Z toho plyne, že nejdříve je spočítána hodnota funkce LOWER pro všechny řádky a až po té je výsledná množina seřazena. Pokud však budeme chtít výslednou množinu omezit a vybrat pouze některé řádky použijeme klauzuli WHERE: EMPLOYEE_ID, LOWER(FIRST_NAME) AS NAME WHERE NAME = 'ADAM' ORDER BY NAME; V tomto případě ale Oracle vrátí následující chybu: ORA-00904: "NAME": INVALID IDENTIFIER 00904. 00000 - "%S: INVALID IDENTIFIER" *CAUSE: *ACTION: ERROR AT LINE: 3 COLUMN: 7 Omezující podmínka WHERE se totiž odkazuje na sloupec NAME, který ale v době vykonávání podmínky ještě neexistuje. Nejdříve je totiž zpracována podmínka WHERE, poté je zpracována funkce LOWER a až na závěr je množina řádek seřazena podle sloupce NAME. Pokud bychom chtěli data filtrovat podle sloupce NAME, je nutné použít poddotaz: * FROM ( EMPLOYEE_ID, LOWER(FIRST_NAME) AS NAME ) WHERE NAME = 'adam'; Případně použít funkci LOWER znovu v klauzuli WHERE: EMPLOYEE_ID, LOWER(FIRST_NAME) AS NAME WHERE LOWER(FIRST_NAME) = 'adam'; Pokud k nějakému SQL dotazu přidáme seskupení GROUP BY, bude podmínka vyhodnocena před vykonáním seskupení. Dotaz WHERE - 12 -

DEPARTMENT_ID, AVG(SALARY) AS AVG WHERE SALARY > 5000 GROUP BY DEPARTMENT_ID; vrátí průměrné platy po odděleních s tím, že jsou započítáni pouze zaměstnanci s platem vyšším než 5000. Případné řazení ORDER BY by bylo vykonáno až po vykonání GROUP BY 3. Seskupené řádky je možné dále filtrovat pomocí klauzule HAVING. Zde ale není možné použít sloupec AVG 4. Následující dotaz je rozšířením předchozího. Výsledné řádky navíc seřadí podle sloupce AVG a vybere jen řádky s průměrem vyšším než 7000: DEPARTMENT_ID, AVG(SALARY) AS AVG WHERE SALARY > 5000 GROUP BY DEPARTMENT_ID HAVING AVG(SALARY) > 7000 ORDER BY AVG; 2.3.2 Základy analytických dotazů Analytické dotazy jsou podobné agregačním dotazům. Liší se tím, že vracejí hodnotu pro každou skupinu záznamů (1). Skupina záznamů se nazývá oblast a je definována v analytické části dotazu. Každý řádek patří právě do jedné oblasti. Chceme-li z databáze získat report všech zaměstnanců firmy s nějakou informací týkající se určité veličiny v oddělení příslušného zaměstnance (např. průměrný plat) budou jednotlivé oblasti tvořit řádky se zaměstnanci daného oddělení. Syntaxe analytické funkce vypadá následovně (4): ANALYTICKÁ FUNKCE (ARGUMENTY) OVER (ANALYTICKÁ KLAUZULE) Všechny analytické funkce jsou vykonány až v závěru těsně před vykonáním řazení ORDER BY. Analytickým funkcím tedy předchází vykonání spojeni JOIN, seskupení GROUP BY a filtrování HAVING (4). Dále platí, že analytické dotazy je možné použít kdekoliv ve výčtu sloupců nebo v klauzuli GROUP BY. Pro pochopení jak fungují analytické funkce a oblasti použijeme jednoduchý příklad s hodnocením řádků podle kritéria (ranking, podrobně viz kapitola 3.1). 3 Je tedy možné řadit i podle sloupce AVG 4 Resp. není možné použít jeho alias, ale pouze jeho původní definici, tedy AVG (SALARY) - 13 -

K jednoduchému hodnocení řádku slouží pseudosloupec ROWNUM, který očísluje vrácené řádky. ROWNUM, FIRST_NAME, SALARY ; Výsledek dotazu je následující (uvedeno je pouze prvních 10 záznamů). Řádky jsou vráceny tak, jak jsou uloženy v datových souborech (to nemusí nutně odpovídat pořadí vkládání záznamů). ROWNUM FIRST_NAME LAST_NAME SALARY ---------- -------------------- ------------------------- ---------- 1 STEVEN KING 24000 2 NEENA KOCHHAR 17000 3 LEX DE HAAN 17000 4 ALEXANDER HUNOLD 9000 5 BRUCE ERNST 6000 6 DAVID AUSTIN 4800 7 VALLI PATABALLA 4800 8 DIANA LORENTZ 4200 9 NANCY GREENBERG 12008 10 DANIEL FAVIET 9000 Pokud bychom chtěli data seřadit podle platu, použijeme klauzuli ORDER BY: ROWNUM, FIRST_NAME, SALARY ORDER BY SALARY; ROWNUM FIRST_NAME LAST_NAME SALARY ---------- -------------------- ------------------------- ---------- 33 TJ OLSON 2100 29 STEVEN MARKLE 2200 37 HAZEL PHILTANKER 2200 28 JAMES LANDRY 2400 36 KI GEE 2400 20 KAREN COLMENARES 2500 32 JAMES MARLOW 2500 41 JOSHUA PATEL 2500 45 PETER VARGAS 2500 83 MARTHA SULLIVAN 2500 Opět je uvedeno pouze prvních 10 záznamů. Na výsledných záznamech je vidět, že ROWNUM je vykonáno dříve než ORDER BY. Sloupec ROWNUM by ale měl obsahovat pořadí - 14 -

zaměstnance ve skupině seřazené podle výše platu. Toho lze snadno docílit použitím poddotazu. ROWNUM, T.* FROM ( FIRST_NAME, SALARY ORDER BY SALARY ) T; ROWNUM FIRST_NAME LAST_NAME SALARY ---------- -------------------- ------------------------- ---------- 1 TJ OLSON 2100 2 STEVEN MARKLE 2200 3 HAZEL PHILTANKER 2200 4 JAMES LANDRY 2400 5 KI GEE 2400 6 KAREN COLMENARES 2500 7 JAMES MARLOW 2500 8 JOSHUA PATEL 2500 9 PETER VARGAS 2500 10 MARTHA SULLIVAN 2500 Zde přichází na řadu analytické funkce, neboť stejného výsledku dosáhneme, pokud použijeme analytickou funkci ROW_NUMBER (podrobně viz kapitola 3.1.1). ROW_NUMBER() OVER (ORDER BY SALARY), FIRST_NAME, SALARY ORDER BY SALARY; Již v tomto triviálním příkladě je vidět jednoduchost zápisu dotazu. Nejprve uvádíme název analytické funkce ROW_NUMBER, která nepřijímá žádné argumenty. Následuje klíčové slovo OVER a definice pořadí řádků v oblasti (ORDER BY SALARY). Nejdříve je proveden dotaz... a výsledná sada záznamů je předána funkci ROW_NUMBER. Tato sada záznamů je dále seřazena dle ORDER BY SALARY v analytické klauzuli. Funkce ROW_NUMER pak pro každý řádek vrací hodnotu s pořadím ve vytvořené skupině 5. 5 Zde se jedná o jednu velkou skupinu obsahující všechny řádky - 15 -

2.3.3 Oblasti (partitions) V praxi se často setkáváme s požadavkem reportu, který bude obsahovat všechny řádky ale s nějakou informací, která je společná pouze pro určitou skupinu řádek. Takovým reportem může být například seznam všech zaměstnanců společnosti spolu s průměrným platem v jeho oddělení. Chceme tedy dotaz, který vrátí následující sloupce (jejich význam je zřejmý) DEPARTMENT_ID, SALARY, DEP_AVG_SALARY. Dotaz, který vrátí požadovaný seznam, vypadá následovně: DEPARTMENT_ID DEP_ID, SALARY, AVG(SALARY) OVER (PARTITION BY DEPARTMENT_ID) DEP_AVG_SALARY ; LAST_NAME DEP_ID SALARY DEP_AVG_SALARY ------------------------- ---------- ---------- -------------- WHALEN 10 4400 4400 HARTSTEIN 20 13000 9500 FAY 20 6000 9500 RAPHAELY 30 11000 4150 KHOO 30 3100 4150 BAIDA 30 2900 4150 TOBIAS 30 2800 4150 HIMURO 30 2600 4150 COLMENARES 30 2500 4150 MAVRIS 40 6500 6500 Tento dotaz nám ilustruje, jak vznikají a jak se používají oblasti. Jednotlivé oblasti jsou naznačeny různým podbarvením řádku. Funkce AVG přijímá jako argument název sloupce, pro který se průměr počítá. Řádky jsou poté rozděleny do oblastí podle odpovídajícího oddělení. Oblast je definována pomocí klíčových slov PARTITION BY, která je součástí analytické klauzule. Funkce AVG pak vrací hodnotu v závislosti na tom, do které oblasti procházený řádek patří. Definice oblasti pomocí PARTITION BY je obdobné jako definování oblasti pomocí GROUP BY a může obsahovat více sloupců. Řekněme, že bychom chtěli znovu sledovat průměrné platy v odděleních, ale chtěli bychom zaměstnance odlišit i podle data nástupu. Pro lepší ilustraci jsou vybráni zaměstnanci z oddělení 30 a 60. - 16 -

DEPARTMENT_ID DEP_ID, TO_CHAR(HIRE_DATE, 'YYYY') YEAR, SALARY, AVG(SALARY) OVER (PARTITION BY DEPARTMENT_ID, TO_CHAR(HIRE_DATE, 'YYYY')) AVG_SALARY WHERE DEPARTMENT_ID IN (30, 60); Tento dotaz vrátí jméno, oddělení, rok 6, plat a průměrný plat v oddělení u zaměstnanců se stejným datem nástupu. V definici oblasti jsou použity dva sloupce oddělení a rok nástupu. Naznačeny jsou oblasti, které obsahují více než jeden řádek. Řádky v těchto oblastech mají různou hodnotu sloupce SALARY, ale obsahují stejnou hodnotu průměrného platu. Ostatní záznamy tvoří jednořádkovou oblast. LAST_NAME DEP_ID YEAR SALARY AVG_SALARY ------------------------- ---------- ---- ---------- ---------- RAPHAELY 30 2002 11000 11000 KHOO 30 2003 3100 3100 BAIDA 30 2005 2900 2850 TOBIAS 30 2005 2800 2850 HIMURO 30 2006 2600 2600 COLMENARES 30 2007 2500 2500 AUSTIN 60 2005 4800 4800 HUNOLD 60 2006 9000 6900 PATABALLA 60 2006 4800 6900 ERNST 60 2007 6000 5100 LORENTZ 60 2007 4200 5100 Vraťme se nyní k dotazu, který hodnotil řádky v seznamu podle platu ROW_NUMBER() OVER (ORDER BY SALARY), FIRST_NAME, SALARY ORDER BY SALARY; Zde definice oblasti zcela chybí. Pokud v dotazu není definice oblasti uvedena, je vytvořena oblast se všemi řádky. To je vhodné pokud chceme znát pořadí podle jiného sloupce, než podle kterého jsou řádky výsledně seřazeny. Takovým seznamem může být například seznam zaměstnanců seřazených podle jména a jeho pořadí ve firmě podle platu a pořadí ve firmě podle provize. 6 Rok je z data nástup získán pomocí funkce TO_CHAR. Stejná funkce je použita i v definici oblasti, neboť na sloupec YEAR se nelze odkázat, protože vzniká současně s výpočtem analytické funkce. - 17 -

FIRST_NAME, ROW_NUMBER() OVER (ORDER BY SALARY) SALARY_POS, ROW_NUMBER() OVER (ORDER BY COMMISSION_PCT) COMMISION_POS ORDER BY FIRST_NAME; V definici oblasti smí být nejen název sloupce ale i konstanta, volání neanalytické funkce nebo funkční výraz 7 (4). Volání neanalytické funkce v PARTITION BY klauzuli jsme použili v dotazu, který vracel průměrné platy zaměstnanců podle oddělení a roku nástupu. 2.3.4 Řazení oblasti (ORDER BY) Oblast vytvořená v rámci analytické funkce může být dále seřazena. To je užitečné zejména u různých žebříčků (rankings, viz kapitola 3.1). K ilustraci opět využijeme tabulku zaměstnanců. Budeme chtít znát jejich pořadí v oddělení podle výše platu. K tomu využijeme funkci ROW_NUMBER, která nám k seřazeným záznamům vrátí pořadí. Seřazení zajistíme klíčovými slovy ORDER BY v analytické klauzuli a uvedením sloupců, podle nichž se má řadit. V našem případě je to sloupec SALARY. Jednotlivé oblasti jsou pro názornost vyznačeny různým podbarvením. DEPARTMENT_ID DEP_ID, SALARY, ROW_NUMBER() OVER (PARTITION BY DEPARTMENT_ID ORDER BY SALARY) RANK ; 7 Funkční výraz je například součet sloupců apod. - 18 -

LAST_NAME DEP_ID SALARY RANK ------------------------- ---------- ---------- ---------- WHALEN 10 4400 1 FAY 20 6000 1 HARTSTEIN 20 13000 2 COLMENARES 30 2500 1 HIMURO 30 2600 2 TOBIAS 30 2800 3 BAIDA 30 2900 4 KHOO 30 3100 5 RAPHAELY 30 11000 6 MAVRIS 40 6500 1 OLSON 50 2100 1 PHILTANKER 50 2200 2 MARKLE 50 2200 3 Pro potvrzení výše uvedeného výsledku (prvních 10 záznamů) zobrazíme zaměstnance z oddělení 30 seřazené podle výše platu. SALARY WHERE DEPARTMENT_ID=30 ORDER BY SALARY; LAST_NAME SALARY ------------------------- ---------- COLMENARES 2500 HIMURO 2600 TOBIAS 2800 BAIDA 2900 KHOO 3100 RAPHAELY 11000 Když se na výsledek dotazu podíváme podrobněji, zjistíme, že funkce ROW_NUMBER() ohodnotila zaměstnance Philtanker a Markle z oddělení 50 různou hodnotu ačkoliv mají stejný plat a patří do stejného oddělení. To je vlastnost funkce ROW_NUMBER. Další možnosti hodnocení řádků jsou uvedeny v kapitole 3.1. V našem případě je zaměstnanec Philtanker před Marklem protože jej Oracle načetl jako první z datového souboru. Řekněme ale, že v našem případě hraje při hodnocení řádku roli i například datum nástupu zaměstnance. Čím později zaměstnanec nastoupil, tím bychom ho chtěli lépe 8 hodnotit. Definice řazení sloupců může obsahovat více sloupců a umožňuje nám vyřešit 8 Neboli posunout jej v žebříčku výše a zvýšit jeho skóre (snížit číselné vyjádření jeho pozice) - 19 -

situace, kdy jsou řádky hodnoceny stejně. K ORDER BY SALARY přidáme ještě sloupec HIRE_DATE. Tímto způsobem můžeme zajistit jedinečné a deterministické seřazení oblasti 9. DEPARTMENT_ID DEP_ID, SALARY, HIRE_DATE, ROW_NUMBER() OVER (PARTITION BY DEPARTMENT_ID ORDER BY SALARY, HIRE_DATE DESC) RANK ; LAST_NAME DEP_ID SALARY HIRE_DATE RANK ------------------------- ---------- ---------- --------- ---------- WHALEN 10 4400 17-SEP-03 1 FAY 20 6000 17-AUG-05 1 HARTSTEIN 20 13000 17-FEB-04 2 COLMENARES 30 2500 10-AUG-07 1 HIMURO 30 2600 15-NOV-06 2 TOBIAS 30 2800 24-JUL-05 3 BAIDA 30 2900 24-DEC-05 4 KHOO 30 3100 18-MAY-03 5 RAPHAELY 30 11000 07-DEC-02 6 MAVRIS 40 6500 07-JUN-02 1 OLSON 50 2100 10-APR-07 1 MARKLE 50 2200 08-MAR-08 2 PHILTANKER 50 2200 06-FEB-08 3 2.3.5 Okna (windows) V předchozích příkladech byla vždy vytvořena oblast a analytická funkce měla na svém vstupu všechny řádky spadající do příslušné oblasti. Například pro průměrný plat v oddělení byla vytvořena oblast pro každé oddělení. Všichni zaměstnanci z tohoto oddělení byli započítáni do průměrného platu oddělení. V určitých případech by nás z oblasti mohla zajímat jen její část. Takovým příkladem je třeba klouzavý aritmetický průměr. Požadavek je sestavit seznam zaměstnanců a jejich klouzavý průměr o délce 3 (samozřejmě v rámci oddělení). Jinými slovy chceme sestavit oblast podle oddělení, seřazenou podle platu a vyjmout z ní ke každé řádce pouze předchozí a následující záznam. K tomu slouží okna (windows). 9 Seřazení je deterministické za předpokladu, že neexistují dva zaměstnanci, kteří nastoupili ve stejný den a mají stejný plat. Jedná se o takový případ, kdy je pořadí řádků na výstupu jednoznačně dáno pouze a jen pořadím definovaným pomocí sloupců v ORDER BY klauzuli a neovlivní jej žádné jiné další faktory. - 20 -

Okno se definuje v analytické klauzuli za ORDER BY a je možné použít dva typy oken. Prvním typem je okno definované pomocí počtu řádek. Klíčovým slovem je pak ROWS. Definovat lze začátek a konec relativně vůči procházené řádce. Jednotkou je zde počet řádků. Například tři řádky před a tři řádky po, šest řádek před a dvě řádky před, jedna řádka po a 3 řádky po. Okno tedy nutně nemusí začínat před aktuální řádkou a končit za. Následující příklad ukazuje výpočet klouzavého průměru v rámci oddělení o délce 3 a 5. V prvním výsledku je ohraničením naznačena oblast pro oddělení 30 a v ní různým podbarvením okna pro výpočet klouzavého průměru o délce 3 (sloupec AVG_3) pro zaměstnance Himuro a pro zaměstnance Khoo (tyto okna se nepřekrývají). V dotazu se ptáme na jeden řádek před a na jeden řádek po (ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING). Pro zaměstnance Himuro byl počítán klouzavý průměr z platu zaměstnanců Colmenares a Tobias, kteří se nacházejí na řádce před Himuro, resp. na řádce po. DEPARTMENT_ID, SALARY, AVG(SALARY) OVER (PARTITION BY DEPARTMENT_ID ORDER BY SALARY ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) AVG_3, AVG(SALARY) OVER (PARTITION BY DEPARTMENT_ID ORDER BY SALARY ROWS BETWEEN 2 PRECEDING AND 2 FOLLOWING) AVG_5 ORDER BY DEPARTMENT_ID, SALARY; LAST_NAME DEPARTMENT_ID SALARY AVG_3 AVG_5 ------------------------- ------------- ---------- ------ ------ WHALEN 10 4400 4400 4400 FAY 20 6000 9500 9500 HARTSTEIN 20 13000 9500 9500 COLMENARES 30 2500 2550 2633 HIMURO 30 2600 2633 2700 TOBIAS 30 2800 2767 2780 BAIDA 30 2900 2933 4480 KHOO 30 3100 5667 4950 RAPHAELY 30 11000 7050 5667 MAVRIS 40 6500 6500 6500 Okno, které bylo sestaveno pro výpočet klouzavého průměru o délce 5 (sloupec AVG_5) např. pro zaměstnance Baida, by vypadalo následovně (naznačena je oblast pro oddělení 30 a okno pro zaměstnance Baida). Pomocí ROWS BETWEEN 2 PRECEDING AND 2 FOLLOWING říkáme, že do výpočtu klouzavého průměru vstupují 2 řádky před a dva řádky - 21 -

po aktuální řádce. Pro zaměstnance Baida jsou to tedy řádky s platy zaměstnanců Himuro, Tobias (dva řádky před). A dále řádky s platy zaměstnanců Khoo a Raphaely. LAST_NAME DEPARTMENT_ID SALARY AVG_3 AVG_5 ------------------------- ------------- ---------- ------ ------ WHALEN 10 4400 4400 4400 FAY 20 6000 9500 9500 HARTSTEIN 20 13000 9500 9500 COLMENARES 30 2500 2550 2633 HIMURO 30 2600 2633 2700 TOBIAS 30 2800 2767 2780 BAIDA 30 2900 2933 4480 KHOO 30 3100 5667 4950 RAPHAELY 30 11000 7050 5667 MAVRIS 40 6500 6500 6500 Důležité je, že pomocí klíčového slova ROWS vybíráme předcházející či následující řádky na základě jejich počtu bez ohledu na hodnoty v těchto řádcích. Druhým typem je okno definované na základě hodnot v řádku. Na rozdíl od předchozího způsobu bude počet řádek proměnlivý a bude záviset na hodnotách v řádcích. Klíčové slovo zde je RANGE. Uvedený způsob bychom mohli využít například, pokud bychom chtěli (v rámci oddělení) znát u každého zaměstnance počet zaměstnanců, kteří mají podobný plat (řekněme ±200+). Výsledek analytické funkce je zde ještě upraven o -1- neboť vždy zahrnuje i aktuální řádek, který je nutné odečíst. DEPARTMENT_ID, SALARY, COUNT(*) OVER (PARTITION BY DEPARTMENT_ID ORDER BY SALARY RANGE BETWEEN 200 PRECEDING AND 200 FOLLOWING) - 1 COUNT ORDER BY DEPARTMENT_ID, SALARY; - 22 -

LAST_NAME DEPARTMENT_ID SALARY COUNT ------------------------- ------------- ---------- ---------- WHALEN 10 4400 0 FAY 20 6000 0 HARTSTEIN 20 13000 0 COLMENARES 30 2500 1 HIMURO 30 2600 2 TOBIAS 30 2800 2 BAIDA 30 2900 2 KHOO 30 3100 1 RAPHAELY 30 11000 0 MAVRIS 40 6500 0 Např. pro zaměstnance Tobias jsou do počtu zahrnuty řádky, které mají plat vyšší nebo roven 2800 200 = 2600 a nižší nebo roven 2800 + 100 = 3000 (tedy zaměstnanci Himuro a Baida). Řádky, které vstoupí do výpočtu, byly v tomto případě vybrány na základě hodnoty ve sloupci SALARY, nikoliv na základě přesně stanoveného počtu řádků. Syntaxe okna je následující (4): [RANGE ROWS] BETWEEN <START> AND <END> RANGE či ROWS definuje typ okna. Následuje část BETWEEN <START> AND <END>, která nastavuje začátek a konec oblasti. Část BETWEEN <START> AND může být vynechána, <END> poté bude začátek okna a koncem okna bude aktuální řádka 10. <START> a <END> mohou nabývat hodnot UNBOUNDED [PRECEDING FOLLOWING], nebo CURRENT ROW NEBO VÝRAZ [PRECEDING FOLLOWING]. Hodnoty START a END (jak bylo vidět v předchozím příkladě), jsou hodnoty, které budou přičteny k hodnotě v požadovaném sloupci pro každý procházený řádek (nikoliv absolutní hodnoty). Následující příklad obsahuje dotaz, který vrací přehled zaměstnanců, kde je ke každému zaměstnanci zobrazen počet zaměstnanců v oddělení, kteří mají více než dvojnásobný plat. Sloupec SALARY*2 obsahuje hodnotu dvojnásobku platu a LAST_NAME_2 obsahuje jméno prvního takového zaměstnance (v seznamu zaměstnanců seřazeném podle oddělení a platu). Pro názornost byli vybráni pouze zaměstnanci z oddělení 50. 10 Jinými slovy, pokud uvedeme jen jednu mez a vynecháme BETWEEN, bude tato mez chápána jako začátek okna a jako dolní mez se bere aktuální řádka. - 23 -

DEPARTMENT_ID, SALARY, SALARY*2, FIRST_VALUE(LAST_NAME) OVER (PARTITION BY DEPARTMENT_ID ORDER BY SALARY ASC RANGE BETWEEN SALARY FOLLOWING AND UNBOUNDED FOLLOWING) LAST_NAME_2, COUNT(*) OVER (PARTITION BY DEPARTMENT_ID ORDER BY SALARY ASC RANGE BETWEEN SALARY FOLLOWING AND UNBOUNDED FOLLOWING) COUNT WHERE DEPARTMENT_ID=50; ORDER BY DEPARTMENT_ID, SALARY ASC; LAST_NAME DEPARTMENT_ID SALARY SALARY*2 LAST_NAME_2 COUNT ----------- ------------- ---------- ---------- ----------- ---------- OLSON 50 2100 4200 SARCHAND 6 MARKLE 50 2200 4400 MOURGOS 5 PHILTANKER 50 2200 4400 MOURGOS 5... BULL 50 4100 8200 FRIPP 1 SARCHAND 50 4200 8400 0 MOURGOS 50 5800 11600 0 VOLLMAN 50 6500 13000 0 KAUFLING 50 7900 15800 0 WEISS 50 8000 16000 0 FRIPP 50 8200 16400 0 Například dvojnásobek platu zaměstnance Olsona je 4200. Tento či vyšší plat má ještě šest dalších zaměstnanců počínaje zaměstnance Sarchandem. Dvojnásobek platu zaměstnance Bulla je 8200. Takový plat má pouze zaměstnance Fripp. Definice okna může být i úplně vynechána, vznikne pak výchozí okno od první řádky až po aktuální řádku. Funkce AVG (viz 3.2.1) vrací aritmetický průměr, ne vždy ale musí být výsledek dle očekávání. DEPARTMENT_ID, SALARY, HIRE_DATE, AVG(SALARY) OVER (PARTITION BY DEPARTMENT_ID) AVG1, AVG(SALARY) OVER (PARTITION BY DEPARTMENT_ID ORDER BY HIRE_DATE) AVG2 ORDER BY DEPARTMENT_ID, HIRE_DATE; - 24 -

LAST_NAME DEPARTMENT_ID SALARY HIRE_DATE AVG1 AVG2 ----------- ------------- ---------- --------- ---------- ---------- WHALEN 10 4400 17-SEP-03 4400.00 4400.00 HARTSTEIN 20 13000 17-FEB-04 9500.00 13000.00 FAY 20 6000 17-AUG-05 9500.00 9500.00 RAPHAELY 30 11000 07-DEC-02 4150.00 11000.00 KHOO 30 3100 18-MAY-03 4150.00 7050.00 TOBIAS 30 2800 24-JUL-05 4150.00 5633.33 BAIDA 30 2900 24-DEC-05 4150.00 4950.00 HIMURO 30 2600 15-NOV-06 4150.00 4480.00 COLMENARES 30 2500 10-AUG-07 4150.00 4150.00 MAVRIS 40 6500 07-JUN-02 6500.00 6500.00 Sloupec AVG1 obsahuje hodnotu aritmetického průměru v oddělení. Ačkoliv se může zdát, že aritmetický průměr nad neseřazenými a seřazenými záznamy v oblasti (oddělní) bude stejný, není tomu tak. Sloupec AVG2 totiž vrací hodnotu, kterou bychom mohli nazvat kumulativní průměr, neboli průměr hodnot až po aktuální řádku v rámci oddělení, kde jsou hodnoty seřazeny podle sloupce HIRE_DATE. Oracle totiž při uvedení ORDER BY klauzule vytvoří výchozí okno od první řádky až po aktuální řádku. Z použití okna plyne několik omezení pro analytickou klauzuli. Pokud vytváříme okno, je nutné definovat řazení oblasti pomocí ORDER BY. Na řazení jsou pak kladeny ještě další požadavky, pokud je použit typ RANGE. Za předpokladu že je použit typ RANGE a <START> či <END> obsahuje výraz, musí být oblast řazena pouze podle jednoho sloupce. 2.3.6 Zpracování SQL dotazu s analytickou funkcí V případě, že SQL dotaz obsahuje volání analytické funkce, je tato funkce zpracována těsně před vykonáním řazení GROUP BY. Pořadí tedy je: výběr sloupců, omezení WHERE, seskupení GROUP BY, omezení HAVING, volání analytické funkce (a sestavení oblasti pro tuto funkci), řazení ORDER BY (2). - 25 -

3 Přehled analytických funkcí 3.1 Ranking family Tyto funkce jsou využívány k hodnocení řádků a k určení jejich pořadí v rámci seřazené množiny záznamů. 3.1.1 ROW_NUMBER, RANK, DENSE_RANK Tyto funkce jsou si velmi podobné. Všechny tyto funkce určují pořadí řádku v oblasti seřazené dle libovolného sloupce (popř. sloupců). Liší se tím, jak postupují v případě, že se v oblasti nacházejí řádky se stejným hodnocením. Následující příklad ukazuje použití těchto funkcí. Hodnotíme zaměstnance v celé společnosti podle platu 11. DEPARTMENT_ID AS DEP_ID, SALARY, ROW_NUMBER() OVER(ORDER BY SALARY) ROW_NUMBER, RANK() OVER (ORDER BY SALARY) RANK, DENSE_RANK() OVER (ORDER BY SALARY) DENSE_RANK ; LAST_NAME DEP_ID SALARY ROW_NUMBER RANK DENSE_RANK ----------- ---------- ---------- ---------- ---------- ---------- OLSON 50 2100 1 1 1 MARKLE 50 2200 2 2 2 PHILTANKER 50 2200 3 2 2 LANDRY 50 2400 4 4 3 GEE 50 2400 5 4 3 COLMENARES 30 2500 6 6 4 MARLOW 50 2500 7 6 4 PATEL 50 2500 8 6 4 VARGAS 50 2500 9 6 4 SULLIVAN 50 2500 10 6 4 Z uvedeného výsledku je rozdíl mezi funkcemi patrný. ROW_NUMBER přiřadí každé řádce unikátní pořadové číslo. Tzn., že pokud mají řádky stejné hodnocení, funkce jim i tak 11 Příklad zároveň ukazuje situaci, kdy je vynechána část PARTITION BY. Při zpracování tak vzniká pouze jediná oblast, která zahrnuje všechny řádky. - 26 -

přiřadí různou hodnotu. Funkce při shodě hodnocení přiřazuje hodnotu v závislosti na uložení řádku v datovém souboru 12. Naproti tomu funkce RANK stejně hodnoceným řádkům přiřadí stejnou hodnotu. Řádek následující po skupině se stejným hodnocením, je ale ohodnocen tak, že v řadě jsou vynechány hodnoty podle velikosti skupiny se stejným hodnocením a řada tak není spojitá. Zaměstnanci s platem 2200 jsou hodnoceni číslem 2, následující řádky pak začínají číslem 4 (číslo tři bylo vynecháno). Funkce DENSE_RANK je podobná funkci RANK, ale udržuje řadu spojitou. Po zaměstnancích s platem 2200 s hodnocením 2 následují řádky s hodnocením 3. Vzniká tak spojitá řada bez mezer. 3.1.2 PERCENT_RANK Funkce PERCENT_RANK stanovuje pořadí vyjádřené pomocí procentuální hodnoty. Funkce nabývá hodnot od nuly do jedné, přičemž první řádek v oblasti má hodnotu 0 a poslední 1. Hodnocení je založené na hodnotě funkce RANK a její definice vypadá následovně (2): PERCENT_RANK = (RANK 1) / (COUNT 1) Pro ilustraci chceme opět hodnotit zaměstnance v celé společnosti podle platu. Příklad ukazuje výpočet funkce RANK, PERCENT_RANK a ruční výpočet PERCENT_RANK (sloupec PR1) pomocí hodnoty RANK a COUNT podle výše uvedeného vzorce (sloupec PR2) 13. DEPARTMENT_ID AS DEP_ID, SALARY, RANK() OVER (ORDER BY SALARY) RANK, PERCENT_RANK() OVER (ORDER BY SALARY) PR1, (RANK() OVER (ORDER BY SALARY) - 1)/(COUNT(LAST_NAME) OVER() - 1) PR2 ; 12 Uložení v datovém souboru není v čase konstantní a funkce tak může být nedeterministická a může pro stejně hodnocené řádky vracet různá pořadí. Je tedy vhodné použít více sloupců v ORDER BY, aby řazení bylo unikátní. 13 Hodnoty ve sloupcích PR1 a PR2 jsou zaokrouhleny na 4 desetinná místa - 27 -

LAST_NAME DEP_ID SALARY RANK PR1 PR2 ----------- ------ ------ ---- -------- -------- OLSON 50 2100 1.0000.0000 MARKLE 50 2200 2.0094.0094 PHILTANKER 50 2200 2.0094.0094 LANDRY 50 2400 4.0283.0283 GEE 50 2400 4.0283.0283 COLMENARES 30 2500 6.0472.0472 MARLOW 50 2500 6.0472.0472 PATEL 50 2500 6.0472.0472 VARGAS 50 2500 6.0472.0472 SULLIVAN 50 2500 6.0472.0472 3.1.3 CUME_DIST Funkce CUME_DIST počítá komutativní distribuční funkci, ale pro řádky se stejným hodnocením vrací funkce stejnou hodnotu. Jedná se tedy o hodnotu R/N, kde R je počet řádku se stejným či nižším hodnocením a N je celkový počet řádků (5). DEPARTMENT_ID AS DEP_ID, SALARY, CUME_DIST() OVER (ORDER BY SALARY) CUME_DIST ; LAST_NAME DEP_ID SALARY CUME_DIST ------------------------- ---------- ---------- --------- OLSON 50 2100.0093 MARKLE 50 2200.0280 PHILTANKER 50 2200.0280 LANDRY 50 2400.0467 GEE 50 2400.0467 COLMENARES 30 2500.1028 MARLOW 50 2500.1028 PATEL 50 2500.1028 VARGAS 50 2500.1028 SULLIVAN 50 2500.1028 Hodnota funkce CUME_DIST se dá spočítat ručně pomocí hodnot ROW_NUMBER, RANK a pomocí vnořeného dotazu. Nejprve si spočteme hodnoty RANK a ROW_NUMBER. Výsledek dotazu použijeme ve vnějším dotazu. Řádky rozdělíme do oblastí podle hodnoty RANK a z oblasti vybereme maximální hodnotu sloupce ROW_NUMBER, neboli určíme počet řádků se stejným či nižším hodnocením (to je pro řádky se stejným hodnocením stejné). Získanou hodnotu stačí vydělit celkovým počtem řádků a získáme hodnotu CUME_DIST. - 28 -

T.*, MAX(RN) OVER(PARTITION BY RANK) / COUNT(*) OVER() CD2 FROM ( SALARY, RANK() OVER (ORDER BY SALARY) RANK, ROW_NUMBER() OVER (ORDER BY SALARY) RN, CUME_DIST() OVER (ORDER BY SALARY) CD1 ) T; LAST_NAME SALARY RANK RN CD1 CD2 ----------- ------ ---- ---- -------- -------- OLSON 2100 1 1.0093.0093 PHILTANKER 2200 2 3.0280.0280 MARKLE 2200 2 2.0280.0280 GEE 2400 4 5.0467.0467 LANDRY 2400 4 4.0467.0467 SULLIVAN 2500 6 10.1028.1028 VARGAS 2500 6 9.1028.1028 PATEL 2500 6 8.1028.1028 MARLOW 2500 6 7.1028.1028 PERKINS 2500 6 11.1028.1028 3.2 Window aggregate family 3.2.1 AVG, SUM, MIN, MAX, COUNT Význam těchto funkcí je naprosto zřejmý. AVG počítá průměrnou hodnotu, SUM součet, MAX vrací nejvyšší hodnotu, MIN vrací nejnižší hodnotu a COUNT vrací počet hodnot. Následující příklad počítá výše uvedené veličiny pro hodnotu SALARY. Hodnoty funkcí jsou počítány v rámci oddělení. SALARY, DEPARTMENT_ID AS DEP_ID, AVG(SALARY) OVER(PARTITION BY DEPARTMENT_ID) AVG, MAX(SALARY) OVER(PARTITION BY DEPARTMENT_ID) MAX, MIN(SALARY) OVER(PARTITION BY DEPARTMENT_ID) MIN, COUNT(SALARY) OVER(PARTITION BY DEPARTMENT_ID) COUNT, SUM(SALARY) OVER(PARTITION BY DEPARTMENT_ID) SUM ; - 29 -

LAST_NAME SALARY DEP_ID AVG MAX MIN COUNT SUM ----------- ------ ------ ---------- ------- ------- ----- ------- WHALEN 4400 10 4400.00 4400 4400 1 4400 HARTSTEIN 13000 20 9500.00 13000 6000 2 19000 FAY 6000 20 9500.00 13000 6000 2 19000 RAPHAELY 11000 30 4150.00 11000 2500 6 24900 KHOO 3100 30 4150.00 11000 2500 6 24900 BAIDA 2900 30 4150.00 11000 2500 6 24900 TOBIAS 2800 30 4150.00 11000 2500 6 24900 HIMURO 2600 30 4150.00 11000 2500 6 24900 COLMENARES 2500 30 4150.00 11000 2500 6 24900 MAVRIS 6500 40 6500.00 6500 6500 1 6500 Definice těchto funkcí vypadá následovně (4): FUNKCE(DISTINCT ALL FUNKČNÍ VÝRAZ) OVER (ANALYTICKÁ KLAUZULE) Pokud není uveden modifikátor DISTINCT nebo ALL, použije se ALL. ALL zahrne do výpočtu všechny hodnoty, DISTINCT zahrne pouze unikátní hodnoty. Pokud je uveden modifikátor DISTINCT nelze v analytické klauzuli použít ORDER BY a definici okna (dotaz skončí vyhozením výjimky). Pokud chceme například zjistit, kolik různých platů se vyplácí v každém oddělení, použijeme agregační funkci COUNT. DEPARTMENT_ID, COUNT(*) EMP_COUNT, COUNT(DISTINCT SALARY) SAL_COUNT GROUP BY DEPARTMENT_ID; DEPARTMENT_ID EMP_COUNT SAL_COUNT ------------- ---------- ---------- 100 6 6 30 6 6 1 1 90 3 2 20 2 2 70 1 1 110 2 2 50 45 25 80 34 23 40 1 1 60 5 4 10 1 1 Například oddělení 90 má tři různé zaměstnance, ale dva z nich mají stejný plat. Stejně tak lze počítat například aritmetický průměr z unikátních hodnot či součet unikátních hodnot. - 30 -

Argumentem funkce COUNT může být navíc ještě symbol * (asterisk). Funkce pak vrací počet řádků včetně null hodnot a duplicit (4). 3.2.2 RATIO_TO_REPORT Funkce RATIO_TO_REPORT vrací poměr hodnoty výrazu k součtu všech hodnot výrazu v oblasti. DEPARTMENT_ID, SALARY, RATIO_TO_REPORT(SALARY) OVER (PARTITION BY DEPARTMENT_ID) RATIO, SALARY / SUM(SALARY) OVER (PARTITION BY DEPARTMENT_ID) RATIO2 ORDER BY DEPARTMENT_ID, SALARY LAST_NAME DEPARTMENT_ID SALARY RATIO RATIO2 ----------- ------------- ---------- ----- ------ WHALEN 10 4400 1 1 FAY 20 6000.3158.3158 HARTSTEIN 20 13000.6842.6842 COLMENARES 30 2500.1004.1004 HIMURO 30 2600.1044.1044 TOBIAS 30 2800.1124.1124 BAIDA 30 2900.1165.1165 KHOO 30 3100.1245.1245 RAPHAELY 30 11000.4418.4418 MAVRIS 40 6500 1 1 Sloupec RATIO obsahuje výsledek funkce RATIO_TO_REPORT a RATIO2 pak ručně spočítanou hodnotu pomocí podílu a funkce SUM. 3.3 LEAD/LAG family 3.3.1 LEAD, LAG Funkce LEAD a LAG nám umožňují se v oblasti podívat na hodnotu (resp. výraz) v řádce, která se nachází o určitý počet řádek před aktuální řádkou resp. po aktuální řádce. V SQL dotazu tak máme k dispozici nejen data z aktuální řádky, ale i z libovolné další řádky v oblasti. Funkce LEAD a LAG přebírají mimo funkčního výrazu ještě offset a výchozí hodnotu. Syntax je následující (4): - 31 -

LEAD LAG (VÝRAZ, OFFSET, VÝCHOZÍ HODNOTA) RESPECT IGNORE NULLS OVER (PARTITION BY KLAUULE ORDER BY KLAUZULE) 14 Výrazem může být název sloupce či jiný funkční výraz. Offset je pořadí požadovaného řádku před či po aktuální řádce. Tento parametr je volitelný a výchozí hodnotou je null. Volitelně lze pak ještě nastavit výchozí hodnotu, která bude vrácena v případě, že offset zasahuje za hranici oblasti (např. pro předchozí řádek u první řádky) (4). RESPECT IGNORE NULLS je volitelný modifikátor (výchozí hodnota je RESPECT NULLS), který ovlivňuje chování řádků vracejících NULL. IGNORE NULLS zajistí, že budou přeskočeny řádky, které vracejí NULL. Tyto řádky nebudou započítány do hodnoty offset (přeskočeno bude OFFSET řádků plus všechny řádky, které vracejí NULL) (5). Dotaz v následujícím příkladě vrací seznam zaměstnanců seřazený podle oddělení a platu (vzestupně). U každého zaměstnance je zobrazen rozdíl mezi předchozím nižším platem a jméno zaměstnance, který tento plat dostává (v rámci oddělení). Pokud neexistuje zaměstnanec s nižším platem, je rozdíl roven hodnotě NULL a místo jména je zobrazen text N/A. Toho je docíleno dosazením volitelného parametru. DEPARTMENT_ID, SALARY, SALARY - LAG(SALARY) OVER (PARTITION BY DEPARTMENT_ID ORDER BY SALARY ASC) SALARY_DIFF, LAG( 1, 'N/A') OVER (PARTITION BY DEPARTMENT_ID ORDER BY SALARY ASC) PREV_NAME ORDER BY DEPARTMENT_ID, SALARY ASC; 14 Alternativně lze modifikátor RESPECT IGNORE NULLS uvést za výrazem - 32 -

LAST_NAME DEPARTMENT_ID SALARY SALARY_DIFF PREV_NAME ----------- ------------- ---------- ----------- ----------- WHALEN 10 4400 N/A FAY 20 6000 N/A HARTSTEIN 20 13000 7000 FAY COLMENARES 30 2500 N/A HIMURO 30 2600 100 COLMENARES TOBIAS 30 2800 200 HIMURO BAIDA 30 2900 100 TOBIAS KHOO 30 3100 200 BAIDA RAPHAELY 30 11000 7900 KHOO MAVRIS 40 6500 N/A 3.4 FIRST/LAST family 3.4.1 FIRST, LAST Funkce FIRST a LAST od ostatních odlišuje jejich syntax. Umožňují nám operovat nad první resp. poslední skupinou, která vznikne hodnocením pomocí DENSE_RANK. Nad řádky, které vrátí FIRST či LAST je možné volat libovolnou agregační funkci (resp. funkce MIN, MAX, SUM, AVG, COUNT, VARIANCE, STDDEV) (3). Syntax je následující (5): AGREGAČNÍ FUNKCE KEEP (DENSE_RANK FIRST LAST ORDER BY VÝRAZ) OVER (PARTITION BY KLAUZULE) Klauzuli PARTITION BY je možné vynechat, funkce FIRST či LAST pak bude operovat nad všemi řádky. Pokud je vynechána celá část počínaje klíčovým slovem OVER, je funkce chápána jako funkce agregační (a je tedy nutné seskupit řádky pomocí GROUP BY). Tabulka EMPLOYEES obsahuje sloupec COMMISSION_PCT, kde uchováváme informace provizi. Chceme (v rámci oddělení) porovnat plat zaměstnance s nejnižším resp. nejvyšším platem ze skupiny zaměstnanců, kteří mají nejmenší resp. nejvyšší provizi (4). DEPARTMENT_ID, SALARY, COMMISSION_PCT, MIN(SALARY) KEEP (DENSE_RANK FIRST ORDER BY COMMISSION_PCT) OVER (PARTITION BY DEPARTMENT_ID) WORST, MAX(SALARY) KEEP (DENSE_RANK LAST ORDER BY COMMISSION_PCT) OVER (PARTITION BY DEPARTMENT_ID) BEST ORDER BY DEPARTMENT_ID, COMMISSION_PCT, SALARY; - 33 -

LAST_NAME DEPARTMENT_ID SALARY COMMISSION_PCT WORST BEST ----------- ------------- ---------- -------------- ---------- ---------- WHALEN 10 4400 4400 4400 FAY 20 6000 6000 13000 HARTSTEIN 20 13000 6000 13000 COLMENARES 30 2500 2500 11000... ERNST 60 6000 4200 9000 HUNOLD 60 9000 4200 9000 BAER 70 10000 10000 10000 KUMAR 80 6100 0.1 6100 14000 JOHNSON 80 6200 0.1 6100 14000 BANDA 80 6200 0.1 6100 14000 ANDE 80 6400 0.1 6100 14000 LEE 80 6800 0.1 6100 14000 MARVINS 80 7200 0.1 6100 14000 TUVAULT 80 7000 0.15 6100 14000... PARTNERS 80 13500 0.3 6100 14000 MCEWEN 80 9000 0.35 6100 14000 SULLY 80 9500 0.35 6100 14000 KING 80 10000 0.35 6100 14000 RUSSELL 80 14000 0.4 6100 14000 DE HAAN 90 17000 17000 24000 Jak funguje funkce FIRST a LAST je nejlépe vidět na zaměstnancích z oddělení 80. V rámci tohoto oddělení 15 byli zaměstnanci v případě výpočtu sloupce WORST seřazeni vzestupně 16 podle hodnoty COMMISSION_PCT. DENSE_RANK všem řádkům v oblasti přiřadí hodnocení. FIRST omezí řádky pouze na ty, které mají hodnocení nejnižší (hodnota 0.1) a vrátí je funkci MIN, která spočítá minimální hodnotu ze sloupce SALARY. Průběh výpočtu sloupce BEST je obdobný, ale je použita funkce LAST, která vrací řádky s nejvyšším hodnocením (hodnota 0.4). Funkce MAX pak vrací maximum z těchto řádků. Naznačena je vytvořená oblast oddělení 80, minimální plat ve skupině s nejnižší provizí a maximální plat ve skupině s nejvyšší provizí. 3.4.2 FIRST_VALUE, LAST_VALUE FIRST_VALUE resp. LAST_VALUE se od předchozích funkcí odlišuje tím, že vrací první resp. poslední hodnotu celé oblasti (nikoliv výsledek aplikování funkce nad první resp. poslední ohodnocenou skupinou). Nejdříve se určí oblast, které se seřadí a poté je vrácena hodnota z prvního resp. posledního řádku. Syntax je následující (4): 15 Rozdělení na oddělení bylo dosaženo pomocí části OVER a klauzule PARTITION BY DEPARTMENT_ID 16 Seřazení bylo dosaženo pomocí ORDER BY COMMISION_PCT - 34 -

FIRST_VALUE LAST_VALUE(VÝRAZ)RESPECT IGNORE NULLS OVER(PARTITION BY KLAUZULE) RESPECT NULLS je výchozí volba, která zajistí navrácení hodnoty z prvního resp. posledního řádku i v případě že se jedná o hodnotu NULL. Oproti tomu IGNORE NULLS zajistí vrácení první nenulové hodnoty (pokud taková existuje, jinak vrátí rovněž NULL). V následujícím příkladě chceme u každého zaměstnance znát maximální plat z jeho oddělení. K tomu je možné využít jak funkci MAX, tak funkci FIRST_VALUE. Funkce MAX nám ovšem nestačí v případě, kdy chceme ke každému zaměstnanci znát jméno zaměstnance s nejvyšším platem v oddělení. DEPARTMENT_ID, SALARY, MAX(SALARY) OVER (PARTITION BY DEPARTMENT_ID) MAX, FIRST_VALUE(SALARY) OVER (PARTITION BY DEPARTMENT_ID ORDER BY SALARY DESC) FIRST_VALUE, FIRST_VALUE(LAST_NAME) OVER (PARTITION BY DEPARTMENT_ID ORDER BY SALARY DESC) NAME_FIRST_VALUE LAST_NAME DEPARTMENT_ID SALARY MAX FIRST_VALUE MAX_NAME ----------- ------------- ---------- ---------- ----------- ----------- WHALEN 10 4400 4400 4400 WHALEN HARTSTEIN 20 13000 13000 13000 HARTSTEIN FAY 20 6000 13000 13000 HARTSTEIN RAPHAELY 30 11000 11000 11000 RAPHAELY KHOO 30 3100 11000 11000 RAPHAELY BAIDA 30 2900 11000 11000 RAPHAELY TOBIAS 30 2800 11000 11000 RAPHAELY HIMURO 30 2600 11000 11000 RAPHAELY COLMENARES 30 2500 11000 11000 RAPHAELY MAVRIS 40 6500 6500 6500 MAVRIS FRIPP 50 8200 8200 8200 FRIPP WEISS 50 8000 8200 8200 FRIPP Sloupce MAX a FIRST_VALUE obsahují stejné hodnoty, ačkoliv jsou počítány různými způsoby. Sloupec MAX_NAME obsahuje jméno zaměstnance v oddělení, který má nejvyšší plat. Funkce nejdříve rozdělí záznamy do oblastí, poté je seřadí a vrátí hodnotu sloupce SALARY z prvního řádku seřazené oblasti. Pozn.: Funkcí FIRST_VALUE resp. LAST_VALUE jsme schopni částečně nahradit funkce LEAD a LAG, které vracejí hodnoty z předchozích resp. následujících řádků. Pomocí okna vybereme z oblasti jen předchozí resp. následující řádku. Např. ROWS BETWEEN 2 PRECEEDING AND 1 PRECEEDING. - 35 -

3.4.3 NTH_VALUE Do verze 11gR2 přidal Oracle funkci NTH_VALUE, které je zobecněním funkcí FIRST_VALUE a LAST_VALUE. Funkce vrací hodnotu z n-tého řádku od konce či od začátku. Ačkoliv seřazení není vyžadováno, má tato funkce smysl pouze v případě seřazené oblasti. Syntax je následující (4): NTH_VALUE (VÝRAZ, N) FROM FIRST LAST IGNORE RESPECT NULLS OVER (PARTITION BY KLAUZULE ORDER BY KLAUZULE) Funkce jako svůj druhý parametr přijímá offset, tedy počet přeskočených řádků od konce či od začátku. To zda funkce vrací hodnotu z n-tého řádku od konce nebo od začátku, určuje modifikátor FROM FIRST LAST, jehož výchozí hodnota je FROM FIRST. FROM FIRST vrací hodnotu z n-tého řádku od začátku oblasti, FROM LAST od konce. Modifikátor IGNORE RESPECT NULLS pak určuje, zda jsou do offsetu započítány řádky, které vracejí null. Vztah s funkcemi FIRST_VALUE a LAST_VALUE je následující: FIRST VALUE (...) = NTH_VALUE (..., 1) FROM FIRST LAST VALUE (...) = NTH_VALUE (..., 1) FROM LAST V následujícím příkladě chceme porovnat plat každého zaměstnance s třemi nejvyššími platy v oddělení. DEPARTMENT_ID, SALARY, NTH_VALUE(SALARY, 1) OVER (PARTITION BY DEPARTMENT_ID ORDER BY SALARY DESC) FIRST, NTH_VALUE(SALARY, 2) OVER (PARTITION BY DEPARTMENT_ID ORDER BY SALARY DESC) SECOND, NTH_VALUE(SALARY, 3) OVER (PARTITION BY DEPARTMENT_ID ORDER BY SALARY DESC) THIRD ORDER BY DEPARTMENT_ID, SALARY DESC; - 36 -

LAST_NAME DEPARTMENT_ID SALARY FIRST SECOND THIRD ----------- ------------- ---------- ---------- ---------- ---------- WHALEN 10 4400 4400 HARTSTEIN 20 13000 13000 FAY 20 6000 13000 6000 RAPHAELY 30 11000 11000 KHOO 30 3100 11000 3100 BAIDA 30 2900 11000 3100 2900 TOBIAS 30 2800 11000 3100 2900 HIMURO 30 2600 11000 3100 2900 COLMENARES 30 2500 11000 3100 2900 MAVRIS 40 6500 6500 FRIPP 50 8200 8200 WEISS 50 8000 8200 8000 KAUFLING 50 7900 8200 8000 7900 Sloupec SECOND a THIRD obsahuje hodnoty NULL i např. v oddělení 30, ačkoliv v oddělení pracují více než 3 zaměstnanci. NULL hodnota ve sloupci SECOND a THIRD není v oddělení 10 překvapivá. Pracuje zde jen jeden zaměstnanec a tak hodnoty druhý nejvyšší a třetí nejvyšší plat nedávají smysl. V oddělení 30 by ale tyto hodnoty měly existovat u každého řádku (zaměstnance). Výsledky SQL dotazu jsou ale správné a jsou v souladu s kapitolou 2.3.5. Analytické klauzule u sloupců FIRST, SECOND a THIRD obsahují definici řazení ORDER BY (jinak by dotaz postrádal smysl) ale neobsahují definici okna. Výchozím oknem tak je ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW. Pokud chceme mít hodnoty sloupců SECOND a THIRD 17 v každém řádku, je nutné explicitně uvést definici okna, které bude obsahovat všechny řádky, tedy ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING. Následující SQL dotaz je důkazem. Zde se hodnoty NULL vyskytují pouze tam, kde hodnota skutečně neexistuje (oddělení obsahuje méně zaměstnanců než je n-tá hodnota). zaměstnance. 17 Sloupec FIRST neobsahuje v žádném řádku hodnotu NULL, neboť neexistuje oddělení bez - 37 -

DEPARTMENT_ID, SALARY, NTH_VALUE(SALARY, 1) OVER (PARTITION BY DEPARTMENT_ID ORDER BY SALARY DESC) FIRST, NTH_VALUE(SALARY, 2) OVER (PARTITION BY DEPARTMENT_ID ORDER BY SALARY DESC ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) SECOND, NTH_VALUE(SALARY, 3) OVER (PARTITION BY DEPARTMENT_ID ORDER BY SALARY DESC ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) THIRD ORDER BY DEPARTMENT_ID, SALARY DESC; LAST_NAME DEPARTMENT_ID SALARY FIRST SECOND THIRD ----------- ------------- ---------- ---------- ---------- ---------- WHALEN 10 4400 4400 HARTSTEIN 20 13000 13000 6000 FAY 20 6000 13000 6000 RAPHAELY 30 11000 11000 3100 2900 KHOO 30 3100 11000 3100 2900 BAIDA 30 2900 11000 3100 2900 TOBIAS 30 2800 11000 3100 2900 HIMURO 30 2600 11000 3100 2900 COLMENARES 30 2500 11000 3100 2900 MAVRIS 40 6500 6500 FRIPP 50 8200 8200 8000 7900 WEISS 50 8000 8200 8000 7900 KAUFLING 50 7900 8200 8000 7900 3.5 Statistické funkce Oracle obsahuje poměrně velké množství funkcí určených pro různé statistické výpočty. V následujícím textu jsou popsány některé nejběžnější funkce. 3.5.1 NTILE Funkce NTILE(N) rozdělí oblast na N skupin. Každý řádek je pak zařazen právě do jedné skupiny. Pokud je N větší než počet řádků v oblasti, bude počet skupin roven počtu řádků (4). Chceme například rozdělit zaměstnance do 4 platových skupin. Pro názornost vybereme pouze zaměstnance z oddělení 30. SALARY, NTILE(4) OVER (ORDER BY SALARY) NTILE WHERE DEPARTMENT_ID = 30; - 38 -