Aneb jak co nejrychlejc začít s Oraclem.
Prostě asi protože jsem sám hledal nějaký příklad a nedařilo se mi nějaký najít, tak jsem se rozhodl, že dám svůj výtvor v plen světu :-) A jednak i sám pro sebe, jelikož co si nemapíšu,to jako bych něměl :-) Můžete si celou tu nádheru stáhnout jako zatatovaný balík, ale pak si přečtěte to co je na spodních řádkách téhle stránky.
Tak nějak už čekám, že ten kdo tohle bude číst tuší co to je tabulka, Integritní omezení a spol...
Klíč v tabulce, na který se odkazuje položka z jiné tabulky. Porušení cizího klíče je v Oracle Databaze error 02291. Cizí klíč lze definovat také tak, aby se po porušení odstranily záznamy, které na daný klíč odkazovali (ON DELETE CASCADE), nebo aby se nastavily na NULL (ON DELETE SET NULL).
Požadavek, aby každý řádek v daném sloupci byl unikátní. Porušení unikátnosti je v Oracle Databaze error 00001.
Procedura která se volá před nebo po provedení nějaké akce na tabulce. Akce jsou Update, Delete,Insert. Používají se k hlídání toho, na co nestačí integritní omezení.
Oběkt který vrací při každém dalším volání následující číslo. Spolu s triggery se dají použí na "nahrazení" typu "auto_increment".
Balík procedur a funkcí v PL-SQL, většinou vztahující se k nějaké tabulce. Pokud by nekoha zajímalo víc, tak pěkné povídání o procedurách v plsql je tady Na stránce není copyright, takže jsem si ji dovolil ozrcadlit sem.
Pomocný výpočet databázového stroje, který na základě statistiky posuzuje, jak si ukládat data.
No to asi programator ví, co to je vyjimka, ale co to je v Oraclu? No pokud provede aplikace něco, co by provádět neměla. Mohou to být:
A možná ještě něco.Pokud si vyvoláváme vlastní vyjimky,tak můžou být v rozmezí -20000 a -20999. Podstatné je, že vyjimku si můžeme odchytit a ošetřit v EXCEPTION části FUNKCE /PROCEDURY. Vyjimky jsou buď už pojmenované "od přírody", nebo si je můžeme pojmenovat, tj. číslu přidělit nějaký lidsky přijatelný identifikátor, a to pomoci PRAGMA EXCEPTION_INIT, tj, např.
PRAGMA EXCEPTION_INIT (EXC_kolidujici_rezervace, -20042);
Za tohle fakt neručím prostě to berte tak,že dávám k nahlédnutí svoje zápisky.To schema je tu jen tak pro nahladnuti , s korektnim er to asi nema moc spolecneho.
Jde o takovou jakoby malou databázi vybavení sportovního klubu. Na databázi si klademe následující požadavky:
Tohle je moje řešení
Struktura bude tvořena sadou tabulek, tabulky budou mít jako primarní klíč integer, ikdyž by se třeba nabízel jiný kandidátní klíč, kvůli urychlení vzhledávání a indexování. Omezení můžeme definovat buď hned v době tvorby tabulek, nepo pomocí "ALTER TABLE xxx ADD CONSTRAINT ...", po vztvoření celého schématu. První y způsob je přehlednější, druhý má tu výhodu, že tabulky jsou již vztvořeny, a tak nezáleží na pořadí, ve kterém jsou jednotlivé příkazy volány (nejde se odvol8vat na ciz9 kl94 tabulky, kter8 neexistuje). Cizí klíče by měli uržovat integritu celé databáze. Indexy jsou nutné pokud to má celé nějak fungovat. Je víc než vhodné nadefinovat indexy pres cizí klíče, jinak databáze stráce spoustu času při každém "DELETE",zvláště Oracle se svoji specialitou tedy zamykáním referencovaných tabulek. To by Vás uživatelé hnali.
--Zapoctova prace na predmet DATABAZOVE APLIKACE, ODLADENO PRO ORACLE 9 ------------------------------------------------------------------------------- --------------------------------------- --TABULKA CLEN (jsou zde ulozeni clenove oddilu) --------------------------------------- CREATE TABLE clen ( id NUMBER NOT NULL, login VARCHAR2(10) NOT NULL, -- je kandidatnim klicem - vytvari se dale unikatni email VARCHAR2(100) NOT NULL, jmeno VARCHAR2(40) NOT NULL, prijmeni VARCHAR2(40) NOT NULL, -- CONSTRAINT PK_clen_id PRIMARY KEY (id), CONSTRAINT UN_clen_login UNIQUE (login) ); --------------------------------------- --TABULKA TYP (jsou zde ulozeny typy vybaveni, kterymi oddil disponuje) --------------------------------------- -- typ vybaveni, muze jit bud o macky, cepin, helmu, hulky. -- odkazuje se na ni tabulka vybavani. CREATE TABLE typ ( id NUMBER NOT NULL, --primarni klic nazev VARCHAR2(20) NOT NULL, -- macka, cepin... kandidatni klic pro snazzsi praci uzivatele poznamka VARCHAR2(256), --neco jako "nevhodne pro tezzsi tury" -- CONSTRAINT PK_typ_id PRIMARY KEY (id), CONSTRAINT UN_typ_nazev UNIQUE (nazev) ); --------------------------------------- --TABULKA VYBAVENI (jsou zde ulozeny jednotlive kusy vybaveni) --------------------------------------- --tabulka s oddilovym vybavenim CREATE TABLE vybaveni ( id NUMBER NOT NULL, --primarni klic id_typ NUMBER NOT NULL, -- id_typu id_clena NUMBER NOT NULL, --id clena stanoveneho jako spravce pocet_vydani NUMBER NOT NULL,--sledovani aby se nacini optrebovavalo stejnomerne poznamka VARCHAR2(256), -- CONSTRAINT PK_vybaveni_id PRIMARY KEY (id), CONSTRAINT FK_vybaveni_id_typ FOREIGN KEY (id_typ) REFERENCES typ (id), CONSTRAINT FK_vybaveni_clen_id FOREIGN KEY (id_clena) REFERENCES clen (id) ); --indexy pres cizi klice. create index IDX_vybaveni_typ on vybaveni(id_typ); create index IDX_vybaveni_spravce on vybaveni(id_clena); --------------------------------------- --TABULKA VYPUJCKY (jsou zde informace o momentalne vypujcenem vybaveni) --------------------------------------- --primarni klic je id_vybaveni CREATE TABLE vypujcky ( id_clena NUMBER NOT NULL, --id clena, ktery si vypujcil id_vybaveni NUMBER NOT NULL, -- uniktani, tedy bude primarnim klicem datum_vypujceni DATE NOT NULL, -- kdy pujceno datum_navraceni DATE NOT NULL, --dokdy vratit -- CONSTRAINT PK_vypujcky_id_vyb PRIMARY KEY (id_vybaveni), CONSTRAINT FK_vypujcky_id_vybaveni FOREIGN KEY (id_vybaveni) REFERENCES vybaveni (id), CONSTRAINT FK_vypujcky_clen_id FOREIGN KEY (id_clena) REFERENCES clen (id) ); --indexy pres cizi klice --create index IDX_vypujcky_id_vybav on vypujcky(id_vybaveni); --uz je primarni klic, takze si ho oracle inxuej sam. create index IDX_vypujcky_id_clena on vypujcky(id_clena); --index, pres ktery hledaji casto poheldy create index IDX_vypujcky_vratit_do on vypujcky(datum_navraceni); --------------------------------------- --TABULKA REZERVACE (jsou zde ulozeny informace o rezervacich vybaveni na urcitou dobu urcitymi cleny) --------------------------------------- -- rezervace, klic je kombinace id_clena, id_vybaveni CREATE TABLE rezervace ( id_clena NUMBER NOT NULL, id_vybaveni NUMBER NOT NULL, -- zabiraji se konkretni macky ne nejake, -- kazdy clen muze mit svoje oblibene, velikost... datum DATE NOT NULL, -- poznamka o tom, kdy doslo k rezervaci od_datum DATE NOT NULL, -- rezervace na dobu od do_datum DATE NOT NULL, --rezervace na dobu do -- CONSTRAINT PK_rezervace_id_cl_id_vyb PRIMARY KEY (id_vybaveni,id_clena), CONSTRAINT FK_rezervace_id_vybaveni FOREIGN KEY (id_vybaveni) REFERENCES vybaveni (id) ON DELETE CASCADE, CONSTRAINT FK_rezervace_id_clena FOREIGN KEY (id_clena) REFERENCES clen (id) ON DELETE CASCADE ); --indexy pres cizi klice create index IDX_rezervace_id_clena on rezervace(id_clena); create index IDX_rezervace_id_vybaveni on rezervace(id_vybaveni); --------------------------------------- --TABULKA VYPUJCKY_LOG (jsou zde informace o minulosti vypujcek a rezervaci) --------------------------------------- --primarni klic je id CREATE TABLE vypujcky_log ( id NUMBER NOT NULL, --primarni klic datum DATE NOT NULL, --datum udalosti id_clena NUMBER NOT NULL, id_vybaveni NUMBER NOT NULL, status VARCHAR2(1) NOT NULL, -- P pujceno, V vraceno R rezervovano poznamka VARCHAR2(64), -- poznamka, napr vratil se zlomenym hrotem, vratil pozde, pokuta 20kc, a pod. CONSTRAINT PK_vypujcky_log_id PRIMARY KEY (id), CONSTRAINT FK_vypujcky_log_id_vybaveni FOREIGN KEY (id_vybaveni) REFERENCES vybaveni (id) ON DELETE CASCADE, CONSTRAINT FK_vypujcky_log_id_clena FOREIGN KEY (id_clena) REFERENCES clen (id) ON DELETE CASCADE ); --indexy pres cizi klice create index IDX_vypujcky_log_id_vyb on vypujcky_log (id_vybaveni); create index IDX_vypujcky_log_id_clena on vypujcky_log (id_clena); --tohle se casto hleda v pohladech. create bitmap index IDX_vypujcky_log_status on vypujcky_log (status);
Potom je potřeba dodělat triggery a sekvence na to, na co integritní omezení nestačila.
--tabulka vybaveni CREATE SEQUENCE SEQ_vybaveni_id ; CREATE OR REPLACE TRIGGER TRG_bef_ins_row_vybaveni_id BEFORE INSERT ON vybaveni FOR EACH ROW BEGIN SELECT SEQ_vybaveni_id.NEXTVAL INTO :NEW.id FROM DUAL; END; / --tabulka clen CREATE SEQUENCE SEQ_clen_id; CREATE OR REPLACE TRIGGER TRG_bef_ins_row_clen_id BEFORE INSERT ON clen FOR EACH ROW BEGIN SELECT SEQ_clen_id.NEXTVAL INTO :NEW.id FROM DUAL; END; / --tabulka vypujcky_log CREATE SEQUENCE SEQ_vypujcky_log_id; CREATE OR REPLACE TRIGGER TRG_bef_ins_row_vyp_lg_id BEFORE INSERT ON vypujcky_log FOR EACH ROW BEGIN SELECT SEQ_vypujcky_log_id.NEXTVAL INTO :NEW.id FROM DUAL; END; / --typ CREATE SEQUENCE SEQ_typ_id; CREATE OR REPLACE TRIGGER TRG_bef_ins_row_typ_id BEFORE INSERT ON typ FOR EACH ROW BEGIN SELECT SEQ_typ_id.NEXTVAL INTO :NEW.id FROM DUAL; END; / ----------------------------------------------------------------------------- --trigery zajistujici integritu dat ----------------------------------------------------------------------------- -- triggery zajistujici integritu dat tabulky vybaveni --na insert, zajisti aby pocet_vydani byl roven 0 CREATE OR REPLACE TRIGGER TRG_bef_ins_row_vybaveni BEFORE INSERT ON vybaveni FOR EACH ROW BEGIN select 0 into :new.pocet_vydani from dual; END; / CREATE OR REPLACE TRIGGER TRG_bef_upd_row_vybaveni BEFORE UPDATE OR DELETE ON vybaveni FOR EACH ROW declare xpocet_rezervaci number; xpocet_vypujcek number; BEGIN IF updating then IF (:new.pocet_vydani < :old.pocet_vydani) THEN RAISE_APPLICATION_ERROR(-20070,'Nejde snizit optotrebeni materialu!!'); END IF; END IF; --updating -- tohle jsou dost zavazne dva radky, pokud tu tohle nebude, tak se to diky constraints proste smaze a konec. -- select count(*) into xpocet_rezervaci from rezervace where id_vybaveni=:old.id; -- select count(*) into xpocet_vypujcek from vypujcky where id_vybaveni=:old.id; -- IF xpocet_rezervaci<>0 or xpocet_vypujcek<>0 then -- RAISE_APPLICATION_ERROR (-20071,'vybaveni nejde menit, pokud je prave vypujceno nebo rezervovano'); -- END IF; END ; / --kontrola sprvanych vlozeni udaju a pripadna oprava CREATE OR REPLACE TRIGGER TRG_bef_ins_upd_row_clen BEFORE INSERT OR UPDATE ON clen FOR EACH ROW declare kontrolni_login varchar2(10); BEGIN kontrolni_login := trim(:new.login); IF lower(kontrolni_login)<> kontrolni_login THEN RAISE_APPLICATION_ERROR (-20050,'Login se musi skladat pouze z malych pismen'); end if; --pozmenit vsem prvni pismeno na velke, aby se pak nejakej zakaznik neurazil :-) :new.jmeno := trim(initcap(:new.jmeno)); :new.prijmeni := trim(initcap(:new.prijmeni)); :new.email := trim(lower(:new.email)) ; --assert!!! kontrola emailu??? to bylo pracny, zavinac, kontrolovat,ze je neco pred nim, za nim alespon jedna tecka... to bude lepsi udelat nejakym reqexpem v nejakym ovladacim prvku k databazi END; / ---- triggery zajistujici integritu dat tabulky rezervace --kontrola, jestli si nekdo nedava rezervacku na neco, co neni vypujcene create or replace TRIGGER TRG_bef_ins_row_rezervace BEFORE INSERT ON rezervace FOR EACH ROW declare kdo_to_ma_pujcene clen.id%type; pocet_neslucitelnych_rezervaci number; xpocet_clen number; xpocet_vybaveni number; BEGIN IF :new.do_datum < sysdate or :new.od_datum < sysdate then RAISE_APPLICATION_ERROR(-20043, 'Nejde rezervovat na dobu v minulosti'); END IF; IF (:new.do_datum - :new.od_datum) > 30 or (:new.do_datum - :new.od_datum) < 1 then RAISE_APPLICATION_ERROR(-20041, 'Doba na kterou jde vybaveni rezervovat musi byt mezi 1 a 30 dny'); END IF; -- osetrit, aby si dva lidi nemohli rezervovat SELECT COUNT(*) into pocet_neslucitelnych_rezervaci from rezervace where (( (od_datum <= :new.do_datum and do_datum >= :new.do_datum) or (od_datum <= :new.do_datum and do_datum >= :new.do_datum) ) and id_vybaveni = :new.id_vybaveni ); IF pocet_neslucitelnych_rezervaci<> 0 then RAISE_APPLICATION_ERROR(-20042, 'Tato rezervaci koliduje s jiz zadanymi rezervacemi'); END IF; END; / -- hlida, ze vypujceni neni rezervovane, ze si nikdo neprodluzuje zapujcni dobu na vice nez sto dni CREATE OR REPLACE TRIGGER TRG_bef_ins_upd_row_vypujcky BEFORE INSERT OR UPDATE ON vypujcky FOR EACH ROW declare xpocet number; xdatum rezervace.datum%type; xid_clen vypujcky.id_clena%type; BEGIN begin --jsou nejake rezervace?? --pokud jsou nejake rezervace ... --tak kdy si to muzeme pujcit?? SELECT COUNT(*) into xpocet from rezervace where ( ( (od_datum >= :new.datum_vypujceni and do_datum <= :new.datum_navraceni) or (od_datum >= :new.datum_vypujceni and do_datum <= :new.datum_navraceni) ) and id_vybaveni = :new.id_vybaveni ); if xpocet<> 0 then --DBMS_OUTPUT.PUT_LINE ('Nalezena nejaka rezervace na dane vybaveni v danou dobu...'); if inserting then -- nekdo si neco pujcuje begin -- kdy to je mozne?? -- ...a kdyz na dane vybaveni mam nejcasnejsi rezervaci select datum into xdatum from rezervace where id_vybaveni = :new.id_vybaveni and id_clena = :new.id_clena and datum = ( select min(datum) from rezervace where id_vybaveni = :new.id_vybaveni); --a jeste to z vybaveni smazat delete from rezervace where id_vybaveni = :new.id_vybaveni and id_clena = :new.id_clena; DBMS_OUTPUT.PUT_LINE ('Existuje rezervace clena, ktery pozaduje vypujceni...'); exception when no_data_found then raise_application_error(-20065, 'Dane vybaveni jiz bylo rezervovano jinym clenem'); end; elsif updating then -- nekdo si neco prodluzuje raise_application_error(-20066, 'Vybaveni je rezervovane, vypujcni doba nelze prodlouzit.'); end if; else -- zbozi neni rezervovano -- DBMS_OUTPUT.PUT_LINE ('Vybaveni neni rezervovano pro danou dubu...'); if updating then if :old.datum_vypujceni + 100 < :new.datum_navraceni then raise_application_error(-20067, 'Celkova doba vypujcky nesmi presahnout 100 dni. '); end if; if :old.datum_navraceni < sysdate then raise_application_error(-20068, 'Vypujcni doba prekrocena. V takovem pripade neni mozno obnovit vypujcku.'); end if; end if; end if; --tohle je ale skarede a neprehledne :-) end; END; / create or replace TRIGGER TRG_aft_del_row_vypujcky after delete ON vypujcky FOR EACH ROW declare xstav_vraceni vypujcky_log.poznamka%type := 'Vraceno v casovem limitu'; BEGIN if :old.datum_navraceni < sysdate then xstav_vraceni := 'Vraceno se zpozdenim'; DBMS_OUTPUT.PUT_LINE ('POZOR VYBAVENI S ID: '||:old.id_vybaveni ||' VRACENO SE ZPOZDENIM. MELO BYT VRACENO: ' || :old.datum_navraceni); end if; insert into vypujcky_log (datum,id_clena,id_vybaveni,status, poznamka) values (sysdate, :old.id_clena, :old.id_vybaveni,'V', xstav_vraceni); -- V je vraceno END; / create or replace TRIGGER TRG_aft_ins_row_rezervace after INSERT ON rezervace FOR EACH ROW BEGIN insert into vypujcky_log (datum,id_clena,id_vybaveni,status,poznamka) values (:new.datum, :new.id_clena, :new.id_vybaveni, 'R','Rezervovano od/do :'||:new.od_datum ||'/'||:new.do_datum ); END; / create or replace TRIGGER TRG_aft_ins_row_vypujcky after INSERT ON vypujcky FOR EACH ROW BEGIN insert into vypujcky_log (datum,id_clena,id_vybaveni,status,poznamka) values (:new.datum_vypujceni, :new.id_clena, :new.id_vybaveni, 'P', 'Vypujceno od/do :'||:new.datum_vypujceni ||'/'||:new.datum_navraceni); --zvysit miru opotrebovani vybaveni. update vybaveni set pocet_vydani = pocet_vydani + 1 where id = :new.id_vybaveni; END; / CREATE OR REPLACE TRIGGER TRG_bef_del_upd_row_typ BEFORE UPDATE OR DELETE ON typ FOR EACH ROW declare xpocet_vypujcek number; xpocet_rezervaci number; BEGIN select count(*) into xpocet_vypujcek from vypujcky where id_vybaveni in (select id from vybaveni where id_typ = :old.id); select count(*) into xpocet_rezervaci from rezervace where id_vybaveni in (select id from vybaveni where id_typ = :old.id); IF (xpocet_vypujcek<> 0) or (xpocet_rezervaci<> 0) then raise_application_error(-20090, 'Typ nejde menit ani mazat pokud je rezervovan nebo vypujcen'); END IF; END; /
Pro aplikaci je ideální napsat si balíky procedur a funkcí, protože v nich můžeme korektně reagovat na chyby vygenerované v triggerech a jinak generovaných databází. Krom toho usnadňují život uživatelům a o to tady přeci jde :-)
CREATE OR REPLACE PACKAGE dbp_typ AS PROCEDURE pridej( xnazev typ.nazev%type, xpoznamka typ.poznamka%type ); procedure odeber(xid typ.id%type); procedure odeber_podle_nazvu(xnazev typ.nazev%type); procedure zmen( xid typ.id%type default null, xnazev typ.nazev%type default null, xpoznamka typ.poznamka%type default null ); function id_podle_nazvu(xnazev typ.nazev%type) return typ.id%type; END; / CREATE OR REPLACE PACKAGE BODY dbp_typ AS EXC_prave_prop_or_rezer EXCEPTION; EXC_prilis_dlouha_hodnota EXCEPTION; EXC_cizi_klic EXCEPTION; --provazani s chybami vyvolavanymi triggery PRAGMA EXCEPTION_INIT (EXC_prave_prop_or_rezer, -20060); --provazani se standardnimi chybami PRAGMA EXCEPTION_INIT (EXC_prilis_dlouha_hodnota, -01401); PRAGMA EXCEPTION_INIT (EXC_cizi_klic, -02291); PROCEDURE pridej( xnazev typ.nazev%type, xpoznamka typ.poznamka%type ) AS BEGIN insert into typ (nazev , poznamka) values (xnazev ,xpoznamka); DBMS_OUTPUT.PUT_LINE ('Typ vybaveni'''||xnazev||''' byl pridan.'); EXCEPTION when EXC_prilis_dlouha_hodnota then RAISE_APPLICATION_ERROR (-20101,'Vkladana hodnota je pro sloupec prilis dlouha.'); END; procedure odeber(xid typ.id%type) as begin --kontrola,ze tento typ neni vypujcen nebo rezervovan provadi triggery delete from typ where id = xid; exception when EXC_cizi_klic then RAISE_APPLICATION_ERROR (-20111,'Existuje vybaveni daneho typu,typ nejde odstranit'); end; procedure odeber_podle_nazvu(xnazev typ.nazev%type) as xid typ.id%type; begin xid := dbp_typ.id_podle_nazvu(xnazev); dbp_typ.odeber(xid); end; procedure zmen( --kontrola,ze tento typ neni vypujcen nebo rezervovan provadi triggery xid typ.id%type default null, xnazev typ.nazev%type default null, xpoznamka typ.poznamka%type default null )as begin update typ set --pokud se nenajde, pouzit defaultni hodnoty nazev = decode(xnazev,null,nazev,'null',null, xnazev), poznamka = decode(xpoznamka,null,poznamka,'null',null, xpoznamka) where id=xid; end; function id_podle_nazvu(xnazev typ.nazev%type) return typ.id%type as xid typ.id%type; begin select id into xid from typ where nazev = xnazev; return xid; EXCEPTION WHEN NO_DATA_FOUND THEN RAISE_APPLICATION_ERROR (-20110,'Typ nazvu '''||xnazev||''' neexistuje.'); return null; end; END; --dbp_typ / CREATE OR REPLACE PACKAGE dbp_clen AS PROCEDURE pridej( xlogin clen.login%type, xemail clen.email%type, xjmeno clen.jmeno%type, xprijmeni clen.prijmeni%type ); procedure odeber(login clen.login%type); procedure odeber_id(xid clen.id%type); procedure zmen( xlogin clen.login%type, -- ten podle ktereho se vyhledava, menit nejde xemail clen.email%type default null, xjmeno clen.jmeno%type default null, xprijmeni clen.prijmeni%type default null ); procedure zmen_id( xid clen.id%type, -- ten podle ktereho se vyhledava, menit nejde xlogin clen.login%type default null, xemail clen.email%type default null, xjmeno clen.jmeno%type default null, xprijmeni clen.prijmeni%type default null ); function id_podle_loginu(xlogin clen.login%type) return clen.id%type; END; / CREATE OR REPLACE PACKAGE BODY dbp_clen AS EXC_porusena_unikatnost EXCEPTION; EXC_prilis_dlouha_hodnota EXCEPTION; EXC_neexistujici_zaznam EXCEPTION; EXC_existuji_vypuj_or_rez EXCEPTION; PRAGMA EXCEPTION_INIT (EXC_porusena_unikatnost, -00001); PRAGMA EXCEPTION_INIT (EXC_prilis_dlouha_hodnota, -01401); --pragma exception_init (EXC_existuji_vypuj_or_rez, -20071); pragma exception_init (EXC_existuji_vypuj_or_rez, -02292); -- pridani noveho clen PROCEDURE pridej( xlogin clen.login%type, xemail clen.email%type, xjmeno clen.jmeno%type, xprijmeni clen.prijmeni%type ) AS BEGIN insert into clen (login,email,jmeno,prijmeni) values (xlogin,xemail,xjmeno,xprijmeni); DBMS_OUTPUT.PUT_LINE ('Uzivatel'''||xlogin||''' byl pridan.'); EXCEPTION when EXC_porusena_unikatnost then -- unikatni klic je pouze na loginu RAISE_APPLICATION_ERROR (-20121,'Clen s loginem '''||xlogin||''' jiz existuje'); when EXC_prilis_dlouha_hodnota then RAISE_APPLICATION_ERROR (-20101,'Vkladana hodnota je pro sloupec prilis dlouha.'); END; -- odebrani clen, podle klice id procedure odeber_id(xid clen.id%type) as begin delete from clen where id = xid; exception when EXC_neexistujici_zaznam then -- odpropagovano funkci uzivatel_id(login) raise_application_error(-20122,'Clen s takovym id neexistuje, nejde smazat'); when EXC_existuji_vypuj_or_rez then raise_application_error(-20123, 'Nelze vymazat clena, ktery ma neco pujceno/rezervovano/je spravce!'); end; -- pokud zname login procedure zmen( xlogin clen.login%type, -- ten podle ktereho se vyhledava, menit nejde xemail clen.email%type default null, xjmeno clen.jmeno%type default null, xprijmeni clen.prijmeni%type default null ) as xid clen.id%type; begin update clen set email = decode(xemail,null,email,'null',null, xemail), jmeno = decode(xjmeno,null, jmeno, 'null', null, xjmeno), prijmeni = decode(xprijmeni, null, prijmeni, 'null',null, xprijmeni) where login = xlogin; exception when EXC_neexistujici_zaznam then -- odpropagovano funkci uzivatel_id(login) raise_application_error(-20124,'Uzivatel s loginem '''||xlogin||''' neexistuje.'); when EXC_prilis_dlouha_hodnota then RAISE_APPLICATION_ERROR (-20125,'Vkladana hodnota je pro sloupec prilis dlouha.'); end; -- pokud zname id. je tak mozno i menit login!!! procedure zmen_id( xid clen.id%type, -- ten podle ktereho se vyhledava, menit nejde xlogin clen.login%type default null, xemail clen.email%type default null, xjmeno clen.jmeno%type default null, xprijmeni clen.prijmeni%type default null ) as begin update clen set email = decode(xemail,null,email,'null',null, xemail), jmeno = decode(xjmeno,null, jmeno, 'null', null, xjmeno), prijmeni = decode(xprijmeni, null, prijmeni, 'null',null, xprijmeni), login = decode (xlogin, null, login,'null',null,xlogin) where id = xid; exception when EXC_neexistujici_zaznam then raise_application_error(-20122,'Uzivatel s danym id neexistuje.'); when EXC_prilis_dlouha_hodnota then RAISE_APPLICATION_ERROR (-20101,'Vkladana hodnota je pro sloupec prilis dlouha.'); end; -- dotaz na id clena podle daneho loginu function id_podle_loginu(xlogin clen.login%type) return clen.id%type as xid clen.id%type; begin select id into xid from clen where login=xlogin; RETURN xid; EXCEPTION WHEN NO_DATA_FOUND THEN -- toto je chyba, predpokladam pouzivani funkce original_id pri pridavani do tabulky vybaveni RAISE_APPLICATION_ERROR (-20124,'Uzivatel '''||xlogin||''' neexistuje.'); return null; END; --odebirani podle loginu clena procedure odeber(login clen.login%type) as xid clen.id%type; begin xid := dbp_clen.id_podle_loginu(login); dbp_clen.odeber_id(xid); end; END; / CREATE OR REPLACE PACKAGE dbp_vybaveni AS PROCEDURE pridej( xid_typ vybaveni.id_typ%type, xid_clena vybaveni.id_clena%type, xpoznamka vybaveni.poznamka%type default null ); procedure vloz_vybaveni_hromadne ( kolik number, login_spravce clen.login%type, ceho typ.nazev%type ); procedure odeber(xid vybaveni.id%type); --pocet pouziti jde menit akorat na vyssi cislo procedure zmen( xid vybaveni.id%type, xid_typ vybaveni.id_typ%type default null, xid_clena vybaveni.id_clena%type default null, xpocet_vydani vybaveni.pocet_vydani%type default null ); -- vybere nejmene opotrebovane vybaveni function nejvhodnejsi_podle_opotrebeni( xtyp_nazev typ.nazev%type, xod_datum DATE, xdo_datum DATE ) return vybaveni.id%type; procedure nejvhodnejsi( xtyp_nazev typ.nazev%type, xod_datum DATE, xdo_datum DATE ); --vybere nejmene opotrebovane vybaveni, ktere spravuje dany spravce return vybaveni.id%type; END; / create OR REPLACE PACKAGE BODY dbp_vybaveni AS EXC_prilis_dlouha_hodnota EXCEPTION; EXC_zaznam_vybaveni_neexistuje exception; EXC_nulova_hodnota exception; EXC_existuji_vyp_rez exception; PRAGMA EXCEPTION_INIT (EXC_prilis_dlouha_hodnota, -01401); --PRAGMA EXCEPTION_INIT (EXC_zaznam_vybaveni_neexistuje -20022); PRAGMA EXCEPTION_INIT (EXC_nulova_hodnota, -01407); --pragma exception_init (e_existuji_vypujcky, -02292); PRAGMA EXCEPTION_INIT (EXC_existuji_vyp_rez, -20071); -- interni, neni soucasti baliku... procedure id_exists(xid vybaveni.id%type) as xxid vybaveni.id%type; begin select id into xxid from vybaveni where id = xid; -- kontrola, zda tam id je, pokud ne, vyhodi se chyba, ktera se propaguje vys... exception when NO_DATA_FOUND then --propagovat chybu... raise_application_error(-20130,'Vybaveni stakovym id neexistuje',TRUE);--propagovat dal end; -- prida novy kus vybaveni PROCEDURE pridej( xid_typ vybaveni.id_typ%type, xid_clena vybaveni.id_clena%type, xpoznamka vybaveni.poznamka%type default null ) as begin insert into vybaveni ( id_typ, id_clena, poznamka ) values ( xid_typ, xid_clena, xpoznamka ); end; PROCEDURE vloz_vybaveni_hromadne ( kolik number, login_spravce clen.login%type, ceho typ.nazev%type) AS i NUMBER := 1; xid_typ vybaveni.id_typ%type; xid_spravce clen.id%type; BEGIN select typ.id into xid_typ from typ where nazev = ceho; select clen.id into xid_spravce from clen where login = login_spravce; if kolik < 1 then raise_application_error(-20195,'Pocet vkladaneho vybaveni je prilis maly'); end if; LOOP INSERT INTO VYBAVENI (id_typ,id_clena,pocet_vydani) VALUES(xid_typ,xid_spravce,0); i := i+1; EXIT WHEN i = kolik + 1; END LOOP; END; --meni vsecko ve vybaveni, vcetne mnozstvi vypujcek, na vyssi, na nizssi dat nejde (trigger)... procedure zmen( xid vybaveni.id%type, xid_typ vybaveni.id_typ%type default null, xid_clena vybaveni.id_clena%type default null, xpocet_vydani vybaveni.pocet_vydani%type default null ) as begin dbp_vybaveni.id_exists(xid); --pokud neexistuje, tak hnedka tady vyhodime vyjimku a zbytek se neprovede update vybaveni set id_clena = decode(xid_clena,null,id_clena,'null',null, xid_clena), id_typ = decode(xid_typ,null,id_typ,'null',null, xid_typ), pocet_vydani = decode(xpocet_vydani,null,pocet_vydani,'null',null, xpocet_vydani) where id=xid; end; procedure odeber(xid vybaveni.id%type) as tid vybaveni.id%type; begin select id into tid from vybaveni where id = xid; -- kontrola, zda tam id je delete from vybaveni where id = xid; -- tohle jde jen pokud nejsou nejake rezervace a nebo vypujcky. -- inak by se rezervace smazali samy zrusenim ciziho klice DBMS_OUTPUT.PUT_LINE ('vybaveni s id: '''||xid||''' bylo odebrano.'); exception when NO_DATA_FOUND then raise_application_error(-20130,'vybaveni s id '''||xid||''' neexistuje.'); when EXC_existuji_vyp_rez then raise_application_error(-20131, 'Nelze vymazat vybaveni, nekdo jej mam pujceny. Mel by jej nejdriv vratit.'); end; --vybere nejmene opotrebovany kus vybavni daneho typu function nejvhodnejsi_podle_opotrebeni( xtyp_nazev typ.nazev%type, xod_datum DATE, xdo_datum DATE ) return vybaveni.id%type as retval vybaveni.id%type; xid_typ typ.id%type; begin xid_typ := dbp_typ.id_podle_nazvu(xtyp_nazev); DBMS_OUTPUT.PUT_LINE('ID TYPU VYBAVENI:' ||xid_typ); select id into retval from vybaveni where id_typ = xid_typ and pocet_vydani = (select min(pocet_vydani) from vybaveni where id_typ = xid_typ and not exists (select id_vybaveni from vypujcky where id_vybaveni = id) and not exists (select id_vybaveni from rezervace where ((od_datum <= xod_datum and do_datum >= xod_datum) or (od_datum <= xdo_datum and do_datum >= xdo_datum) ) and id_vybaveni = id ) ) and id not in (select id_vybaveni from rezervace where ((od_datum <= xod_datum and do_datum >= xod_datum) or (od_datum <= xdo_datum and do_datum >= xdo_datum) ) ) and ROWNUM < 2; --limitace na 1 navraceny radek DBMS_OUTPUT.PUT_LINE('Vybrane vybaveni:' ||retval); return retval; exception when NO_DATA_FOUND then raise_application_error(-20151,'Neni vhodne vybaveni vybaveni'); end; procedure nejvhodnejsi( xtyp_nazev typ.nazev%type, xod_datum DATE, xdo_datum DATE ) as begin DBMS_OUTPUT.PUT_LINE('ID VYBRANEHO VYBAVENI:' ||dbp_vybaveni.nejvhodnejsi_podle_opotrebeni(xtyp_nazev, xod_datum, xdo_datum)); end; --vybere nejmene opotrebovane vybaveni, ktere spravuje dany spravce END; / ---- balik pro praci s rezervacemi create or replace package dbp_rezervace as -- rezervuj vybaveni xid_vybaveni pro clen procedure rezervuj(xid_vybaveni vybaveni.id%type, xlogin clen.login%type, xod_datum rezervace.od_datum%type, xdo_datum rezervace.do_datum%type ); -- zrusi rezervaci na vybaveni pro clen xlogin -- je-li zadano pro nektery parametr null, jsou vymazany vsechny rezervace pro druhy parametr procedure zrus_rezervaci(xid_vybaveni vybaveni.id%type default null, xlogin clen.login%type default null); end; / create or replace package body dbp_rezervace as EXC_kolidujici_rezervace exception; EXC_vybaveni_neexistuje exception; EXC_uzivatel_neexistuje EXCEPTION; EXC_neplatne_datum EXCEPTION; PRAGMA EXCEPTION_INIT (EXC_kolidujici_rezervace, -20042); PRAGMA EXCEPTION_INIT (EXC_uzivatel_neexistuje, -20124); PRAGMA EXCEPTION_INIT (EXC_neplatne_datum, -20043); PRAGMA EXCEPTION_INIT (EXC_vybaveni_neexistuje, -02291); procedure rezervuj(xid_vybaveni vybaveni.id%type, xlogin clen.login%type, xod_datum rezervace.od_datum%type, xdo_datum rezervace.do_datum%type ) as xid_clena clen.id%type; xtemp vybaveni.id%type; begin xid_clena := dbp_clen.id_podle_loginu(xlogin); select id into xtemp from vybaveni where id = xid_vybaveni; insert into rezervace (id_vybaveni, id_clena, od_datum, do_datum, datum) values (xid_vybaveni,xid_clena, xod_datum, xdo_datum, sysdate); exception when no_data_found then raise_application_error(-20141,'Vybaveni s id '''||xid_vybaveni||''' neexistuje.'); when EXC_uzivatel_neexistuje then raise_application_error(-20142,'Uzivatel s loginem '''||xlogin||''' neexistuje.'); when EXC_kolidujici_rezervace then raise_application_error(-20143,'Vybaveni je jiz rezervovano na tuto dobu.'); when EXC_neplatne_datum then raise_application_error(-20144,'Vybaveni nelze rezervovat na dobu v minulosti'); end; -- pro parametr, ktery je nezadany, se vymazou veskere vyskyty - pouziti napr. pro zruseni vsech rezervaci nejakeho clen procedure zrus_rezervaci(xid_vybaveni vybaveni.id%type default null, xlogin clen.login%type default null) as xdatum rezervace.datum%type; xid_clen clen.id%type; begin if xid_vybaveni is null and xlogin is null then --jsou-li oba null, zrusim vse delete from rezervace; elsif xid_vybaveni is null then begin xid_clen := dbp_clen.id_podle_loginu(xlogin); delete from rezervace where id_clena = xid_clen; end; elsif xlogin is null then begin delete from rezervace where id_vybaveni = xid_vybaveni; end; else begin xid_clen := dbp_clen.id_podle_loginu(xlogin); select datum into xdatum from rezervace -- pro zjisteni, zda tato dvojce v rezervacich existuje where id_vybaveni = xid_vybaveni and id_clena = xid_clen; delete from rezervace where id_vybaveni = xid_vybaveni and id_clena = xid_clen; end; end if; exception when no_data_found then raise_application_error(-20040,'Zadna rezervace nebyla smazana ( login: '''||xlogin||''', id'''||xid_vybaveni||''').'); end; end; / create or replace package dbp_vypujcky as -- vypujci vybaveni xid_vybaveni pro clena defaultne na dva tydny procedure vypujcit(xid_vybaveni vybaveni.id%type, xdo_datum vypujcky.datum_navraceni%type default null, xlogin clen.login%type); -- vrati vypujcku -- je-li zadano pro vybaveni null, vrati vsechny vypujcky zadaneho clen procedure vratit(xid_vybaveni vybaveni.id%type default null, xlogin clen.login%type); procedure prodlouzit(xid_vybaveni vybaveni.id%type, xdo_datum vypujcky.datum_navraceni%type default null, xlogin clen.login%type); end; / -- telo baliku pro praci s vypujckami create or replace package body dbp_vypujcky as EXC_vypujceno exception; EXC_rezervovano exception; EXC_vybaveni_neexistuje exception; EXC_uzivatel_neexistuje EXCEPTION; -- vyjimka osetrujici absenci ciziho klice - znamena nepritomnost vybaveni, nepritomnost loginu se detekuje v prevodu loginu na id PRAGMA EXCEPTION_INIT (EXC_rezervovano, -20065); PRAGMA EXCEPTION_INIT (EXC_vypujceno, -00001); --porusi se unikatni klic PRAGMA EXCEPTION_INIT (EXC_uzivatel_neexistuje, -20124); -- rezervuje vybaveni s id xid_vybaveni pro clen s loginem xlogin procedure vypujcit(xid_vybaveni vybaveni.id%type, xdo_datum vypujcky.datum_navraceni%type default null, xlogin clen.login%type) as xid_clen clen.id%type; xpocet number; begin xid_clen := dbp_clen.id_podle_loginu(xlogin); select count(*) into xpocet from vypujcky where id_clena = xid_clen; if xpocet >= 5 then raise_application_error(-20150, 'Kazdy muze mit pujcene max 5 veci najednou.'); end if; -- datum vypujcky a doba vraceni se nastavuje automaticky v triggeru -- kontrola max. tri pujcenych vybaveniu daneho clen insert into vypujcky (id_vybaveni, id_clena, datum_vypujceni, datum_navraceni) values ( xid_vybaveni, xid_clen, sysdate, -- defaultne se pujcuje na 14 dni decode(xdo_datum,'null',sysdate + 14,null,sysdate + 14,xdo_datum)); exception when EXC_vybaveni_neexistuje then raise_application_error(-20151,'vybaveni s id '''||xid_vybaveni||''' neexistuje.'); when EXC_uzivatel_neexistuje then raise_application_error(-20152,'Clen s loginem '''||xlogin||''' neexistuje.'); when EXC_vypujceno then raise_application_error(-20153,'vybaveni s id '''||xid_vybaveni||''' je an danou dobu vypujceno.'); when EXC_rezervovano then raise_application_error(-20154,'vybaveni s id '''||xid_vybaveni||''' je na danou dobu rezervovano.'); end; -- jde s nim zrusit napr vsechny rezervace procedure vratit(xid_vybaveni vybaveni.id%type default null, xlogin clen.login%type ) as xdatum vypujcky.datum_vypujceni%type; xid_clen clen.id%type; begin if xid_vybaveni is null then begin xid_clen := dbp_clen.id_podle_loginu(xlogin); delete from vypujcky where id_clena = xid_clen; end; else begin xid_clen := dbp_clen.id_podle_loginu(xlogin); select datum_vypujceni into xdatum from vypujcky -- jen se koukenem jestli je where id_vybaveni = xid_vybaveni and id_clena = xid_clen; delete from vypujcky where id_vybaveni = xid_vybaveni and id_clena = xid_clen; end; end if; exception when no_data_found then raise_application_error(-20160,'Neexistuje vypujcka ( login: '''||xlogin||''', id'''||xid_vybaveni||''').'); end; -- prodlouzeni vypujcky procedure prodlouzit(xid_vybaveni vybaveni.id%type, xdo_datum vypujcky.datum_navraceni%type default null, xlogin clen.login%type) as xid vypujcky.id_vybaveni%type; xid_clen vypujcky.id_clena%type ; -- prodlouzeni - nelze prodlouzit vypujcku, je-li na ni rezervace, jinak se prodluzuje max. na dvojnasobek vypujcni doby, tedy begin xid_clen := dbp_clen.id_podle_loginu(xlogin); select id_vybaveni into xid from vypujcky where id_vybaveni = xid_vybaveni and id_clena = xid_clen; update vypujcky set datum_navraceni = xdo_datum where id_vybaveni = xid_vybaveni and id_clena = xid_clen; exception when no_data_found then raise_application_error(-20160,'Neexistuje vypujcka ( login: '''||xlogin||''', id'''||xid_vybaveni||''').'); when EXC_uzivatel_neexistuje then raise_application_error(-20142,'Uzivatel s loginem '''||xlogin||''' neexistuje.'); end; end; /
Oracle nám umožňuje spočítat si statistikz kolik, čeho a kam bylo umístěno, vzhledáváno a podle toho si sám uspořádat všecko tak jak potřebuje, aby se mu pro naši konkrítní tabulku s našimi konkrétními nároky co nejlépe počítalo.
analyze TABLE typ compute statistics; analyze TABLE vybaveni compute statistics; analyze TABLE clen compute statistics; analyze TABLE vypujcky compute statistics; analyze TABLE rezervace compute statistics; analyze TABLE vypujcky_log compute statistics;
Pokud si někdo budete chtít zkusit tetovací soubor, tak tady jsou data. Emaily jsou trochu namršený, strkat je jinak na web bych si netroufl.
------------------------------------------------------------------------------- -- clenove insert into clen (jmeno, prijmeni, login, email) values ('Tomas', 'Pop', 'tom','tomas.kop@selanam.cz'); insert into clen (jmeno, prijmeni, login, email) values ('Marcel', 'Tlustos', 'macino','tlusto@erra.cz'); insert into clen (jmeno, prijmeni, login, email) values ('Marketa', 'Florianova', 'makula','makula@sfcentrum.cz'); insert into clen (jmeno, prijmeni, login, email) values ('Jan', 'Marecek', 'pinda','honzasd@studentt.cvut.cz'); insert into clen (jmeno, prijmeni, login, email) values ('Alena', 'Sedlackova', 'aja','alasedla@pimail.cz'); insert into clen (jmeno, prijmeni, login, email) values ('Dusan', 'Micica', 'dusan','moncicakd@sezlnam.cz'); -- typy vybaveni insert into typ (nazev, poznamka) values ('Macka_kovana_88', 'Kovana macka, nehhodna na lezeni v ledech'); insert into typ (nazev, poznamka) values ('Macka_ramova_94', 'Ramova macka, pouzitelne pouze na skelet!!'); insert into typ (nazev, poznamka) values ('Cepin_stubaj_71', 'Historicke cepiny, turistaky'); insert into typ (nazev, poznamka) values ('Cepin_do_ledu_96','Cepiny pro narocnejsi lezeni'); insert into typ (nazev, poznamka) values ('Helma_kasida_88', 'Tezka a stara, lepsi mit vlastni...'); insert into typ (nazev, poznamka) values ('Teleskopky_99', 'Teleskopky cobry, odpruzene'); --vlozime desatero od kazdeho typu vybaveni exec dbp_vybaveni.vloz_vybaveni_hromadne(10,'macino','Macka_ramova_94'); exec dbp_vybaveni.vloz_vybaveni_hromadne(10,'tom','Macka_kovana_88'); exec dbp_vybaveni.vloz_vybaveni_hromadne(10,'tom','Cepin_stubaj_71'); exec dbp_vybaveni.vloz_vybaveni_hromadne(10,'tom','Teleskopky_99'); exec dbp_vybaveni.vloz_vybaveni_hromadne(10,'macino','Helma_kasida_88'); insert into vypujcky_log(datum, id_clena, id_vybaveni, status, poznamka) values ('01-JAN-06', 1,2,'P',''); insert into vypujcky_log(datum, id_clena, id_vybaveni, status, poznamka) values ('11-JAN-06', 1,2,'V',''); insert into vypujcky_log(datum, id_clena, id_vybaveni, status, poznamka) values ('15-JAN-06', 2,5,'R',''); insert into vypujcky_log(datum, id_clena, id_vybaveni, status, poznamka) values ('18-JAN-06', 2,5,'P',''); insert into vypujcky_log(datum, id_clena, id_vybaveni, status, poznamka) values ('27-JAN-06', 2,5,'V',''); -- aktualni vypujcka insert into vypujcky (id_clena, id_vybaveni, datum_vypujceni, datum_navraceni) values(1, 16, sysdate -7, sysdate +7 ); -- vypujcka, ktera nabyla vracena v limitu insert into vypujcky (id_clena, id_vybaveni, datum_vypujceni, datum_navraceni) values(2, 18, sysdate -20, sysdate -5);
Pohledy jsou takovou náhradou za neexistující uživatelské rozhraní. Jsou to vlastně takové nějaké složitějsí dotazi zakuklené tak aby se tvářili jednoduše.
------------------------------------------------------------------------------- create or replace view VW_seznam_spravcu_vybaveni as select distinct clen.jmeno, clen.prijmeni, clen.email from vybaveni inner join clen on vybaveni.id_clena = clen.id ; create or replace view VW_seznam_clenu as select distinct clen.jmeno, clen.prijmeni, clen.email, clen.login from clen ; create or replace view VW_vybaveni_po_limitu as select distinct vypujcky.datum_navraceni,typ.nazev, clen.jmeno, clen.prijmeni,clen.email from (((vybaveni join typ on vybaveni.id_typ = typ.id) join vypujcky on vybaveni.id = vypujcky.id_vybaveni) join clen on vypujcky.id_clena = clen.id) where vypujcky.datum_navraceni < sysdate ; --seznam vybaveni + nazev + login spravce create or replace view VW_seznam_vybaveni as select distinct vybaveni.id, typ.nazev,clen.login from (vybaveni join typ on vybaveni.id_typ = typ.id) join clen on vybaveni.id_clena = clen.id ; --seznam vybaveni ktere prave neni zapujcene + nazev + login spravce create or replace view VW_seznam_dostupneho_vybaveni as select distinct vybaveni.id, typ.nazev,clen.login as login_spravce,clen.email as email_spravce from (vybaveni join typ on vybaveni.id_typ = typ.id) join clen on vybaveni.id_clena = clen.id where not exists (select * from vypujcky where vypujcky.id_vybaveni = vybaveni.id) ; --seznam deseti kusu nejpouzivanejsiho vybaveni + spravce create or replace view VW_seznam_nejpouzivanejsiho as select distinct vybaveni.pocet_vydani, vybaveni.id, typ.nazev,clen.login from ((vybaveni join typ on vybaveni.id_typ = typ.id) join vypujcky on vypujcky.id_vybaveni = vybaveni.id) join clen on vybaveni.id_clena = clen.id where rownum < 11 order by vybaveni.pocet_vydani desc ; --seznam prave vypujceneho vybaveni create or replace view VW_prave_vypujcene as select distinct vypujcky.datum_navraceni, vybaveni.id, typ.nazev,clen.login from ((vybaveni join typ on vybaveni.id_typ = typ.id) join vypujcky on vypujcky.id_vybaveni = vybaveni.id) join clen on vypujcky.id_clena = clen.id order by vypujcky.datum_navraceni desc ; create or replace view VW_rezervace as select typ.nazev,vybaveni.id, clen.jmeno, clen.prijmeni from ((typ join vybaveni on typ.id = vybaveni.id_typ) join rezervace on vybaveni.id = rezervace.id_vybaveni) join clen on rezervace.id_clena = clen.id ; create or replace view VW_log as select clen.jmeno as jmeno, clen.prijmeni as prijmeni, clen.login as login_clena, vypujcky_log.status as akce, vypujcky_log.poznamka as poznamka from vypujcky_log join clen on vypujcky_log.id_clena = clen.id ; create or replace view VW_kdo_jak_vyuzival as select count(clen.login) as pocet_akci, clen.login as login_clena from (vypujcky_log join clen on vypujcky_log.id_clena = clen.id) group by clen.login order by pocet_akci desc ;
Takovou slušností je jako součást řešení dát i testovací skript, který tak nějak ukáže co to umí.
--nastaveni rozumnejsiho chovani prostredi set linesize 200; set pagesize 80; set serverout on; --seznam spravcu vybaveni exec DBMS_OUTPUT.PUT_LINE('-------SPRAVCI VYBAVENI-----------'); select * from VW_seznam_spravcu_vybaveni; -- seznam dostupneho vybaveni (toho, ktere aktualne neni vypujcene) exec DBMS_OUTPUT.PUT_LINE('-------DOSTUPNE VYBAVENI-----------'); select * from VW_seznam_dostupneho_vybaveni; exec DBMS_OUTPUT.PUT_LINE('-------SEZNAM CLENU-----------'); select * from VW_seznam_clenu; exec DBMS_OUTPUT.PUT_LINE('-------VYPIS LOGU VYPUJCEK-----------'); select * from VW_log; exec DBMS_OUTPUT.PUT_LINE('-------VYPIS AKTUALNICH VYPUJCEK-----------'); select * from VW_prave_vypujcene; exec DBMS_OUTPUT.PUT_LINE('-------VYPIS VYABVENI PO LIMITU-----------'); select * from VW_vybaveni_po_limitu; --rezervujeme si macky /* pokus o rezervaci v neplatnem datu */ exec dbp_rezervace.rezervuj(25,'aja','12-JAN-06','18-JAN-06'); /* tak si ho rezervujem na platnou dobu */ exec dbp_rezervace.rezervuj(25,'aja','12-AUG-06','18-AUG-06'); /* podivame se, ze rezervace je skutecne v rezervacich */ select * from VW_rezervace; /* tak a zkusim si ho rezervovat na jineho clena, coz nepujde */ exec dbp_rezervace.rezervuj(25,'pinda','14-AUG-06','15-AUG-06'); /* pro uplnost rezervaci zrusim */ exec dbp_rezervace.zrus_rezervaci(25, 'aja'); /* podivame se, ze rezervace skutecne zmizela */ select * from VW_rezervace; /* pak se podivam po nejvhodnejsich mackach na pristi tyden (tj volnych, nejmenekrat pouzitych */ exec dbp_vybaveni.nejvhodnejsi('Macka_ramova_94', sysdate +7, sysdate + 14); /* rezervuju ho na popristi tyden */ exec dbp_rezervace.rezervuj(dbp_vybaveni.nejvhodnejsi_podle_opotrebeni('Macka_ramova_94', sysdate +7, sysdate + 14),'pinda',sysdate +7,sysdate+14); /* ale kdyz to zkusi provest jiny uzivatel, tak mu system vybere jine vybaveni */ exec dbp_rezervace.rezervuj(dbp_vybaveni.nejvhodnejsi_podle_opotrebeni('Macka_ramova_94', sysdate +7, sysdate + 14),'aja',sysdate +7,sysdate+14); /* podivame se, kdo si tedy co rezervoval */ select * from VW_rezervace; /* a ted si to zkusime pujcit, jako nekdo, kdo to nema rezervovane, tak abychom porusili rezervaci...*/ exec dbp_vypujcky. vypujcit(2, null, 'tom'); /* ale ten, kdo to ma rezervovane si to pujcit muze...*/ exec dbp_vypujcky. vypujcit(2, null, 'aja'); /* podivame se, ze zmizela z rezervaci */ select * from VW_rezervace; /* a ted si to zkusime vypujcit jeste jednou...*/ exec dbp_vypujcky. vypujcit(2, null, 'aja'); /* a kouknem se kdo ma co prave pujcene */ select * from VW_prave_vypujcene; /* vidime ze aja, tak ji zkusime odstranit z clenu */ exec dbp_clen.odeber('aja'); /* to nejde, takze vypujcku vratime vsecko co ma aja pujceno */ exec dbp_vypujcky.vratit(null,'aja'); /* podivame se do logu kdo jak vyuzival aplikaci*/ select * from VW_kdo_jak_vyuzival; /*pak smazneme tu aju */ exec dbp_clen.odeber('aja'); /* podivame se do logu kdo jak vyuzival aplikaci, tentokrat uz udaje o aje nejsou, nesmime skladovat data o nikom, kdou uz neni clen*/ select * from VW_kdo_jak_vyuzival; /* chudaka aju zas pridame, at o neco neprijde a to hned dvakret, podruhe bude chyba*/ exec dbp_clen.pridej('aja', 'alased@seznam.cz', 'Alena', 'Sedlackova'); exec dbp_clen.pridej('aja', 'alased@seznam.cz', 'Alena', 'Sedlackova'); /* a zkusime si napujcovat hodne vybaveni na jednoho clena */ exec dbp_vypujcky. vypujcit(dbp_vybaveni.nejvhodnejsi_podle_opotrebeni('Macka_ramova_94', sysdate +7, sysdate + 14), null, 'pinda'); exec dbp_vypujcky. vypujcit(dbp_vybaveni.nejvhodnejsi_podle_opotrebeni('Macka_ramova_94', sysdate +7, sysdate + 14), null, 'pinda'); exec dbp_vypujcky. vypujcit(dbp_vybaveni.nejvhodnejsi_podle_opotrebeni('Macka_ramova_94', sysdate +7, sysdate + 14), null, 'pinda'); exec dbp_vypujcky. vypujcit(dbp_vybaveni.nejvhodnejsi_podle_opotrebeni('Macka_ramova_94', sysdate +7, sysdate + 14), null, 'pinda'); exec dbp_vypujcky. vypujcit(dbp_vybaveni.nejvhodnejsi_podle_opotrebeni('Macka_ramova_94', sysdate +7, sysdate + 14), null, 'pinda'); exec dbp_vypujcky. vypujcit(dbp_vybaveni.nejvhodnejsi_podle_opotrebeni('Macka_ramova_94', sysdate +7, sysdate + 14), null, 'pinda'); /* tak dopujcujeme zbytek vybaveni na jineho clena, aby uz nebylo zadne vhodne */ exec dbp_vypujcky. vypujcit(dbp_vybaveni.nejvhodnejsi_podle_opotrebeni('Macka_ramova_94', sysdate +7, sysdate + 14), null, 'dusan'); exec dbp_vypujcky. vypujcit(dbp_vybaveni.nejvhodnejsi_podle_opotrebeni('Macka_ramova_94', sysdate +7, sysdate + 14), null, 'dusan'); exec dbp_vypujcky. vypujcit(dbp_vybaveni.nejvhodnejsi_podle_opotrebeni('Macka_ramova_94', sysdate +7, sysdate + 14), null, 'dusan'); exec dbp_vypujcky. vypujcit(dbp_vybaveni.nejvhodnejsi_podle_opotrebeni('Macka_ramova_94', sysdate +7, sysdate + 14), null, 'dusan'); exec dbp_vypujcky. vypujcit(dbp_vybaveni.nejvhodnejsi_podle_opotrebeni('Macka_ramova_94', sysdate +7, sysdate + 14), null, 'dusan'); exec dbp_vypujcky.vratit(null,'pinda'); exec dbp_vypujcky.vratit(null,'dusan'); /* pokus vratit nekoho, kdo neexistuje */ exec dbp_vypujcky.vratit(null,'dus'); /* Zkusime vratit marcelovu propadlou vypujcku*/ exec dbp_vypujcky.vratit(null,'macino'); /* podivame se na aktualni vypujckly */ select * from VW_prave_vypujcene; /* a kdo jak vyuzival aplikaci */ select * from VW_kdo_jak_vyuzival; --tohle je konec testovaciho souboru--
No a jelikož asi nikdo na tuhle aplikaci nebude dlouho zvedavej, tohle je skript na úklid.
--zase vsechno pekne smazat, pospatku v opacnem poradi nez to bylo tvoreno... --odstraneni statistik analyze TABLE typ delete statistics; analyze TABLE vybaveni delete statistics; analyze TABLE clen delete statistics; analyze TABLE vypujcky delete statistics; analyze TABLE rezervace delete statistics; analyze TABLE vypujcky_log delete statistics; --odstraneni pohledu drop view VW_seznam_spravcu_vybaveni; drop view VW_seznam_clenu; drop view VW_vybaveni_po_limitu; drop view VW_seznam_vybaveni; drop view VW_seznam_dostupneho_vybaveni; drop view VW_seznam_nejpouzivanejsiho; drop view VW_prave_vypujcene; drop view VW_rezervace; drop view VW_log; drop view VW_kdo_jak_vyuzival; --odstraneni balicku drop package dbp_typ; drop package dbp_rezervace; drop package dbp_vybaveni; drop package dbp_clen; drop package dbp_vypujcky; --odstraneni sekvenci drop SEQUENCE SEQ_vybaveni_id; drop SEQUENCE SEQ_vypujcky_log_id; drop SEQUENCE SEQ_clen_id; drop SEQUENCE SEQ_typ_id; --odstraneni triggeru drop TRIGGER TRG_bef_ins_row_vybaveni_id; drop TRIGGER TRG_bef_ins_row_clen_id; drop TRIGGER TRG_bef_ins_row_typ_id; drop TRIGGER TRG_bef_ins_row_vyp_lg_id; drop TRIGGER TRG_bef_ins_row_vybaveni; drop TRIGGER TRG_bef_upd_row_vybaveni; drop TRIGGER TRG_bef_ins_upd_row_clen; drop TRIGGER TRG_bef_ins_row_rezervace; drop TRIGGER TRG_bef_ins_upd_row_vypujcky; drop TRIGGER TRG_aft_del_row_vypujcky; drop TRIGGER TRG_aft_ins_row_rezervace; drop TRIGGER TRG_aft_ins_row_vypujcky; --odstraneni indexu drop index IDX_vybaveni_typ; drop index IDX_vybaveni_spravce; drop index IDX_vypujcky_id_clena; drop index IDX_vypujcky_vratit_do; drop index IDX_rezervace_id_clena; drop index IDX_rezervace_id_vybaveni; drop index IDX_vypujcky_log_status; drop index IDX_vypujcky_log_id_vyb; drop index IDX_vypujcky_log_id_clena; --vymazani tabulek a zavislosti DROP TABLE vypujcky_log CASCADE CONSTRAINTS; DROP TABLE rezervace CASCADE CONSTRAINTS; DROP TABLE vypujcky CASCADE CONSTRAINTS; DROP TABLE clen CASCADE CONSTRAINTS; DROP TABLE vybaveni CASCADE CONSTRAINTS; DROP TABLE typ CASCADE CONSTRAINTS;
Co dodat, hodně toho tady není, nejsou tu kursory, a spousta dalsího zajímavého co nám Oracle a jiné databáze poskztují, Ale je to docela mzslím pěkný úvod, pro člověka,který o tom už někdy slyšel. Tohle je pro studijní účely, tedy pro čtení a pokusy, nikoli jako možnost co odevzdat. Pokud to někdo budete chtít použít jako svůj zápočťák nebo nějak jinak, tak bych ocenil, kdybyste se přemohli a konzultovali to se mnou. © T.P. 2006