Tunnetko nämä PL/SQL:n piirteet? Kari Aalto Saariston IT
Saariston IT Oracle-, BI/DW- sekä QlikView-koulutukseen erikoistunut yritys Perustettu 2005 Asiakkaina ohjelmistotaloja sekä Oraclekäyttäjäyrityksiä Qliktech on Suomessa ulkoistanut vakiokurssien pidon Saariston IT:lle 2
Kari Aalto Oracle-koulutuskokemusta vuodesta 1994 alkaen Oraclen palveluksessa n. 9 vuoden ajan Suomessa, Euroopan tasolla sekä Lähi-Idässä Vajaan 2 vuoden kokemus Oraclen teknisen tuen tehtävistä Dubaissa ja Abu Dhabissa Pitkä käytännön kokemus Oraclesovelluskehityksestä 3
PL/SQL vanhat uudet piirteet jokainen ohjelmaversio tuo mukanaan ominaisuuksia, jotka helpottavat ja tehostavat ohjelmistojen kehitystyötä ja käyttöä tämä esitys luo pikaisen katsauksen PL/SQL:n vähemmän tunnettuihin, mutta joissain tilanteissa hyödyllisiin ominaisuuksiin ja tekniikoihin 4
Aiheita mm. Cursor Expression Dynaaminen SQL Record-Based DML Returning Values Bulk-operaatiot Conditional Compilation Table Function DML Error Logging 5
Cursor Expression
Osoitinlauseke (Cursor Expression) liittyy hierarkiseen hakuun: haun sisällä on toinen haku(luuppi) osoitinlauseke on vaihtoehto useampien osoittimien käytölle osoitinlausekkeiden käyttö tiivistää ohjelmakoodia, mutta ei ehkä tee sitä luettavammaksi 7
Cursor Expression (Oracle9i) Cursor Expression on Select-käskyn sarakelistaan kirjoitettu alikysely, joka muodostaa pää-select:in sisäisen toistorakenteen, eli... syntaksi: SELECT column1, column2, CURSOR (SELECT column3 FROM table2 t2 FROM table1 t1; WHERE t1.column = t2.column) 8
Cursor Expression asiakkaan tietojen alle tulevat hänen tilaustensa tiedot: SELECT id, nimi, CURSOR (SELECT tilno, tilpvm FROM tilaukset t WHERE t.asiakas_id = a.id) FROM asiakkaat a; ID NIMI -------------------- 1 MATTILA TILNO TILPVM -------------------- 10 10.05.2004 12 15.08.2004 25 28.10.2004 ID NIMI -------------------- 2 NURMELA TILNO TILPVM -------------------- 11 01.02.2005 9
Bulk-operaatiot
BULK LOAD FORALL-toistorakenne, joka voi parantaa suorituskykyä voidaan käyttää INSERT-, UPDATE- ja DELETEkäskyjen yhteydessä tiedot SQL-käskylle PL/SQL-taulukoista muistuttaa FOR LOOP rakennetta, mutta... ei END LOOP -avainsanoja toistorakenteen sisällä ei muita komentoja kuin SQL-käsky (ja viittaukset indeksiin) käytettävissä myös dynaamisessa SQL:ssä 11
BULK LOAD Without the bulk bind, PL/SQL sends a SQL statement to the SQL engine for each record that is inserted, updated, or deleted leading to context switches that hurt performance FORALL <index_name> IN <lower_boundary>.. <upper_boundary> <sql_statement> SAVE EXCEPTIONS; 12
Perinteinen tapa ja BULK LOAD Perinteinen tapa FOR i IN 1..500000 LOOP INSERT INTO testitaulu ( id, nimi, pvm) VALUES (id_taulu(i), nimi_taulu(i), END LOOP; pvm_taulu(i)); Bulk Load FORALL i IN 1.. 500000 INSERT INTO testitaulu ( id, nimi, pvm) VALUES (id_taulu(i), nimi_taulu(i), pvm_taulu(i)); 13
SQL%BULK_ROWCOUNT SQL%BULK_ROWCOUNT on taulukko, johon tallettuu bulk-moodissa käsiteltävien rivien rivikohtaiset paluukoodit BEGIN FORALL i IN 1..100 UPDATE testitaulu SET nimi = 'Mr. ' nimi WHERE id = indeksitaulu(i); END; IF SQL%BULK_ROWCOUNT(50) = 0 THEN... 14
Virhekoodit voidaan tallettaa taulukkoon DECLARE... virhekoodit NUMBER; BEGIN FORALL i IN 1.. 500000 SAVE EXCEPTIONS INSERT INTO testitaulu ( id, nimi, pvm) VALUES (id_taulu(i), nimi_taulu(i), pvm_taulu(i)); EXCEPTION WHEN OTHERS THEN virhekoodit := SQL%BULK_EXCEPTIONS.COUNT; FOR i IN 1.. virhekoodit LOOP -- indeksin arvo on SQL%BULK_EXCEPTIONS(i).ERROR_INDEX -- virhekoodi on SQL%BULK_EXCEPTIONS(i).ERROR_CODE END LOOP; END; 15
DML Error Logging (Oracle10g rel.2) yleensä DML-käskyn aiheuttama virhetilanne yhdenkin rivin johtaa koko käskyn perumiseen (Rollback) DML Error Logging mahdollistaa osan riveistä käsittelyn ja vie tiedot virheellisistä riveistä virhetauluun voidaan käyttää INSERT, UPDATE, DELETE ja MERGE käskyjen yhteydessä 16
DML Error Logging syntaksi LOG ERRORS [INTO [schema.]table] [('simple_expression')] [REJECT LIMIT integer UNLIMITED] vaaditut log-taulut luodaan komennolla BEGIN DBMS_ERRLOG.create_error_log (dml_table_name => 'emp'); END; käsky luo taulun err$_emp 17
DML Error Logging SQL> INSERT INTO emp SELECT * FROM tyontekijat; ERROR at line 2: ORA-01400: cannot insert NULL into ("demo". "EMP". "PALKKA") SQL> SQL> INSERT INTO emp SELECT * FROM tyontekijat LOG ERRORS INTO err$_emp ('koe_lisays') REJECT LIMIT UNLIMITED; SQL> 18
BULK COLLECT FORALL:ia vastaava rakenne hauissa on BULK COLLECT voidaan käyttää sekä osoittimien (Cursor) että Select Into lauseen yhteydessä hakee rivit PL/SQL taulukkoihin jos taulukot eivät ole tyhjiä, BULK COLLECT kirjoittaa tiedot aiempien arvojen päälle SELECT id, nimi, pvm BULK COLLECT INTO idt, nimet, osoitteet FROM testitaulu; 19
FORALL & BULK COLLECT FUNCTION TEST (p_osastot id_taulu_tyyppi) RETURN sotu_taulu_tyyppi IS sotut sotu_taulu_tyyppi; BEGIN FORALL i IN p_osastot.first..p_osastot.last DELETE FROM tyontekijat WHERE osasto_id = p_osastot(i) RETURNING sotu BULK COLLECT INTO sotut; RETURN sotut; END; 20
Native Dynamic SQL
Native Dynamic SQL yksinkertaisempaa kuin perinteinen dynaaminen SQL (DBMS_SQL-paketin käyttö) tehokkaampaa kuin DBMS_SQL:n käyttö OPEN CURSOR ottaa vastaa suoritettavan SQL-haun string:inä EXECUTE IMMEDIATE yksi käsky korvaa useat käskyt, joita vaaditaan DBMS_SQL:ää käytettäessä ottaa vastaa minkä tahansa SQL-käskyn, paitsi Selectin, joka palauttaa rivejä > 1 kappaletta 22
EXECUTE IMMEDIATE... BEGIN lause := 'INSERT INTO asiakkaat (id, nimi, kaupunki) VALUES (:1, :2, :3)'; EXECUTE IMMEDIATE lause USING a_id, a_nimi, a_kaupunki; lause := 'SELECT * FROM asiakkaat WHERE id = :id'; EXECUTE IMMEDIATE lause INTO asiakastietue USING a_id; END; / 24
OPEN FOR DECLARE TYPE as_cursortype is REF CURSOR; as_haku as_cursortype;... BEGIN lause := 'UPDATE asiakkaat SET osoite = :1 WHERE id = :2 RETURNING kaupunki INTO :3'; EXECUTE IMMEDIATE lause USING a_osoite, a_id, a_kaupunki; OPEN as_haku FOR 'SELECT id, nimi, kaupunki FROM asiakkaat WHERE id > :1' USING a_id;... END; 25
OPEN FOR CREATE OR REPLACE PROCEDURE tuote_proc ( p_ehto IN VARCHAR2) IS TYPE ctype IS REF CURSOR; cursor1 ctype; apu_id tuotteet.id%type; apu_merkki tuotteet.merkki%type; BEGIN OPEN cursor1 FOR 'SELECT id, merkki FROM tuotteet WHERE ' p_ehto; LOOP FETCH cursor1 INTO apu_id, apu_merkki; EXIT WHEN cursor1%notfound; DBMS_OUTPUT.PUT_LINE ( TO_CHAR (apu_id) ', ' apu_merkki); END LOOP; CLOSE cursor1; END; 26
OPEN FOR & BULK COLLECT CREATE OR REPLACE PROCEDURE tuote_proc ( p_ehto IN VARCHAR2) IS TYPE ctype IS REF CURSOR; cursor1 ctype; TYPE id_taulu_tyyppi IS TABLE OF NUMBER; TYPE merkki_taulu_tyyppi IS TABLE OF VARCHAR2; apu_idt id_taulu_tyyppi; apu_merkit merkki_taulu_tyyppi; BEGIN OPEN cursor1 FOR 'SELECT id, merkki FROM tuotteet WHERE ' p_ehto; FETCH cursor1 BULK COLLECT INTO apu_idt, apu_merkit; CLOSE cursor1; END; 27
Record-Based DML & DML Returning Values
Record-Based DML Insert-käskyssä voi käyttää arvolistana muuttujien sijasta tietuetta DECLARE as_tietue asiakkaat%rowtype; BEGIN as_tietue.id := 120; as_tietue.nimi := 'ABC OY'; as_tietue.lahios := 'Kauppakatu 12'; as_tietue.kaupunki := 'FORSSA'; as_tietue.kirjpvm := SYSDATE; as_tietue.sotu := NULL; as_tietue.kengannumero := 37; as_tietue.maa := 'SUOMI'; INSERT INTO asiakkaat VALUES as_tietue; END; 29
Record-Based DML Update-käskyssä voi tietueen avulla päivittää rivin syntaksi: UPDATE <table_name> SET ROW = <record_name>; BEGIN... UPDATE asiakkaat SET ROW = as_tietue;... END; 30
DML Returning Values Insert, Update ja Delete-käskyt palauttavat tietoa niistä riveistä, joihin niiden suoritus on kohdistunut Returning optio määrittelee tietojen talletuspaikan (esim. muuttujalista) esimerkkinä Insert-käskyn syntaksi: INSERT INTO <table_name> (column_list) VALUES (values_list) RETURNING <value_name> INTO <variable_name>; 31
DML Returning Values DECLARE apu1 VARCHAR2(30); apu2 VARCHAR2(30); apu3 VARCHAR2(30); BEGIN UPDATE asiakkaat SET nimi = 'SAARELA', kaupunki = 'RAUMA', maa = 'SUOMI' WHERE kaupunki = 'LAITILA' RETURNING substr(nimi, 1,3), kaupunki, substr(maa, 1, 1) INTO :apu1, :apu2, :apu3; END; 32
Returning Values ja funktiot Insert-käsky voi palauttaa yksittäisen funktion arvon funktion arvo johdetaan niistä riveistä, joihin käsky kohdistuu DECLARE duunari_lkm number(4);... BEGIN INSERT INTO duunarit SELECT * FROM tyontekijat RETURNING count(id) INTO duunari_lkm; END; / 33
Returning Values ja funktiot annetaan normaali palkankorotus ja katsotaan samalla, miten kalliiksi se tulee DECLARE palkka_summa NUMBER(9,2);... BEGIN UPDATE tyontekijat SET palkka = palkka * 1.5 RETURNING SUM(palkka) INTO palkka_summa; END; / 34
Käännöksiin liittyviä muutoksia
Conditional Compilation mahdollistaa vain haluttujen PL/SQL-koodinpalojen poimimisen mukaan moduulin käännettyyn versioon samasta moduulista voidaan muodostaa eri käännöstuloksia eri ympäristöihin voi pienentää käännetyn ohjelmakoodin kokoa ja nopeuttaa suoritusta perustuu $$-symbolin käyttöön ehdollisuus toteutetaan $IF-$THEN-$ELSE syntaksilla DBMS_PREPROCESSOR-paketti 36
Conditional Compilation CREATE OR REPLACE PROCEDURE debug (p_text IN VARCHAR2) IS $IF $$debug_on $THEN l_text VARCHAR2(32767); $END BEGIN $IF $$debug_on $THEN $IF DBMS_DB_VERSION.VER_LE_10_1 $THEN l_text := SUBSTR(p_text, 1,233); $ELSE l_text := p_text; $END... 37
Conditional Compilation $IF $$show_date $THEN DBMS_OUTPUT.put_line(TO_CHAR(SYSDATE, 'DD-MON-YYYY HH24:MI:SS') ': ' l_text); $ELSE DBMS_OUTPUT.put_line(p_text); $END $ELSE NULL; $END END debug; 38
Conditional Compilation moduulin käännös ALTER PROCEDURE debug COMPILE PLSQL_CCFLAGS = 'debug_on:true, show_date:true' REUSE SETTINGS; käännetyn ohjelmaversion koodin haku BEGIN DBMS_PREPROCESSOR.print_post_processed_source ( object_type => 'PROCEDURE', schema_name => 'TEST', object_name => 'DEBUG'); END; / 39
Conditional Compilation ohjelmaversion koodi PROCEDURE debug (p_text IN VARCHAR2) AS l_text VARCHAR2(32767); BEGIN l_text := p_text; DBMS_OUTPUT.put_line(TO_CHAR(SYSDATE, 'DD-MON-YYYY HH24:MI:SS') ': ' l_text); END debug; 40
Table Function PL/SQL-funktio, josta voidaan lukea tietoa samaan tapaan kuin tietokannan taulusta etuna, että PL/SQL-funktiossa voidaan muokata dataa ennen kuin se palautetaan käyttäjälle Selectkäskyllä haku funktiosta: SELECT * from TABLE(testi_1(p_parametri)); 41
Table Function Table Function palauttaa PL/SQL-taulukon määritellään tietue CREATE TYPE taulukko_tyyppi AS RECORD (id nimi NUMBER(5), VARCHAR2(30)); määritellään 2-ulotteinen taulukko CREATE TYPE par_taulukko AS TABLE OF taulukko_tyyppi; 42
Table Function Pipelined-optio kertoo Oraclelle, että funktion rivit halutaan palautuvan sitä mukaa, kun funktio saa ne muodostettua ei koko taulukkoa samalla kertaa CREATE FUNCTION testi_1 (par1 in VARCHAR2) RETURN par_taulukko PIPELINED IS... PIPE ROW käsky palauttaa funktiosta rivin kerrallaan Parallel-asetus funktiolle: lisää Parallel_enable avainsana funktion määritykseen CREATE FUNCTION testi_1 (par1 in VARCHAR2) RETURN par_taulukko PIPELINED PARALLEL_ENABLE... 43
Table Function CREATE OR REPLACE FUNCTION testi_1 (par1 IN VARCHAR2) RETURN par_taulukko PIPELINED IS CURSOR asiakashaku IS SELECT id, nimi FROM asiakkaat WHERE kaupunki = 'RAUMA'; astietue asiakashaku%rowtype; laskuri BINARY_INTEGER := 0; BEGIN... 44
Table Function BEGIN OPEN asiakashaku; FETCH asiakashaku INTO astietue; laskuri := laskuri + 1; LOOP PIPE ROW(astietue); FETCH asiakashaku INTO astietue; EXIT WHEN asiakashaku%rowcount = 3; END LOOP; CLOSE asiakashaku; RETURN; END; / 45
Kiitos, hyvää seminaaria ja hyvää kesää! kari.aalto@saaristonit.fi