Schemat bazy danych TIMES # TIME_KEY TRANSACTION_DATE DAY_OF_WEEK HOLIDAY_FLAG Funkcje analityczne Operatory ROLLUP i CUBE, funkcja GROUPING, funkcje porządkujące (ranking), okienkowe, raportujące, statystyczne, funkcje LAG/LAD PRODUCTS # PRODUCT_KEY DESCRIPTION FULL_DESCRIPTION PRODUCT_TYPE PRODUCT_CATEGORY BRAND AGE_CATEGORY DEPARTMENT SALES_FACT # TIME_KEY # STORE_KEY # PRODUCT_KEY SALES UNIT_SALES COST CUSTOMER_COUNT PROFIT STORE # STORE_KEY STORE_NAME CITY REGION FLOOR_PLAN_TYPE STORE_SIZE REPORTS ROLLUP Polecenie ROLLUP jest rozszerzeniem klauzuli GROUP BY, które pozwala wyliczać podsumowania częściowe i ogólne. Polecenie ROLLUP służy do konstruowania pół-kostek danych. ROLLUP jest wyrażeniem wyjątkowo wydajnym. Dla n kolumn grupujących ROLLUP tworzy n + 1 podsumowań. SELECT atrybuty grupujące, agregaty FROM...... WHERE...... GROUP BY BY ROLLUP (atrybuty grupujące); SELECT t.day_of_week, p.description, s.city, s.city, SUM(sf.sales) AS AS sum_sales, COUNT(*) AS AS num_of_sales FROM FROM times timest, t, products p, p, store stores, s, sales_fact sf sf WHERE t.time_key = sf.time_key AND AND p.product_key = sf.product_key AND AND s.store_key = sf.store_key AND AND s.region = East' East' AND AND p.brand = Wild WildAge' GROUP BY BY ROLLUP(t.day_of_week, p.description, s.city); ROLLUP - wynik DAY_OF_WEEK DESCRIPTION CITY SUM_SALES -------------------- ------------------------------ ------------------------------ ---------- Friday The Net Atlanta 180,17 Friday The Net Boston 247,59 Friday The Net NULL 5421,26 Friday The Secret Garden Philadelphia 17,15 Friday The Secret Garden Pittsburgh 38,22 Friday The Secret Garden Washington 135,77 Friday The Secret Garden NULL 362,59 Friday The Shawshank Redemption Boston 75,04 Friday The Shawshank Redemption New York 190,05 Friday The Shawshank Redemption Pittsburgh 20,93 Friday The Shawshank Redemption Washington 108,82 Friday The Shawshank Redemption NULL 394,84 Friday Village of the Damned New York 605,73 Friday Village of the Damned Philadelphia 126,4 Friday Village of the Damned Pittsburgh 171,01 Friday Village of the Damned Washington 199,94 Friday Village of the Damned NULL 1655,36 Friday NULL NULL 10389,18............ NULL NULL NULL 66917,79
Częściowa operacja ROLLUP SELECT atrybuty grupujące, agregaty FROM...... WHERE...... GROUP BY BY atrybut, ROLLUP (atrybuty grupujące); SELECT t.day_of_week, p.product_type, s.city, s.city, SUM(sf.cost) AS AS sum_sales, COUNT(*) AS AS num_of_sales FROM FROM times timest, t, products p, p, store stores, s, sales_fact sf sf WHERE t.time_key = sf.time_key AND AND p.product_key = sf.product_key AND AND s.store_key = sf.store_key AND AND s.region = 'East' 'East' GROUP BY BY t.day_of_week, ROLLUP(p.product_type, s.city); CUBE Operator CUBE tworzy podsumowania dla wszystkich możliwych kombinacji grupowanych kolumn. W terminologii analiz wielowymiarowych, CUBE generuje podsumowania częściowe i ogólne tabeli faktów dla wszystkich możliwych wymiarów. Dla n kolumn grupujących CUBE tworzy 2 n podsumowań. SELECT atrybuty grupujące, agregaty FROM...... WHERE...... GROUP BY BY CUBE (atrybuty grupujące); SELECT p.product_category, s.region, SUM(sf.profit) AS AS sum_profit, SUM(unit_sales) AS AS sum_unit_sales FROM FROM products p, p, store stores, s, sales_fact sf sf AND AND s.store_key = sf.store_key GROUP BY BY CUBE( CUBE( p.product_category, s.region); CUBE - wynik Częściowa operacja CUBE PRODUCT_CATEGORY REGION SUM_PROFIT SUM_UNIT_SALES -------------------- -------------------- ---------- -------------- Action Central 48960 9813 Action East 69730 15193 Action West 36372 7523 Action NULL 155062 32529 Alcohol Central 91 700 Alcohol East 125 1017 Alcohol West 71 463 Alcohol NULL 287 2180 Candy Central 275 2078 Candy East 429 3402 Candy West 256 1746 Candy NULL 960 7226 Video Game Central 33557 12267 Video Game East 59626 20243 Video Game West 34577 9986 Video Game NULL 127760 42496 NULL Central 312352 99210 NULL East 490286 156979 NULL West 274114 79573 NULL NULL 1076752 335762 SELECT atrybuty grupujące, agregaty FROM...... WHERE...... GROUP BY BY atrybut, CUBE (atrybuty grupujące); SELECT to_char(t.transaction_date,'month') AS AS month, p.product_category, s.region, SUM(sf.profit) AS AS sum_profit, SUM(unit_sales) AS AS sum_unit_sales FROM FROM times timest, t, products p, p, store stores, s, sales_fact sf sf WHERE t.time_key = sf.time_key AND AND p.product_key = sf.product_key AND AND s.store_key = sf.store_key AND AND p.department = 'Video 'Video Rental' GROUP BY BY to_char(t.transaction_date,'month'), to_char(t.transaction_date,'mm'), CUBE CUBE (( p.product_category, s.region) ORDER BY BY to_char(t.transaction_date,'mm');
Podsumowanie CUBE i ROLLUP Wartości puste w operatorach ROLLUP i CUBE Operatory ROLLUP i CUBE działają niezależnie od zdefiniowanych w bazie danych hierarchii Przy operacjach ROLLUP i CUBE możemy wykorzystać również inne funkcje agregujące: COUNT, AVG, MIN, MAX, STDDEV i VARIANCE Klauzula HAVING w przypadku użycia CUBE lub ROLLUP odnosi się zarówno do elementów (wierszy) podsumowywanych jak do zwykłych Klauzula ORDER BY nie rozróżnia wierszy podsumowywanych i zwykłych. Do ich rozróżnienia trzeba użyć funkcji GROUPING Puste wartości kolumn w przypadku zapytań z funkcjami ROLLUP i CUBE mogą oznaczać operacje podsumowania wykonywaną na określonym wymiarze lub standardową wartość pustą kolumny, np. we fragmencie poniżej trzeci wiersz z wartością pustą może oznaczać podsumowanie dwóch powyższych jak i np. podsumowanie dla departamentu o pustej nazwie. Time Region Department Profit ---- ------ ---------- ------ 1996 NULL VideoRental 251,000 1996 NULL VideoSales 275,000 1996 NULL NULL 526,000 Funkcja GROUPING Funkcja GROUPING pozwala rozróżnić wiersze z wartościami pustymi od wierszy podsumowań. Jeżeli wartość pusta oznacza podsumowanie GROUPING zwraca wartość 1, w przeciwnym przypadku 0. SELECT...,..., GROUPING(atrybut grupujący) FROM...... WHERE...... GROUP BY BY {{ ROLLUP CUBE }}(atrybuty grupujące); SELECT t.day_of_week, p.brand, s.city, s.city, GROUPING(t.day_of_week) AS AS T, T, GROUPING(p.brand) AS AS B, B, GROUPING(s.city) AS AS C, C, SUM(sf.profit) AS AS profit profit FROM FROM times timest, t, products p, p, store stores, s, sales_fact sf sf WHERE t.time_key = sf.time_key AND AND p.product_key = sf.product_key AND AND s.store_key = sf.store_key AND AND p.department = 'Snacks' AND AND s.region = 'West 'West GROUP BY BY CUBE CUBE (( t.day_of_week, p.brand, s.city s.city ); ); Funkcja GROUPING - wynik Wednesday San Francisco 0 1 0 32 Wednesday Seattle 0 1 0 13 Wednesday 0 1 1 74 Dordor Denver 1 0 0 27 Dordor Los Angeles 1 0 0 17 Dordor Phoenix 1 0 0 23 Dordor San Francisco 1 0 0 81 Dordor Seattle 1 0 0 90 Dordor 1 0 1 238 Galore Denver 1 0 0 23 Galore Los Angeles 1 0 0 11 Galore Phoenix 1 0 0 9 Galore San Francisco 1 0 0 47 Galore Seattle 1 0 0 48 Galore 1 0 1 138 Leavenworth Denver 1 0 0 36 Leavenworth Los Angeles 1 0 0 14 Leavenworth Phoenix 1 0 0 9 Leavenworth San Francisco 1 0 0 55 Leavenworth Seattle 1 0 0 72 Leavenworth 1 0 1 186 Denver 1 1 0 86 Los Angeles 1 1 0 42 Phoenix 1 1 0 41 San Francisco 1 1 0 183 Seattle 1 1 0 210 1 1 1 562
Funkcja GROUPING rozróżnienie wartości pustych od podsumowań SELECT DECODE(GROUPING(t.day_of_week),1,'All days',t.day_of_week), DECODE(GROUPING(p.product_category),1,'All cats',p.product_category), DECODE(GROUPING(s.region),1,'All regs',s.region), SUM(sf.cost) as as cost, cost, FROM FROM times timest, t, products p, p, store stores, s, sales_fact sf sf WHERE t.time_key = sf.time_key AND AND p.product_key = sf.product_key AND AND s.store_key = sf.store_key GROUP BY BY CUBE CUBE (( t.day_of_week, p.product_category, s.region ); );............ All days Thriller East 39093 All days Thriller West 17275 All days Thriller All regions 82824 All days Video Game Central 10618 All days Video Game East 13427 All days Video Game West 1733 All days Video Game All regions 25778 All days All categories Central 167122 All days All categories East 261547 All days All categories West 111783 All days All categories All regions 540452 Funkcje analityczne Funkcje analityczne dzielą się na następujące kategorie: porządkujące wyliczające ranking : RANK, DENSE_RANK, PERCENT_RANK, CUME_DIST, NTILE Okienkowe (funkcje okna) wyznaczają wartości agregatów dla zdefiniowanych okien : AVG, SUM, MIN, MAX, COUNT, VARIANCE, STDDEV, FIRST_VALUE, LAST_VALUE raportujące wyliczające udziały : AVG, SUM, MIN, MAX, COUNT, VARIANCE, STDDEV funkcje LAG/LEAD znajdujące wartości w krotkach o określonej odległości od krotki bieżącej statystyczne wyliczające zmiany poziomów, i inne statystyki Zagadnienia związane z funkcjami analitycznymi Kolejność przetwarzania Partycje funkcje analityczne pozwalają użytkownikom dzielić rezultat zapytania na grupy zwane partycjami. Partycje są tworzone po grupowaniu, dlatego nie są dozwolone dla nich funkcje agregujące. Podział na partycje może być oparty o dowolną kolumnę lub wyrażenie. Zagadnienia związane z funkcjami analitycznymi Okno dla każdej krotki w partycji można zdefiniować ruchome okno danych. Okno takie określa zakres krotek używanych do wykonania obliczeń dla bieżącej krotki. Rozmiary okna mogą być oparte zarówno na fizycznej liczbie krotek, jak i na logicznym przedziale, takim jak np. czas. Bieżąca krotka każde obliczenie za pomocą funkcji analitycznej jest oparte na bieżącej krotce wewnątrz partycji. Bieżąca krotka służy jako punkt odniesienia określający początek i koniec okna.
RANK i DENSE_RANK Funkcje RANK i DENSE_RANK pozwalają uporządkowanie elementów w grupie, np. na znalezienie trzech najlepiej sprzedających się produktów. RANK() OVER (( DENSE_RANK() OVER (( RANK - przykład SELECT s.city, SUM(sf.profit) AS AS PROFIT, RANK() OVER (( ORDER BY BY SUM(sf.sales) DESC )) AS AS RANK FROM store s, s, sales_fact sf sf WHERE s.store_key = sf.store_key GROUP BY BY s.city; SELECT s.city, s.region, SUM(sf.sales) AS AS SALES, RANK() OVER (( PARTITION BY BY s.region ORDER BY BY SUM(sf.sales) DESC )) AS AS RANK FROM store s, s, sales_fact sf sf WHERE s.store_key = sf.store_key GROUP BY BY s.city, s.region; RANK przykład 2 Przy pomocy funkcji RANK i DENSE_RANK można dokonywać selekcji pozycji wg wyznaczonego przez nie porządku. SELECT ** FROM (( SELECT p.description, SUM(sf.sales) AS AS SALES, RANK() OVER (( ORDER BY BY SUM(sf.sales) )) AS AS RANK FROM products p, p, sales_fact sf sf GROUP BY BY p.description )) WHERE rank BETWEEN 1 AND 10; 10; DENSE_RANK - przykład W przeciwieństwie do funkcji RANK() funkcja DENSE_RANK() nie pozostawia pustych wartości w sekwencji rankingu. SELECT p.product_category, s.city, SUM(sf.profit) AS AS PROFIT, COUNT(*) AS AS COUNT, DENSE_RANK() OVER (( PARTITION BY BY s.city ORDER BY BY COUNT(*) DESC )) AS AS RANK FROM store s, s, products p, p, sales_fact sf sf WHERE s.store_key = sf.store_key AND p.product_key = sf.product_key AND p.department = 'Video Rental' GROUP BY BY p.product_category, s.city;
CUME_DIST Funkcja CUME_DIST wylicza pozycję wyspecyfikowanej wartości w podzbiorze. Kolejność może być rosnąca lub malejąca. Wartości przyjmowane przez CUME_DIST są w zakresie od 0 + do 1. Definicja: CUME_DIST(x) = liczba wartości w zbiorze S występujących przed wartością x (przy określonym porządku wartości) // liczbę wszystkich wartości w zbiorze S CUME_DIST() OVER (( CUME_DIST - przykład SELECT p.description, SUM(sf.sales) AS AS SALES, CUME_DIST() OVER (( ORDER BY BY SUM(sf.sales) )) AS AS CUME_DIST FROM products p, p, sales_fact sf sf AND p.age_category = 'over 18' 18' GROUP BY BY p.description; PERCENT_RANK Funkcja PERCENT_RANK jest bardzo podobna do CUME_DIST. Różnica polega na tym, że PERCENT_RANK bierze pod uwagę pozycję przy określonym porządku a nie wartość. Wartości przyjmowane przez CUME_DIST są w zakresie od 0 do 1. Definicja: PERCENT_RANK(x) = ranking krotki x w partycji 1 // liczba krotek w partycji 1 PERCENT_RANK() OVER (( PERCENT_RANK - przykład SELECT p.description, s.region, SUM(sf.profit) AS AS PROFIT, PERCENT_RANK() OVER (( PARTITION BY BY s.region ORDER BY BY SUM(sf.profit) )) AS AS PERCENT FROM store s, s, products p, p, sales_fact sf sf AND s.store_key = sf.store_key AND p.age_category = 'over 18' 18' GROUP BY BY p.description, s.region;
NTILE NTILE dzieli krotki w uporządkowanej partycję na określoną liczbę grup (bucket) i przypisuje każdej z nich liczbę porządkową. Liczba krotek między grupami różni się co najwyżej o jedną krotkę. Funkcja NTILE służy przede wszystkim do wyliczania kwantyli, kwartyli i median. NTILE jest funkcją niedeterministyczną. NTILE(N) OVER (( NTILE - przykład SELECT s.city, SUM(sf.unit_sales) AS AS UNIT_SALES, NTILE(5) OVER (( ORDER BY BY SUM(sf.unit_sales) )) AS AS NTILE FROM store s, s, sales_fact sf sf WHERE s.store_key = sf.store_key GROUP BY BY s.city ORDER BY BY NTILE, UNIT_SALES DESC; SELECT t.day_of_week, s.city, SUM(sf.profit) AS AS PROFIT, NTILE(7) OVER (( PARTITION BY BY s.city ORDER BY BY SUM(sf.profit) DESC) AS AS NTILE FROM times t, t, store s, s, sales_fact sf sf WHERE s.store_key = sf.store_key AND t.time_key = sf.time_key GROUP BY BY t.day_of_week, s.city ORDER BY BY NTILE, PROFIT DESC; ROW_NUMBER Funkcja ROW_NUMBER przypisuje unikalny numer każdej krotce w partycji. Podobnie jak funkcja NTILE, ROW_NUMBER jest niedeterministyczna. Aby zapewnić deterministyczny wynik sortowanie musi się odbywać po kluczu unikalnym. ROW_NUMBER() OVER (( ROW_NUMBER - przykład SELECT s.city, SUM(sf.profit) --SUM(sf.cost) AS AS FINAL, ROW_NUMBER() OVER (( ORDER BY BY SUM(sf.profit) --SUM(sf.cost) DESC )) AS AS NUM FROM store s, s, sales_fact sf sf WHERE s.store_key = sf.store_key GROUP BY BY s.city; SELECT p.description, p.age_category, TRUNC(SUM(sf.customer_count),-3) AS AS CUSTOMERS, ROW_NUMBER() OVER (( PARTITION BY BY p.age_category ORDER BY BY TRUNC(SUM(sf.customer_count),-3) DESC )) AS AS NUM FROM products p, p, sales_fact sf sf AND p.department = 'Video Sale' GROUP BY BY p.description, p.age_category
Funkcje okienkowe Funkcje okienkowe operują na uporządkowanym zbiorze krotek i dla każdej krotki obliczają wartość agregowaną dla okna, którego środkiem jest bieżąca krotka. Rozmiary okna mogą być nieograniczone lub ograniczone. Podobnie jak w przypadku funkcji rankingowych zbiór danych może być najpierw podzielony na partycje. Rodzina funkcji okienkowych to w rzeczywistości rozszerzona składnia i funkcjonalność klasycznych funkcji agregujących SUM, AVG, MIN, MAX, STDDEV, VARIANCE, COUNT, FIRST_VALUE i LAST_VALUE. Cechy funkcji okienkowych Oprócz funkcji standardowych SUM, AVG, MIN,... Jako funkcje okienkowe można wykorzystać funkcje analizy regresji VAR_SAMP, VAR_POP, STDDEV_SAMP, STDDEV_POP, COVAR_SAMP, COVAR_POP, REGR_SLOPE, REGR_INTERCEPT, REGR_R2, REGR_AVGX, REGR_AVGY, REGR_COUNT, REGR_SXX, REGR_SXY, REGR_SYY Każda funkcja może mieć klauzulę definiującą rozmiar okna (w przeciwnym wypadku okno jest nieograniczone obejmuje wiersze od początku partycji do bieżącego wiersza) Każda funkcja ma własną klauzulę sortującą Funkcje agregujące w oknach są resetowane na granicy partycji Dla każdego wyrażenia występującego w funkcji można określać porządek wzrastający i malejący Wartości puste mogą być umieszczane na początku bądź końcu (niezależnie od porządku sortowania) Określanie rozmiarów okien Fizyczne: wyrażone w liczbie krotek, dodatkowo słowa kluczowe CURRENT ROW: okno rozpoczyna się lub kończy w bieżącym wierszu UNBOUNDED PRECEDING: okno rozpoczyna się na pierwszej krotce partycji UNBOUNDED FOLLOWING: okno kończy się na ostatniej krotce partycji Czasowe: wyrażone interwałem czasowym Zakresy wartości: wyrażone różnicą między wartością w bieżącej krotce i wartością poprzedzającą Funkcja okienkowa ze stałym oknem Okno dla każdej krotki zaczyna się zawsze na początku bieżącej partycji stałe jest osadzenie początku okna SELECT p.description, t.transaction_date, sf.sales, SUM(sf.sales) OVER (( PARTITION BY BY p.description ORDER BY BY t.transaction_date ROWS UNBOUNDED PRECEDING )) AS AS GRAND_SUM FROM times t, t, store s, s, products p, p, sales_fact sf sf WHERE t.time_key = sf.time_key AND s.store_key = sf.store_key AND p.product_key = sf.product_key AND s.city = 'Atlanta' AND p.department = 'Video Rental' AND TO_CHAR(t.transaction_date,'D') = 7; 7;
Funkcja okienkowa ze zmiennym oknem Okno dla bieżącej krotki jest wyrażone jako odległość 15 dni wstecz od daty bieżącej transakcji SELECT t.transaction_date, sf.sales, AVG(sf.sales) OVER (( ORDER BY BY t.transaction_date RANGE INTERVAL '15' '15' DAY PRECEDING )) AS AS AVERAGE FROM times t, t, store s, s, sales_fact sf sf WHERE t.time_key = sf.time_key AND s.store_key = sf.store_key AND s.city = 'New York' AND sf.profit > 250 250 ORDER BY BY AVERAGE DESC; Funkcja okienkowa ze zmiennym oknem Okno dla bieżącej krotki jest wyrażone jako dwie krotki wstecz od bieżącej krotki SELECT t.transaction_date, AVG(sf.sales) OVER (( PARTITION BY BY t.transaction_date ORDER BY BY t.transaction_date ROWS BETWEEN 2 PRECEDING AND 0 FOLLOWING) AS AS AVERAGE FROM times t, t, products p, p, sales_fact sf sf WHERE t.time_key = sf.time_key AND p.product_key = sf.product_key AND t.day_of_week = 'Monday' AND p.description = 'Toy 'ToyStory'; Funkcje FIRST_VALUE i LAST_VALUE Funkcje FIRST_VALUE i LAST_VALUE pozwalają użytkownikowi odczytywać wartości z pierwszej i ostatniej krotki w oknie. Pozwalają one na analizę porównawczą z wartościami bazowymi dla danego okna. SELECT city, city, region, sum_sales, LAST_VALUE(sum_sales) OVER (( PARTITION BY BY region ORDER BY BY sum_sales ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING )) AS AS LAST_VAL FROM (( SELECT s.city, s.region, SUM(sf.sales) AS AS sum_sales FROM store s, s, sales_fact sf sf WHERE s.store_key = sf.store_key GROUP BY BY s.city, s.region ); ); Funkcje raportujące Podczas analizy często zachodzi konieczność porównywania wartości na różnych poziomach agregacji. Funkcje raportujące umożliwiają włączanie do krotek wartości pochodzących z różnych poziomów agregacji. Funkcje raportujące działają na poziomie okien i zwracają albo wartość agregatu dla całego okna albo wartość agregatu dla okna z wyłączeniem bieżącego okna. Składnia {SUM AVG MAX MIN MIN COUNT STDDEV VARIANCE} (([[ ALL ALL DISTINCT ]]{{ <value expression1> **}} )) OVER (([[ PARTITION BY BY <value expression2> [[,...,...]]]]) )
Przykłady funkcji raportujących SELECT p.department, s.region, SUM(sf.sales) AS AS sum_sales, MAX(SUM(sf.sales)) OVER OVER (( PARTITION BY BY p.department )) AS AS max_sales FROM FROM products p, p, store stores, s, sales_fact sf sf AND AND s.store_key = sf.store_key GROUP BY BY p.department, s.region; SELECT TO_CHAR(t.transaction_date,'MONTH') AS AS month, s.region, COUNT(sf.sales) as as count_sales, AVG(COUNT(sf.sales)) OVER OVER (( PARTITION BY BY s.region )) AS AS avg_count_sales FROM FROM times timest, t, store stores, s, sales_fact sf sf WHERE t.time_key = sf.time_key AND AND s.store_key = sf.store_key GROUP BY BY TO_CHAR(t.transaction_date,'MONTH'), s.region, TO_CHAR(t.transaction_date,'MM') ORDER BY BY TO_CHAR(t.transaction_date,'MM'), s.region; RATIO_TO_REPORT Funkcja RATIO_TO_REPORT służy do wyliczania stosunku danej wartości do sumy zbioru wartości w oknie. Jeśli wartość jest pusta, to wynikiem funkcji jest NULL. Jeśli klauzula PARTITION BY zostanie pominięta, to funkcja jest wyliczana na podstawie całego wyniku zapytania. Składnia: RATIO_TO_REPORT (<value expression1>) OVER (([[ PARTITION BY BY <value expression2> [[,...,...]]]]) ) RATIO_TO_REPORT - przykład SELECT p.age_category, SUM(sf.profit) AS AS sum_profit, RATIO_TO_REPORT(SUM(sf.profit)) OVER (()) AS AS ratio_profit, SUM(sf.sales) AS AS sum_sales, RATIO_TO_REPORT(SUM(sf.sales)) OVER (()) AS AS ratio_sales FROM products p, p, sales_fact sf sf GROUP BY BY p.age_category Funkcje LAG i LEAD Funkcje LAG i LEAD pozwalają na dostęp i porównanie wielu różnych krotek jednocześnie, bez konieczności wykonywania połączenia zwrotnego. Funkcje LAG i LEAD działają na podstawie podanego przez użytkownika przesunięcia (offset) względem bieżącej krotki. Składnia: {LAG LEAD} (( <value expression1>, [[ <offset> [[,, <default> ]]]])) OVER (([[ PARTITION BY BY <value expression2> [[,...,...]]]] ORDER BY BY <value expression3> [[ NULLS FIRST NULLS LAST ]][[,...,...]]))
Funkcje LAG i LEAD - przykład SELECT month, sum_cost, LAG(sum_cost,1) OVER (( ORDER BY BY month )) AS AS prev_cost, LEAD(sum_cost,1) OVER (( ORDER BY BY month )) AS AS next_cost FROM (( SELECT TO_CHAR(t.transaction_date,'MM YYYY') AS AS month, SUM(sf.cost) AS AS sum_cost FROM times t, t, sales_fact sf sf WHERE t.time_key = sf.time_key GROUP BY BY TO_CHAR(t.transaction_date,'MM YYYY') ); );