FÖ 12: Databaskursen 1. Lagrade procedurer 2. Fördelar med procedurer 3. Parametrar 4. Vanliga fel 5. Lagrade funktioner 6. Skillnad mellan procedurer och funktioner 7. Triggrar 8. Användningsområde 9. :new och :old -värden 10. Triggerns olika delar 11. Olika typer av triggrar 12. Kodexempel 1 Pär Douhan, pdo@du.se
Stored procedures Lagrade procedurer 2
Lagrade procedurer En lagrad procedur är ett namngivet PLSQL-block som kan: 1. Lagras i databasen 2. Ta emot parametrar 3. Anropas av en applikation, 4. Eller ett annat PLSQL-block Procedur anrop Explicit exekvering PLSQL- kod Oracle 3
En enkel procedur Världens enklaste procedur: create procedure minproc as null; -- den gör ingenting... Procedur: minproc PLSQL- kod eller is (spelar ingen roll) Oracle grant create session to role_name; grant execute ecute on minproc to role e_ name; 4
Fördelar 1. Modularisering Skriv små hanterbara procedurer som tillsammans kan bygga ett komplext program. Detta medför att procedurerna är lätta att modifiera och att dela mellan olika applikationer. 2. Återanvändning Eftersom de lagras i databasen kan de användas av flera olika applikationer, t. ex. webbservrar. 3. Inkapsling Vi kan se en procedur som en svart låda. Vi vet vad den heter, vad den gör och vilka parametrar den tar emot. 4. Säkerhet Vi kan sätta upp vår applikation så att det enda sättet att komma åt data är via våra procedurer, d.v.s. via våra API:er.(Application Programming Interface). 5. Underhåll S.P.O.D. (Single Point of Definition)Vi behöver inte ändra SQL och PLSQL på flera ställen. 5
Irriterande create procedure goaway is dbms_output.put_line('go away!'); error at line 1 ORA-00955: Name is already in use by another object... Lösning: create or replace procedure goaway Satsen or replace fungerar för procedurer, funktioner, triggrar och vyer. 6
Anropa en procedur create or replace procedure goaway is dbms_ output.put p _ line('take a walk!'); Från ett PLSQL-block: goaway; Från Oracle's klientprogram SQL Plus eller SQL Developer: exec goaway; execute goaway; 7
Syntax Syntax för att skapa en lagrad procedur: create [or replace] procedure namn [optional = ej tvingande] [(parameter1,parameter2,...)] is eller as [lokala variabeldeklarationer] exekverbara SQL eller PLSQL-satser; exception -- OBS! skriv inte declare 8
Parametrar Anroparen av en procedur kan skicka k med parametrar (värden) äd som proceduren kan använda. anropa en procedur = invoke a procedure, call a procedure Det finns tre olika modes eller tillstånd på parametrar. Dessa är: 1. in 2. out 3. in out Kommer inte att tas upp på denna kurs. in-parametrar är s.k. read only parametrar. De kan bara läsas av proceduren, ej modifieras. 9
Kompileringsfel i l *?!!***?? Vi skapar något som medför kompileringsfel: create or replace procedure printnamn( p_namn in varchar2) is p_namn := 'Olle'; dbms_output.put_line(p_namn);? PROCEDURE PRINTNAMN compiled Errors: check compiler log Hur ska vi få reda på vilka fel vi har gjort? 10
Visa loggen! Vi måste titta i compiler log. Hur gör vi det? create or replace procedure printnamn( p_namn in varchar2) is p_namn := 'Olle'; dbms_output.put_line(p_namn); OK! PROCEDURE PRINTNAMN compiled Errors: check compiler log Show errors; 51 PLS-00363: expression 'P_NAMN' cannot be used as an assignment target 51 PLSQL: Statement ignored Eller så kan vi visa loggen i SQL Developer genom: view - log, eller CTRL + SHIFT + L 11
Exempel create or replace procedure createnewcustomer( p_fnamn in kund.fnamn%type, -- parameter 1 p_enamn in varchar2) -- parameter 2 as v_knr number(6); OBS! Ingen längd på select seq_knr.nextval datatypen! into v_knr from dual; insert into kund(knr,regdatum,fnamn,enamn) values(v_knr,sysdate,p_fnamn,p_enamn); commit; -- glöm inte att ta hand om transaktionen... p_enamn := 'Carl-Henrik'; Förbjudet! Read Only 12
Anropa createnewcustomer t createnewcustomer p_fnamn p_enamn Den skapar en ny rad i tabellen kund. Vi måste skicka med förnamn och efternamn när vi anropar den. parameter 1 parameter 2 createnewcustomer('hans','rosendahl'); -- parametrarna måste vara i rätt ordning 13
Vanliga fel De tre vanligaste felen enligt Oracle: 1. Fel antal parametrar i anropet 2. Fel ordning od gpå parametrarna a a a 3. Fel datatyp på parametrar Vid problem. Kontrollera detta först! 14
Stored functions Lagrade funktioner 15
Stored functions Funktioner är precis som procedurer, namngivna PLSQL-block PLSQLbl som lagras i databasen. Samma regler gäller för funktioner som för procedurer med avseende på hur vi: 1. Skapar dem. 2. Skickar parametrar till dem. 3. Delar ut behörighet till dem. Den huvudsakliga skillnaden mellan procedurer och funktioner är att funktioner måste returnera ett värde. Detta värde kan vara av enkel datatyp, som number eller varchar2, eller en komplex datatyp, t. ex. en record eller en PLSQL tabell. 16
En enkel funktion create or replace function getgoaway return varchar2 is return 'Keep walking!'; Tala om vilken datatyp som funktionen skall returnera. Se till att returnera något med rätt datatyp. Vid anrop av funktionen måste returvärdet fångas: declare v_text varchar2(20); v_text := getgoaway; -- returvärdet fångas i v_text dbms_output.put_line(v_text); 17
Testa att den fungerar När vi har skapat en funktion så måste vi kontrollera att den fungerar: select getgoaway from dual; GETGOAWAY ------------- Keep Walking! Den verkar fungera! 18
Uppgift ARTIKEL artnr artnamn varumärke lagerantal pris 1 Såskastrull Sofoni 5 498 2 Traktörpanna Hackman 13 795 3 Atlantis kastrull Demeyere 13 2999 4 Opera Såskastrull i koppar 18 cm Ruffoni 2 2599 5 Prima Matera Såskastrull i koppar de Buyer 2 2595 Uppgift: Skriv en lagrad funktion som tar ett artnr som inparameter. Funktionen ska sedan returnera pris på den artikeln som har samma artnr som funktionens inparameter. 19
Skapa funktionen getpris create or replace function getpris( p_artnr in artikel.artnr%type) return number as v_pris artikel.pris%type; select pris into v_pris from artikel where artnr = p_artnr; return v_pris; exception when no_ data_ found then return -1; en in-parameter Om artikeln inte finns 20
Anropa getpris create or replace procedure skrivutpris( p_artnr in artikel.artnr%type) anropa getpris as dbms_output.put_line('artikel: ' p_artnr 'kostar: ' getpris(p_artnr)); Anropa proceduren: skrivutpris(5); Artikel: 5 kostar: 2595 21
Ti Triggers Triggrar 22
Ti Triggrar Triggrar är namngivna block med PLSQL-kod som exekverar när vissa fördefinierade händelser inträffar. Triggrar har s.k. implicit exekvering. Detta innebär att Oracle exekverar dem automatisk, d.v.s. de går inte att anropa. Ti Trigger fixasaldo Oracle PLSQL-kod 23
Regler för användning Använd ti triggrar för att: 1. Förhindra ogiltiga transaktioner 2. Garantera, att när en viss händelse inträffar, så utförs relaterade händelser automatiskt Använd inte triggrar för att: 1. Upprätthålla constraints (PK, FK etc.) Varning! 1. Skapa inte rekursiva triggers (triggrar som startar sig själva) 2. Använda aldrig TCL kommandona commit eller rollback i en trigger eller procedur som anropas av en trigger. 3. Detta måste skötas av den T som sätter startar triggern. 4. Begränsa storleken till max 60 rader kod mellan och end. Behövs det mer kod, så skapa en procedur och anropa den från triggern. 24
Uppgift: Skapa ti trigger KUND knr fnamn enamn stad 56482 Rolf Björk Borlänge 89658 Malin Ek Borlänge 58476 Jossef Mdoud Borlänge Uppgift: Skriv en trigger som formaterar för- och efternamn så att dessa alltid lagras, med stor begynnelsebokstav och resten gemener, i databasen. 'ErIK' 'MaGNUssON' 58477 'borlänge' Before new values :old.fnamn = NULL :old.enamn = NULL :old.knr = NULL :old.stad = NULL insert into kund(knr,fnamn,enamn,stad) values(58477,'erik','magnusson','borlänge'); commit; :new.fnamn = 'ErIK' :new.enamn = 'MaGNUssON' :new.knr = 58477 :new.stad = 'borlänge' :new = "Det nya som är på väg in till tabellen" 25
Skapa triggern biufer_kund KUND knr fnamn enamn stad 56482 Rolf Björk Borlänge insert into kund(knr,fnamn,enamn,stad),e a,stad) values(58477,'erik','magnusson','borlänge'); commit; 89658 Malin Ek Borlänge 58476 Jossef Mdoud Borlänge 58477 Erik Magnusson Borlänge 'ErIK' 'MaGNUssON' 58477 'borlänge' new values create or replace trigger biufer_kund before insert or update of fnamn, enamn, stad 'Erik' 'Magnusson' on kund for each row :new.fnamn := initcap(:new.fnamn); it :new.enamn := initcap(:new.enamn); :new.stad := initcap(:new.stad); 26 58477 Triggern formaterar data innan den hamnar i tabellen 'Borlänge' new values
Triggerns olika delar En trigger består av fyra olika delar: 1) Trigger name 2) Triggering statement 3) Trigger restriction 4) Triggered action 27
Ti Trigger name Trigger name: Namnet på triggerobjektet biufer_kund Använd alltid en namngivningskonvention biufer? Before insert or update for each row Trigger Happy 28
Ti Triggeringi statement t t Triggering statement: Händelsen (eventet) som får Oracle att exekvera triggern. En sådan händelse kan vara: DML-satser: insert, update eller delete på tabeller och vissa vyer. DDL-satser: create alter eller drop på något databasobjekt. "start up" eller "shut down" av Oracle instance. Olika typer av systemfel. Olika systemhändelser, t. ex. inloggning. i inte på kursen kolumn tabell before insert or update of fnamn,enamn,stad on kund 29
Ti Trigger restriction: titi studera! KUND knr fnamn enamn stad 56482 Rolf Björk Borlänge 89658 Malin Ek Borlänge insert into kund(knr,fnamn,enamn,stad) values(58478,'malin','ekholm','mora'); commit; 58476 Jossef Mdoud Borlänge 'Malin' 'ekholm' 58477 Erik Magnusson Borlänge 58478 'Mora' new values new.stad = 'Mora' create or replace trigger biufer_stad_kund before insert or update on kund for each row when(upper(new.stad) not in('borlänge')) -- when() blir, i detta exempel, sant! raise_ application _ error(-20001,'vi tillåter bara kunder som bor i Borlänge!'); 30
Ti Trigger restriction titi Trigger restriction: Trigger restriction: when(upper(new.stad) ( not in('borlänge')) ')) Triggerns kod, det som finns mellan och end, kommer bara att exekveras när "trigger restriction" evalueras till true, d.v.s. när villkoret inom parenteserna i when() är sant. 31
Ti Triggered action Ti Triggered action: Koden mellan och end, d.v.s. det arbete som triggern utför. I våra exempel: :new.fnamn := initcap(:new.fnamn); :new.enamn := initcap(:new.enamn); :new.stad := initcap(:new.stad); och: raise_application_error(-20001,'vi tillåter bara kunder som bor i Borlänge!'); 32
Olika typer av triggers Det finns fem olika typer av triggers: 1) Statement triggers (fire_only_once_triggers) 2) Row triggers (fire_for_each_row_triggers) 3) Instead of triggers 4) System event triggers 5) User event triggers inte på kursen 33
Statement t t triggers En statement trigger kommer bara att exekvera sin kod en gång. create or replace trigger biud_kund before insert or update or delete on kund declare no_way exception; if user not in('douhan') then raise no_way; end if; exception when no_ way then raise_application_error(-20007,'obehörig!'); En statement tt tti trigger har inte tillgång till new och old-värden. Vi skriver inte for each row i en statement trigger. Triggern stoppar den T som startar den 34
Loggning Vi kan logga förändringar i en tabell med en trigger: create table kund_kopia as select * from kund; create table kund_kopia_logg( vem varchar2(30), när date); create or replace trigger aiud_kund_kopia after insert or update or delete on kund_kopia insert into kund_kopia_logg(vem,när) values(user,sysdate); Om det sitter flera triggers av samma typ på en tabell, så avfyras de i en slumpvis ordning! OBS! Inget commit 35
Kontrollera vilken DML Bestämma vilken DML-sats som är aktiv. create or replace trigger aiud_kund_kopia after insert or update or delete on kund_kopia declare v_händelse kund_kopia_logg.händelse%type; kopia if inserting then v_händelse := 'insert'; elsif updating then v_händelse := 'update'; elsif deleting then v_ händelse := 'delete'; end if; insert into kund_kopia_logg(vem,när,händelse) values(user,sysdate,v_händelse); alter table kund_kopia_logg add(händelse varchar2(20)); This is really cool! 36
Before eller After Skall vi använda before eller after? Går vilket som. Låt förnuftet avgöra! Säkerhetskontroll k t before Loggning after 37
Row ti triggers En radtrigger: 1. Exekverar en gång för varje rad som påverkas av transaktionen som startar t ti triggern. update kund set rabatt = rabatt * 0.95; 2. Krav: for each row måste vara med. Om det är 15000 rader i tabellen kund, så kommer triggern att exekvera 15000 gånger. 3. Har tillgång till :new och :old -referenser. insert har tillgång till :new delete har tillgång g till :old update har tillgång till :new och :old 38
The Oracle way: Exempel på en radtrigger som kan användas för att fixa en automatisk primärnyckel till en tabell: create table keynote( id number(9) primary key, data varchar2(200)); create sequence seq_id; create or replace trigger bifer_keynote before insert on keynote for each row select seq_id.nextval into :new.id from dual; This is also really cool! 39
The End 40