Przydatne sztuczki - sql. Na przykładzie postgres a. M. Wiewiórko 05/2014
Plan Uwagi wstępne Przykład Rozwiązanie Tabela testowa Plan prezentacji: Kilka uwag wstępnych. Operacje na typach tekstowych. Korzystanie z funkcji oknowych (window functions)... Tworzenie funkcji użytkownika.
Uwagi wstępne: Uwagi wstępne Przykład Rozwiązanie Tabela testowa Aby sprawnie posługiwać się sql em trzeba dobrze rozumieć zasady jego działania. Sprowadza się to do tego, że zawsze warto sprawdzić czy nasze myślenie jest zbieżne z działaniem sql a;)
Przykład Uwagi wstępne Przykład Rozwiązanie Tabela testowa Problem: Otrzymaliśmy dane (w formie tekstowej). Jedną z kolumn należy przetransformować na typ date. Niestety data jest zapisana w 3 różnych formatach - i nie wszystkie są akceptowane przez postgres a. Formaty daty: yyyy-mm-dd lub yyyymmdd - domyślnie akceptowany przez postgres a dd-mm-yyyy - nie akceptowany przez postgres a
Rozwiązanie Uwagi wstępne Przykład Rozwiązanie Tabela testowa select case when d_zdarzenia ~* [0-9]{4} -[0-9]{1,2} -[0-9]{1,2} or d_zdarzenia ~* [0-9]{8} then d_zdarzenia :: date when dzdarzenia ~* [0-9]{2} -[0-9]{2} -[0-9]{4} then ( substring ( d_zdarzenia from 7 for 4) substring ( d_zdarzenia from 4 for 2) substring ( d_zdarzenia from 1 for 2)):: date else null end from ( select 2011-11 -01 :: text as d_zdarzenia ) a; W prosty sposób sprawdzamy przekształcenie dla konkretnej wartości którą sami podajemy. Wstawiając argument 2011-11-01 lub 20111101 dostaniemy datę 2011-11-01. Podając 20-11-1101 otrzymamy datę 1101-11-20.
Tabela testowa Uwagi wstępne Przykład Rozwiązanie Tabela testowa Stworzenie tabeli: create table tmp_tabela_testowa as select id_platnosc, ( random ()*10000):: numeric (15,2) as kwota, ceil ( random ()*100) id_podmiot, current_date + ceil (( random () -0.5)*300):: int as d_tranzakacji from generate_series (1,3000) id_platnosc ; Będziemy się posługiwać powyższą tabelą do zobrazowania kilku przykładów.
Łączenie łańcuchów znaków (konkatenacja) -- przykład 1: select aaa bbbb ; lub select concat ( aaa, bbbb ); -- przykład 2: select aaa null ; lub select concat ( aaa,null ); Wynik to: Przykład 1: aaabbbb (oba przypadki) Przykład 2: null (dla ) oraz aaa (dla concat). Funkcja concat ignoruje null e!!!
Najważniejsze funkcje: length,translate,substring,position, reverse,replace,lower,upper...
substring Standardowe działanie - wyciąga określoną ilość znaków od określonego miejsca: -- przykład 1: select substring ( asdfghjk from 2 for 5); -- Wynik : sdfgh Niestandardowe działanie - wyciąga określony wzorzec z łańcucha znaków: -- przykład 2: select substring ( asdf2000-09 -11 ghjk from [0-9]{4} -[0-9]{1,2} -[0-9]{1,2} ); -- Wynik : 2000-09 -11
Co to jest?: są to funkcje które przeprowadzają obliczenia na pewnym zbiorze wierszy które są w pewnej relacji z bieżącym wierszem. Między innymi mogą to być wszystkie funkcje agregujące. Składnia - przykład: select *, sum ( kwota ) over ( partition by id_podmiot ) suma_wplat, avg ( kwota ) over ( partition by id_podmiot ) srednia_wplata, row_number () over ( partition by id_podmiot order by d_tranzakacji desc ) as kolejnosc_od_najnowszej from tmp_tabela_testowa ;
Wynik:
Przykład: Chcemy widzieć 3 ostatnie wpłaty danego podmiotu. Rozwiązanie: Mając dodaną do tabeli kolejność możemy zastosować następujące zapytanie: select id_podmiot, sum ( case when order_najnowsza =1 then kwota else null end ) wplat_1, sum ( case when order_najnowsza =2 then kwota else null end ) wplat_2, sum ( case when order_najnowsza =3 then kwota else null end ) wplat_3 from tmp_tabela_testowa group by 1 order by 1;
Wynik:
Operacja: select date 2001-09 -28 + integer 7 ; select date 2001-09 -28 + interval 1 hour ; select date 2001-09 -28 + time 03:00 ; select interval 1 day + interval 1 hour ; select timestamp 2001-09 -28 01:00 + interval 23 hours ; select time 01:00 + interval 3 hours ; select - interval 23 hours ; select date 2001-10 -01 - date 2001-09 -28 ; select date 2001-10 -01 - integer 7 ; select date 2001-09 -28 - interval 1 hour ; select time 05:00 - time 03:00 ; select time 05:00 - interval 2 hours ; select timestamp 2001-09 -28 23:00 - interval 23 hours ; select interval 1 day - interval 1 hour ; select timestamp 2001-09 -29 03:00 - timestamp 2001-09 -27 12:00 ; select 900 * interval 1 second ; select 21 * interval 1 day ; select double precision 3.5 * interval 1 hour ; select interval 1 hour / double precision 1.5 ; Wynik: date 2001-10 -05 timestamp 2001-09 -28 01:00:00 timestamp 2001-09 -28 03:00:00 interval 1 day 01:00:00 timestamp 2001-09 -29 00:00:00 time 04:00:00 interval -23:00:00 integer 3 ( days ) date 2001-09 -24 timestamp 2001-09 -27 23:00:00 interval 02:00:00 time 03:00:00 timestamp 2001-09 -28 00:00:00 interval 1 day -01:00:00 interval 1 day 15:00:00 interval 00:15:00 interval 21 days interval 03:30:00 interval 00:40:00
Przykład Problem: Trzeba przygotować harmonogram spłat rat kredytu. Wiadomo ile klient ma zapłacić rat oraz kiedy ma nastąpić pierwsza płatność. Rozwiązanie: select nr_raty +1 as nr_raty, ( d_p_rata +( nr_raty month ):: interval ):: date data_raty from ( select 10 as l_rat, 2013-01 -30 :: date as d_p_rata ) a join generate_series (0,500) nr_raty on nr_raty <a. l_rat ;
Przykład Wynik:
Przydatne funkcje: to char - przekształca datę na tekst wg. wybranej konwencji. EXTRACT - wyciąga ze zmiennej czasowej wybrany fragment (dzień/miesiąc/godzinę ect.) Przykładowo: select to_char ( 2013-01 -12 :: date, yyyy -mm -01 ); select extract ( month from 2013-01 -12 :: date ); Wynik to kolejno: 2013-01-01 oraz 1;
Przykład 1 Problem: W tabeli tmp tabela testowa wyciągnij rekordy gdzie płatność nie nastąpiła w weekend. Rozwiązanie: select * from tmp_tabela_testowa where extract ( dow from d_tranzakacji ) not in (0,6);
Przykład 2 Problem: Trzeba wyznaczyć liczbę dni roboczych między dwoma datami. Nie uwzględniamy dni świątecznych wypadających w tygodniu. Rozwiązanie: SELECT count (*) l_dni_roboczych FROM generate_series (1,( 2013-05 -01 :: date - 2013-04 -01 :: date )) i WHERE extract ( dow from ( 2013-05 -01 :: date + i)) NOT IN (0,6);
Czym są wyrażenia regularne Z ang. regular expressions, w skrócie regex lub regexp. Są to wzorce, które opisują łańcuchy symboli. Teoria wyrażeń regularnych jest związana z teorią języków regularnych. Wyrażenia regularne mogą określać zbiór pasujących łańcuchów, mogą również wyszczególniać istotne części łańcucha. W praktyce znalazły bardzo szerokie zastosowanie, pozwalają bowiem w łatwy sposób opisywać wzorce tekstu, natomiast istniejące algorytmy w efektywny sposób określają, czy podany ciąg znaków pasuje do wzorca lub wyszukują w tekście wystąpienia wzorca.
Podstawowa składnia Operator porównania: select ala ma konta ~ Ala ; -- wynik false select ala ma konta ~* Ala ; -- wynik true select ala ma konta!~* Ala ; -- wynik false
Znaki specjalne
Znaki specjalne
Znaki specjalne
Przykłady -- Przykładowe wyrażenia -- data w formacie yyyy -mm - dd select asdf2000-09 -11 ghjk ~* [0-9]{4} -[0-9]{1,2} -[0-9]{1,2} ; -- występują cyfry select asdf2000-09 -11 ghjk ~* [0-9]+ ; -- występują same cyfry select asdf2000-09 -11 ghjk ~* ^[0-9]+ $ ; -- liczby typu numeric select asdf2000.23423 ghjk ~* [0-9]+[.]{1}[0-9]+ ; -- [.]=\. -- występuje słowo ala lub kot select ala ma konta ~* ala kot ;
Koniec.