UNIVERZA V MARIBORU
FAKULTETA ZA ELEKTROTEHNIKO,
RAČUNALNIŠTVO IN INFORMATIKO
Urban Rotnik
AKTIVNE PODATKOVNE BAZE IN PROŽILCI
Diplomsko delo
Maribor, avgust 2014
AKTIVNE PODATKOVNE BAZE IN PROŽILCI
Diplomsko delo
Študent: Urban Rotnik
Študijski program: univerzitetni študijski program
Informatika in tehnologije komuniciranja
Smer: Informacijski sistemi
Mentor: izr. prof. dr. Boštjan Brumen, univ.dipl.inţ. rač. in inf.
Lektor(ica): Nastja Stropnik Naveršnik, univ. dipl. slov.
i
.
ZAHVALA
Zahvaljujem se druţini, ki mi je
omogočila študij, in mentorju, izr. prof.
dr. Boštjanu Brumnu, za pomoč pri
izdelavi diplomskega dela.
ii
Aktivne podatkovne baze in proţilci
Ključne besede: podatkovne baze, podatki, sistem za upravljanje podatkovne baze,
proţilci
UDK: 004.651(043.2)
Povzetek
Pretežna večina sodobnih aplikacij in informacijskih sistemov uporablja podatkovne baze
za hranjenje podatkov. Pogosto je potrebno pred vnosom podatkov v bazo ali izbrisom teh
iz nje še dodatno izvesti nekatere akcije, vnose, izbrise ali spremembe, ki jih lahko reši
aplikacija, ali pa te preselimo na nivo podatkovne baze in jih tam implementiramo. Namen
diplomskega dela je implementirati funkcije, imenovane prožilci, na različnih podatkovnih
bazah, ter spoznati, kaj omogočajo posamezne. Za implementacijo prožilcev smo zgradili
primerno podatkovno bazo v treh različnih okoljih. Spoznali smo, da različna okolja
omogočajo različne prožilce, kaj izbrati, pa je pa odvisno od tipa aplikacije in zahtev.
iii
Active databases and triggers
Key words: database, data, database management system, triggers
UDK: 004.651(043.2)
Abstract
Most of modern applications and information systems use databases for storing the data.
Before inserting or deleting the data into or from database it is often necessary to
additionally execute some actions like insert, delete, or change data, what can be done at
application level, or can be moved to database level. The purpose of the diploma work is
to implement such functions, called trigger, on different databases environments and learn
what individual ones are capable of. For implementing the triggers an appropriate
database in three different environments was build. We have learned that different
environments allow different kind of triggers, which one to choose for application
development depends on the type of applications and requirements.
iv
KAZALO VSEBINE
1 UVOD .......................................................................................................................................... 1
2 AKTIVNE PODATKOVNE BAZE ..................................................................................................... 2
2.1 Podatkovne baze ................................................................................................................ 2
2.1.1 Funkcije SUPB-ja ......................................................................................................... 4
2.1.2 Jezik SQL ..................................................................................................................... 5
2.2 Aktivne podatkovne baze ................................................................................................... 6
2.2.1 Prožilci nad podatki .................................................................................................... 6
2.2.2 Prožilci nad podatkovno bazo .................................................................................... 9
3 IMPLEMENTACIJA AKTIVNE PODATKOVNE BAZE ....................................................................... 9
3.1 Opis podatkovne baze ........................................................................................................ 9
3.2 Logični diagram ................................................................................................................ 10
3.3 Postavitev okolja ter generiranje baze ............................................................................. 17
3.3.1 Postavitev okolja MySQL .......................................................................................... 17
3.3.2 Postavitev okolja Microsoft SQL Server ................................................................... 18
3.3.3 Postavitev okolja Oracle ........................................................................................... 19
3.3.4 Ustvarjanje fizične podatkovne baze ....................................................................... 20
3.4 Aktivnosti, na katere so bo odzvala baza ......................................................................... 25
3.4.1 Aktivnosti nad celotno PB ........................................................................................ 25
3.4.2 Aktivnosti nad podatki ............................................................................................. 25
3.5 Implementacija prožilcev ................................................................................................. 27
3.5.1 MySQL prožilci .......................................................................................................... 27
3.5.2 Oracle prožilci ........................................................................................................... 31
3.5.3 MS SQL server prožilci .............................................................................................. 36
4 SKLEP ........................................................................................................................................ 39
VIRI IN LITERATURA .......................................................................................................................... 41
v
KAZALO SLIK
Slika 3.1: Entiteta Uporabnik ............................................................................................10
Slika 3.2: Entiteta Podjetje ...............................................................................................10
Slika 3.3: Entiteta Narocnik ..............................................................................................11
Slika 3.4: Entiteta za kontaktne podatke ..........................................................................11
Slika 3.5: Entiteta Pogodba in ostale entitete, ki jo opisujejo ............................................13
Slika 3.6: Entiteta Terjatev ...............................................................................................14
Slika 3.7: Entitete, ki sestavljajo nakazilo in račun ...........................................................15
Slika 3.8: Entiteta Izbrisana_pogodba ..............................................................................15
Slika 3.9: Logični diagram ................................................................................................16
Slika 3.10: Namestitev MySQL podatkovne baze .............................................................17
Slika 3.11: Namestitev SQL Server podatkovne baze ......................................................18
Slika 3.12: Povezava na bazo SQL Server ......................................................................19
Slika 3.13: Ustvarjanje novega uporabnika v SQL Developerju ........................................20
Slika 3.14: Povezava DBScheme na Oracle ....................................................................21
Slika 3.15: Povezava DBScheme na MySQL ...................................................................21
KAZALO TABEL
Tabela 3.1: Razlike pri generiranju fizične sheme ............................................................22
Tabela 3.2: MySQL proţilci ..............................................................................................27
Tabela 3.3: Oracle proţilci ...............................................................................................31
Tabela 3.4: SQL Server proţilci .......................................................................................36
vi
SEZNAM UPORABLJEN KRATIC
PB - podatkovna baza
SUPB - sistem za upravljanje podatkovne baze
SQL - (angl. structured query language); strukturirani povpraševalni jezik
ER diagram - (angl. entity-relationship diagram); entitetno-relacijski diagram
XML - (angl. extensible Markup Language); razširitveni označevalni jezik
OLAP - (angl. online analytical processing)
NoSQL - (angl. not only SQL); ne samo SQL
DML - (angl. data manipulation language); jezik za delo s podatki
DDL - (angl. data definition language); jezik za definiranje sheme
1
1 UVOD
Ţivimo v informacijski dobi, kar pomeni, da smo obkroţeni z informacijami, katerih
sestavni del so podatki. Podatek sicer sam po sebi ni uporaben, če ni podkrepljen z našim
znanjem. Ko zdruţimo znanje in podatek, dobimo informacijo.
Danes je takšnih podatkov ogromno, da so uporabni, pa morajo biti nekje shranjeni, varni
pred izgubo ali neţeleno spremembo in smiselno organizirani. Za to je najbolj primerna
podatkovna baza (PB) z namensko programsko opremo, sistemom za upravljanje s
podatkovno bazo (SUPB), ki nam omogoča nadzorovan dostop, uporabo in upravljanje s
podatki v PB. Večina sodobnih aplikacij je podprta s PB, ki so lahko nameščene lokalno
ali pa na oddaljenem streţniku. Sistem za uporabljanje podatkovne baze (SUPB) skrbi,
da dovoljuje uporabnikom (to so največkrat aplikacije, ki jih uporablja človek) dostop do
podatkov, branje, pisanje, brisanje ali spreminjanje. Pod pojmom podatkovna baza se
danes razume PB (datoteka, kjer so zapisani podatki fizično) in SUPB (ki skrbi za dostop
in upravljanje s podatki) skupaj, saj sama PB brez ustreznega SUPB-ja ne nudi nobene
koristi.
Velikokrat je treba po določenem dogodku v bazi (vpis v bazo, sprememba ali izbris
podatka) naknadno spremeniti tudi drug podatek, ki se navezuje na prejšnjega. V takih
primerih lahko to rešimo s proţilcem, to je metoda oziroma funkcija, ki se proţi
samodejno. PB, ki omogočajo implementacijo programov, ki se odzivajo na dogodke v
bazi, imenujemo aktivne podatkovne baze.
V diplomskem delu smo podrobneje predelali področje aktivnih podatkovnih baz, raziskali,
kako in na katere dogodke se lahko odzivajo, in kaj vse lahko prenesemo iz aplikacijskega
nivoja na nivo PB. Primerjali smo tudi implementacijo proţilcev v različnih PB (MySql,
Oracle, SQL Server). Namen je bil pridobiti čim več znanja o aktivnih podatkovnih bazah
in prednostih, ki so posledica uporabe aktivne podatkovne baze.
V prvem delu smo se poglobili in preučili literaturo ter predstavili aktivne podatkovne baze
in njihove značilnosti. Opisali smo, kaj je PB, kaj je aktivna PB ter kaj nam omogoča. V
praktičnem delu smo načrtali shemo za PB, na kateri je bilo mogoče smiselno
implementirati proţilce. Vse smo implementirali v treh različnih PB (MySql, Oracle, MS
SQL Server) ter primerjali razlike pri implementaciji. Prišli smo do ugotovitev, kakšne
omejitve oziroma prednosti ima posamezna podatkovna baza.
2
2 AKTIVNE PODATKOVNE BAZE
2.1 Podatkovne baze
Zgodovina hranjenja podatkov sega zelo daleč nazaj, ţe nekaj tisoč let pr. n. št. je človek
shranjeval podatke s simboli in prvimi pisavami. To so bili podatki o rojstvih, pridelani
hrani in o drugih osnovnih človeških potrebah. Kasneje, stoletja nazaj, so zbirke podatkov
nastajale na raznih uradih, v bolnišnicah, ustanovah, vojski in podobno. Vendar tudi takrat
niso hranili podatkov na način in na medijih, kot je to značilno za današnje čase.
Evolucija PB, kot jo poznamo danes, se je začela v 60. letih. Leta pred pojavitvijo prvih PB
so podatke shranjevali iz računalnika na luknjaste kartice, kasneje pa v datoteke, zato tudi
imenujemo obdobje pred pojavitvijo prvih podatkovni baz obdobje datotek [1] in [2].
Ampak datoteke niso imele toliko prednosti, kot so imele slabosti oziroma omejitev.
Omogočale so sicer hranjenje precejšnje količine podatkov, vendar se pojavi teţava ob
veliki porasti aplikacij. Vsaka aplikacija je imela svoje datoteke, v katerih je hranila
podatke, ki pa jih niso mogle uporabljati druge aplikacije. Zaradi tega je prišlo do
redundance in nekonsistentnosti podatkov. Zaradi različnih oblik fizičnega zapisa je
morala vsaka aplikacija biti prilagojena in sprogramirana tako, da je lahko uporabljala to
datoteko. Poleg tega je bila velika teţava tudi varnost datotek in sledenje dogodkom, ki so
se zgodili v tej podatkovni datoteki, saj je bilo vračanje nazaj nemogoče [3] in [4].
V letu 1968 se je začela širša komercialna uporaba PB, ko je IBM predstavil svoj IMS-
Inforation Managment System, ki se je potem uporabljal v 70. in 80. letih.
V 60. letih tudi Charles Bachmann razvije prvi SUPB, imenovan Integrated Data Store
(IDS), ki je bil standardiziran leta 1971, in kot mreţni podatkovni model skupaj s
hierarhičnim predstavlja smernice za razvoj PB v 70. letih.
Novo obdobje za PB se je začelo leta 1970, ko je Edgar F. 'Ted' Codd predstavil koncept
relacijskega podatkovnega modela. PB je prikazana kot mnoţica podatkov, ki so
organizirani v tabelah, in s shemo, ki določi strukturo, to pomeni ime relacije (tabele) in
ime ter vrsta vsakega stolpca v tabeli. V tem modelu je logična shema popolnoma ločena
od fizičnega modela. Tako se uporabnik ne ukvarja več s fizičnim zapisom podatkov in
njihovo strukturo. To postane tudi standardno načelo za razvoj PB v naslednjih letih. Leta
1976 je Peter Chen predstavil entitetno-relacijski (ER) diagram. V tem času razvijejo tudi
zmogljiv programski jezik, angl. Standard Query Language (SQL), ki postane standard v
80. letih. Relacijske podatkovne baze zelo uspešno prodrejo na trg in močno vplivajo na
upad hierarhičnih ter mreţnih modelov PB. Največje uspehe poţanje izdelek DB2, razvit
3
pri IBM-u, ki je bil v kombinaciji z njihovimi računalniki vzrok za razvoj drugih aplikacij pri
IBM-u [1].
V 90. letih se je začelo obdobje objektnih in objektno-relacijskih podatkovnih baz. To je
prineslo s seboj razvoj novih aplikacij OLAP (Online Analytical Processing). Porast in
uporaba interneta postaneta komercialni, posledica je porast oddaljenih PB in naloţb v
razvoj spletnih aplikacij, ki so za svoje delovanje seveda potrebovale PB. Takrat pride
močno do izraza tudi še danes popularen brezplačen MySQL.
Po letu 2000 slišimo izraz NoSQL, angl. Not only SQL. V bazah ne gre več zgolj samo za
hranjenje podatkov, ampak se uveljavijo sistemi, kot je ţe zgoraj omenjen OLAP,
podatkovno rudarjenje, podatkovno skladiščenje, XML podatkovne zbirke in aktivne
podatkovne baze [5].
Definicija podatkovne baze, zapisane na webster.com, se glasi: »A usually large collection
of data organized especially for rapid search and retrieval« [6], kar pomeni »Po navadi
velika zbirka podatkov, ki je organizirana tako, da omogoča hitro iskanje in vračanje
rezultatov, s pomočjo računalnika.«
Danes so podatkovne baze osrednji del vseh velikih informacijskih sistemov raznih
organizacij, podjetij, spletnih aplikacij. Za uspešno delovanje organizacije potrebujemo
znanja, ki jih pridobimo iz podatkov, shranjenih v PB. Na osnovi teh podatkov sprejemamo
nadaljnje odločitve in zbiramo nova znanja ter informacije. Da so podatki pravilni in
uporabni, morajo biti baze ustrezno zaščitene ter opremljene z mehanizmi za upravljanje s
podatki.
Sodobna podatkovna baza mora omogočati hiter dostop do podatkov pooblaščenim
uporabnikom, dostop več uporabnikom hkrati, preprečevati nepooblaščen dostop in
redundanco podatkov, zagotavljati varnostne kopije in vedno sveţe podatke.
V primerjavi s hranjenjem podatkov v datoteki ima baza še precej drugih prednosti. V
objektnih bazah je omogočeno tudi hranjenje metod za delo s podatki, baze omogočajo
različne poglede na podatke za različne tipe uporabnikov, omogočajo nadzorovano delitev
oziroma souporabo podatkov, zagotavljajo fleksibilnost pri spreminjanju in kasnejšemu
razvoju aplikacije ter podatkovne strukture. Zmogljivejše PB imajo tudi mehanizme za
avtomatsko iskanje novih znanj iz ţe pridobljenih podatkov, kar imenujemo podatkovno
rudarjenje.
Seveda pa sistemi za upravljanje s podatkovno bazo niso poceni. Najdemo sicer precej
prosto dostopne programske opreme, vendar je pri zahtevnejših aplikacijah potrebno
4
pogosto poseči po plačljivi opremi. To pomeni, da imamo po navadi zagotovljeno tudi
podporo proizvajalca SUPB-ja. Tudi računalniški sistemi, kjer teče baza, morajo imeti
zmogljivo strojno opremo in se hitro odzivati na zahteve SUPB-ja [7].
2.1.1 Funkcije SUPB-ja
Kot je ţe v uvodu napisano, danes pod pojmom podatkovna baza razumemo podatkovno
bazo kot datoteko, v kateri so organizirani podatki, ter sistem za upravljanje s podatkovno
bazo (SUPB). SUPB je programska oprema, ki se uporablja za upravljanje s podatki v
podatkovni bazi ter za definiranje in spreminjanje same podatkovne baze. Skrbi tudi za
vse funkcionalnosti podatkovne baze, ki so naštete zgoraj in spadajo med zahteve
sodobne PB.
Uporabniške funkcije
Gradnja PB:
definiranje sheme PB,
kreiranje PB,
spreminjanje sheme PB.
Uporaba PB:
iskanje in vračanje podatkov iz PB,
spreminjanje podatkov v PB.
Sistemske funkcije, ki jih uporabnik neposredno ne vidi
Zaščita in varnost
preverjanje vhodnih podatkov,
varnostno kopiranje,
avtorizacija dostopa,
transakcije pri sočasnem dostopu.
Nadzor
zbiranje podatkov o uporabi PB in aktivnosti SUPB-ja,
zagotavljanje neodvisnosti podatkov od aplikacij.
5
2.1.2 Jezik SQL
Preko SUPB-ja torej dostopamo do podatkov in jih spreminjamo, spreminjamo shemo,
kreiramo nove tabele in druge objekte …
Vendar moramo vse to povedati na način, ki ga SUPB razume. V ta namen so v času
razvoja entitetno-relacijskega modela razvili tako imenovani Standard Query Lanugage
(SQL) ali strukturni povpraševalni jezik, ki je postal standard, in se uporablja še danes.
Seveda se je skozi čas ta jezik spreminjal, standardi so se dopolnjevali, vendar sta namen
in osnova ostala ista.
Z jezikom SQL izvršujemo preproste in zahtevne poizvedbe, spreminjamo podatke,
dodajamo nove vrstice, brišemo vrstice, ustvarjamo nove tabele, spreminjamo obstoječe,
pišemo programe, ki se izvajajo znotraj podatkovne baze ...
Zato ga delimo na DML (angl. data manipulation language), kar pomeni jezik za
manipulacijo s podatki, in DDL (angl. data definition lanugage), kar pomeni jezik za
definiranje podatkov oziroma podatkovne sheme.
Najpogosteje uporabljeni DML ukazi so:
SELECT - ukaz za iskanje po PB,
UPDATE - ukaz za posodabljanje vrstice v PB,
INSERT INTO - ukaz za vstavljanje v PB,
DELETE - ukaz za brisanje iz PB.
Najpogosteje uporabljeni DDL ukazi so:
CREATE - ustvari objekt, kot je tabela, proţilec,
ALTER - spreminja obstoječ objekt na različne načine,
RENAME - spreminjanje imena objekta,
DROP - izbris objekta.
Del jezika SQL so tudi pogojni stavki, podatkovni tipi, ki so večinoma enaki tradicionalnim,
poznanim iz programskih jezikov, a se lahko sintakse med različnimi bazami razlikujejo.
Ker je sam SQL namenjen predvsem delu in iskanju s podatki, in ni klasični programski
jezik, kot sta na primer C ali Java, z njim ni mogoče napisati zaporedja izvajanja nekih
ukazov ali akcij. V ta namen se je razvil razširitveni jezik SQL, namenjen programom in
proceduram, ki se izvajajo na nivoju baze. Od proizvajalca do proizvajalca PB se ta
6
razširitveni jezik drugače imenuje: PL/SQL pri Oracl-u, SQL/PSM pri MySQL-u in T-SQL
pri Microsoftu.
Prav tako se razlikuje tudi sintaksa pisanja [8] in [9].
2.2 Aktivne podatkovne baze
Podatkovne baze, ki so se sposobne same odzivati na zunanje dogodke, imenujemo
aktivne podatkovne baze.
Poglejmo primer. Imamo trgovino z računalniškimi komponentami in ţelimo, da so
določene komponente ves čas na zalogi.
V navadni, pasivni podatkovni bazi to pomeni, da bo vsake toliko časa nekdo zadolţen, da
bo pregledal, kakšna je zaloga in ali ustreza našim pogojem.
Aktivna podatkovna baza lahko to reši sama. Razvijalec podatkovne baze bo napisal
program, ki se bo izvedel vedno, ko bo nekdo kupil določen artikel. V programu bo pogoj,
če je zaloga artikla manjša od tiste, ki ustreza našim pogojem, se bo zgodil neki dogodek.
V tem primeru je baza sposobna vpisati novo naročilo, kar se bo zgodilo samodejno.
Tako smo rešili preprosto teţavo, ki je lahko precej nadleţna, če gre za veliko trgovino z
veliko prometa.
Programom, ki se izvajajo ob različnih dogodkih, kot so vpisi podatkov v bazo,
spreminjanja podatkov, izbris podatkov ali tudi prijava uporabnika v PB, pravimo proţilci
(angl. triggers) [10].
Poznamo dve vrsti proţilcev: tiste, ki se proţijo nad podatki in tabelami ob ukazih DML
(vnos v bazeo, izbris, spreminjane), in tiste, ki se proţijo na nivoju podatkovne baze po
navadi z DDL ukazi ob kreiranju novega objekta, spreminjanju obstoječega, izbrisu
objekta, prijavi v bazo in ob spreminjanju sheme. Prijava v bazo sicer ni DDL akcija,
ampak vseeno spada med proţilce nad podatkovno bazo.
2.2.1 Proţilci nad podatki
Proţilci, ki se proţijo ob akcijah INSERT, UPDATE in DELTE nad določeno tabelo, so
DML proţilci. Specificiramo jim tudi čas, ali se proţijo pred ali po uspešno izvedeni SQL
akciji. Pišemo jih, tako kot tudi druge programe na nivoju PB, v razširitvenem SQL jeziku,
zaradi česar se lahko sintakse tudi precej razlikujejo. V naši diplomski nalogi smo se
ukvarjali s proţilci v Oracle, MySQL in SQL Server podatkovni bazi. Sledi pregled
posameznih.
7
2.2.1.1 MySQL
CREATE
[DEFINER = { user | CURRENT_USER }]
TRIGGER ime_prožilca
trigger_time trigger_event
ON tbl_name FOR EACH ROW
trigger_body
trigger_time: { BEFORE | AFTER }
trigger_event: { INSERT | UPDATE | DELETE }
DEFINER določa MySQL uporabnika, ki se uporablja za preverjanje dostopnih privilegijev,
ko se proţilec proţi.
Trigger_time: {BEFORE | AFTER} Proţilec se proţi pred ali po izvedbi SQL akcije.
Trigger_event: {INSERT | UPDATE | DELETE} Ob katerem dogodku se proţi proţilec.
ON nam pove, nad katero tabelo se proţilec proţi.
FOR EACH ROW pomeni, da se proţilec proţi za vsako vrstico posebej. Če vnašamo 10
vrstic, se bo ta proţilec izvedel za vsako vrstico posebej. Če ne dodamo klavzule FOR
EACH ROW, se izvede proţilec po vnosu zadnje vrstice. Tak proţilec je proţilec nad
tabelo, ne nad vrstico.
Na posamezne stolpce znotraj vrstice se sklicujemo z vrednostmi :old.ime_stolpca in
:new.ime_stolpca. V DELETE proţilcu :new ne obstaja, prav tako v INSERT proţilcu ne
obstaja :old. V UPDATE proţilcu predstavlja :old vrednost stolpca pred posodobitvijo,
:new pa predstavlja novo vrednost stolpca, torej po posodobitvi, za katero pa ni nujno, da
je ţe bila izvršena. S temi vrednostmi se lahko sklicujemo na stolpce le v proţilcih, ki so
proţeni nad vrsticamim in ne nad celotno tabelo [11].
8
2.2.1.2 Oracle
CREATE [OR REPLACE] TRIGGER trigger_name
{BEFORE | AFTER | INSTEAD OF }
{INSERT [OR] | UPDATE [OR] | DELETE }
ON table_name
[REFERENCING OLD AS o NEW AS n]
[FOR EACH ROW]
WHEN (condition)
BEGIN
-- sql statements
END;
[12]
Gre za precej podobno sintakso kot pri MySQL-u, vendar nam Oracle omogoča, da si
lahko za :new in :old nastavimo svoje referenčne znake, s pomočjo katerih se potem
sklicujemo na stolpce.
Oracle omogoča tudi proţilce, ki jim definiramo več proţilnih akcij, recimo UPDATE OR
DELETE, torej se aktivira in ob UPDATE in ob DELETE SQL stavku. Seveda moramo
logiko pravilno ločiti za UPDATE in za DELETE.
To storimo s pogojnim stavkom.
IF INSERTING
ali
IF DELETING
[13].
INSTEAD OF proţilec se uporablja v Oraclu predvsem za akcije nad pogledi, in ne nad
tabelami, saj nad pogledi ne moremo direktno izvesti INSERT, UPDATE ali DELETE
stavka. Zato pa lahko v tem proţilcu napišemo logiko, ki bo pravilno izvedla vse potrebne
akcije nad tabelami, na katere se nanaša vrstica v pogledu [14].
2.2.1.3 MS SQL Server
CREATE TRIGGER [ schema_name . ]trigger_name
ON { table | view }
[ WITH <dml_trigger_option> [ ,...n ] ]
{ FOR | AFTER | INSTEAD OF }
{ [ INSERT ] [ , ] [ UPDATE ] [ , ] [ DELETE ] }
AS { sql_statements }
[15]
Transact-SQL ne pozna proţilca BEFORE, v tem se tudi najbolj razlikuje od MySQL-a in
Oracle-a. Namesto njega moramo uporabiti INSTEAD OF, ki prepiše določeno SQL
akcijo.
V Transact-SQL-u tudi nimamo :old in :new vrednosti, namesto njih se sklicujemo v
INSERT proţilcu na INSERTED vrstico in v DELETE proţilcu na DELETED vrstico. Iz te
9
vrstice dobimo vrednosti stolpcev s pomočjo klasičnega SQL poizvedovalnega stavka, ki
ga uporabljamo za poizvedovanje po ostalih tabelah.
Na primer
SELECT @ime=ime FROM inserted
kjer je @ime prej deklarirana spremenljivka, v njo pa je prebrana vrednost iz stolpca
»ime«, ki je bil vnesen v bazo.
Kot v Oraclu lahko tudi tukaj definiramo proţilce, ki se izvedejo ob več dogodkih [15].
2.2.2 Proţilci nad podatkovno bazo
To so tisti proţilci, ki se proţijo ob DDL dogodkih ali drugih dogodkih nad celotno
podatkovno bazo. To so na primer izbris tabele, ustvarjanje nove tabele ali drugega
objekta, ustvarjanje novega uporabnika, prijava v bazo.
MySQL ne pozna DDL proţilcev, medtem ko ju SQL Server in Oracle poznata. S takšnimi
proţilci lahko zavarujemo bazo pred izbrisi tabel, vodimo dnevnik vseh akcij, ki so se
zgodile nad shemo, vodimo vpise v bazo in podobno [16] in [17].
3 IMPLEMENTACIJA AKTIVNE PODATKOVNE BAZE
3.1 Opis podatkovne baze
Za prikaz delovanja proţilcev na realni podatkovni bazi smo implementirali podatkovno
bazo, v kateri hranimo podatke aplikacije, ki je namenjena podjetju, ki prevzame terjatve
za svoje stranke. Naročnik je ţelel prijavo v sistem z različnimi uporabniki, ki pripadajo
določenim izterjevalnim podjetjem. Tako je aplikacija sicer namenjena ciljnemu podjetju, ki
pa lahko ima več registriranih podjetji. Tukaj gre zgolj za pravni vidik in pogled na
pogodbo, ne za sistem, ki bi bil v mnoţični uporabi različnih uporabniških skupin, podjetij.
Znotraj sistema vodimo naročnike, to so osebe ali podjetja, ki najamejo izterjevalno
podjetje, da v njihovem imenu izterjuje njihov denar. Na drugi strani je dolţnik, ki je dolţan
denar.
Pomembno je, da naročnike in dolţnike vidijo vsi uporabniki, ne glede na to, kateremu
izterjevalnemu podjetju pripadajo. Za to smo poudarili, da je aplikacija namenjena
ciljnemu podjetju, ki pa se lahko prijavi z različnimi registriranimi podjetji.
Pogodba je predmet zaveze med naročnikom in podjetjem, ki določa provizije, po katerih
podjetje terja od dolţnika.
10
3.2 Logični diagram
Podjetje (Slika 3.2) ima več uporabnikov (Slika 3.1), ki se prijavijo v sistem. Seveda
aplikacija omogoča tudi registracijo več podjetij v sistem, na katerih imamo potem
uporabnike.
Uporabnik hrani podatke, s katerimi se prijavi v sistem. Ker pripada podjetju, ima tudi
njegov tuji ključ.
Vse pomembne podatke, ki jih potrebujemo za kreiranje pogodb med naročniki in nami kot
izvajalcem terjalnega procesa, smo hranili v tabeli Podjetje. Ker je naročnik ţelel v
aplikaciji tudi koledar, sinhroniziran z Googlovim, potrebujemo tudi njegov Googlov
elektronski poštni naslov.
Naročnik (Slika 3.3) je oseba ali podjetje, ki sklene pogodbo z izterjevalnim podjetjem, da
lahko podjetje zanj izterjuje dolgove. Zanj moramo hraniti podatke, ki so pomembni za
izdelavo pogodbe. Popolnoma enake podatke hranimo tudi o dolţniku, vendar teh dveh
entitet zaradi laţje logike pri pisanju aplikacij ne bomo zdruţili v eno. Tako bi morali pri
poizvedbah po enem ali drugem vedno preverjati dodaten pogoj, ali je naročnik ali dolţnik.
Slika 3.1: Entiteta Uporabnik
Slika 3.2: Entiteta Podjetje
11
Slika 3.3: Entiteta Narocnik
Znotraj tabele naročnika in dolţnika ni nobenega kontaktnega atributa. Z izdelavo nove
tabele Kontakt (Slika 3.4) omogočimo uporabniku aplikacije, da dinamično doda kontaktna
polja, ki so lahko različnih tipov (elektronska pošta, telefon, fax …). Na tak način
omogočimo več telefonskih številk in elektronskih poštnih naslovov. Kontakt je preko
tujega ključa povezan z naročnikom ali dolţnikom.
Slika 3.4: Entiteta za kontaktne podatke
Osrednja enota naše podatkovne baze je pogodba (Slika 3.5), ki jo skleneta naročnik in
podjetje za izterjave. Na to pogodbo so vezane tudi vse terjatve.
Pogodbo je mogoče izbrisati, ob izbrisu se shranijo osnovni podatki izbrisane vrstice v
dnevnik izbrisanih pogodb. Da je izbris mogoč, smo nastavili na tuji ključ starša v tabeli
otroka CASCADE ob izbrisu. To smo nastavili po celi veji, Pogodba, Terjatev, Opomnik,
Kronika in Nakazilo. Ostali izbrisi v bazi niso dovoljeni v primeru, ko obstaja v bazi vpis, ki
se sklicuje na vpis, ki ga ţelimo izbrisati.
Pogodba določa pravila med izterjevalnim podjetjem in naročnikom, po katerih poteka
terjatev. Ker so lahko različnih tipov in vsebujejo različne člene, tudi te hranimo v bazi. Če
12
nek člen vsebuje podatek, ki mora biti vnesen v bazo pred generiranjem, se tudi ta shrani
v tabelo Podatek. Po pogodbi imamo določene tudi provizije, ki jih zasluţi podjetje od
izterjanega dolga. Praviloma so starejše terjatve teţje izterljive, zaradi česar so provizije
višje. Tako lahko dinamično določimo meje in provizije v %. V primeru, da te meje niso
določene, imamo v pogodbi določeno tudi privzeto provizijo, ki jo upoštevamo v tem
primeru. Znotraj pogodbe hranimo tudi rang, ki je določen po kriterijih podjetja.
Rang 4 je najvišji mogoč rang in ga doseţe pogodba, na kateri je vrednost vseh
terjatev skupaj več kot 100.000 €.
Rang 3 doseţe pogodba, ki ima število terjatev več kot 10 in hkrati skupno
vrednost vseh terjatev več kot 50.000 €.
Rang 2 doseţe pogodba, ki ima število terjatev več kot 8 ali ko je skupna vrednost
vseh terjatev več kot 20.000 € ali ko sta izpolnjena oba pogoja skupaj.
Rang 1 doseţe pogodba, ki ima vsaj 1 terjatev, katere vrednost je večja kot 0 €.
Rang 0 pomeni, da pogodba nima nobenih terjatev.
13
Slika 3.5: Entiteta Pogodba in ostale entitete, ki jo opisujejo
Vsaka terjatev (Slika 3.6) pripada eni pogodbi. V njej hranimo podatke o dolgovih in
izbrani proviziji za to terjatev, ki se določi glede na datum dolga ali pa jo nastavi uporabnik
ob kreiranju te terjatve. O procesu terjanja vodimo tudi kroniko. Vsak uporabnik si lahko
na določeni terjatvi naredi svoje opomnike. Status terjatve določa stanje med procesom
terjanja, ob zaključku pa se nastavi atribut »koncana« na 1 oziroma TRUE. Spreminjanja
terjatev aplikacija ne bo omogočila, spremeni se lahko le atribut »koncana« in pa status.
14
Slika 3.6: Entiteta Terjatev
Nakazilo (Slika 3.7) vnesemo, ko prejmemo izterjan denar. Glede na to, kam smo prejeli
sredstva, na račun podjetja ali na račun naročnika, izberemo način nakazila. Nakazilu
lahko določimo tudi račun (Slika 3.7). Ob kreiranju računa mu lahko določimo kot
postavko tudi nakazilo. Ta je lahko negativna ali pa pozitivna, glede na to, kje je nakazan
denar, pri naročniku ali pri izterjevalnem podjetju. Ti aplikacija in baza sta zasnovani za
generiranje računov, vendar ne omogočata celotnega knjigovodstva, ki ga takšno podjetje
zahteva. To tudi ni njen namen.
15
Slika 3.7: Entitete, ki sestavljajo nakazilo in račun
Pogodbe je mogoče izbrisati. Da lahko vseeno preiščemo zgodovino naročnikov, s
katerimi so sklenili pogodbe, si vodimo dnevnik izbrisanih pogodb (Slika 3.8). To je
samostojna tabela brez povezav. V njej hranimo datum izbrisa, ki se vnese samodejno ob
vnosu vrstice v tabelo, podjetje, ki naroča in sklene pogodbo, izterjevalno podjetje,
uporabniško ime baze ter številko pogodbe. Na podlagi tega vpisa lahko kasneje
poiščemo fizično pogodbo.
Slika 3.8: Entiteta Izbrisana_pogodba
16
Celoten logični diagram (Slika 3.9)
Slika 3.9: Logični diagram
17
3.3 Postavitev okolja ter generiranje baze
Za implementacijo proţilcev smo si postavili tri baze z enako shemo:
brezplačna in popularna MySQL rešitev, namenjena predvsem spletnim
aplikacijam,
SQL Server od Microsofta,
Oracle.
3.3.1 Postavitev okolja MySQL
Komplet MySQL podatkovno bazo z vsemi pripadajočimi razvojnimi orodji in SUPB-jem
najdemo na viru [18].
Potrebno se je predhodno registrirati, registracija je seveda brezplačna.
Z MySQL installerjem (Slika 3.10) smo namestili vse potrebno, naredili konfiguracijo baze
in nastavili uporabniško ime ter geslo za dostop do baze.
Slika 3.10: Namestitev MySQL podatkovne baze
V tem paketu se je namestil tudi MySQL Workbench, v katerem smo narisali logični
diagram in kasneje vstavljali podatke v tabele ter testirali naše proţilce.
18
MySQL Workbench omogoča povezavo s podatkovno bazo MySQL ter sinhronizacijo
diagrama s fizično podatkovno bazo. Tako smo izvedli »Forward Engineering« in
neposredno iz narisanega diagrama pognali ukaze za izgradnjo podatkovne baze.
3.3.2 Postavitev okolja Microsoft SQL Server
Microsoft ponuja študentom preko programa DreamSpark brezplačno programsko
razvojno opremo. Tam smo dobili Microsoftov namestitveni paket s SQL Server Express-
om in orodji za konfiguracijo ter delo in razvoj za podatkovno bazo Microsoft SQL
Managment Studio. Tudi v tem primeru nas namestitveni program vodi skozi celotno
namestitev (Slika 3.11) in konfiguracijo podatkovne baze. Za avtentikacijo1 na streţnik
smo izbrali način preko Windows uporabniškega računa (Slika 3.12), kar pomeni, da smo
prijavljeni v streţnik z istim računom kot v operacijski sistem Windows. S tem
uporabnikom bomo tudi ustvarili bazo ter proţilce.
Slika 3.11: Namestitev SQL Server podatkovne baze
1 Avtentikacija je proces v računalništvu, v katerem se mora streţnik prepričati, da je uporabnik
zares tisti uporabnik, za kogar se predstavlja, da je [27].
19
Slika 3.12: Povezava na bazo SQL Server
3.3.3 Postavitev okolja Oracle
Vodilno podjetje na področju podatkovnih baz je Oracle. Leta 1979 je kot prvo poslalo na
trg komercialno različico njihovega RDBMS (angl. relational database management
system). Je zelo zmogljiva, ampak tudi precej kompleksna in komplicirana baza, zato je
tudi bila izbrana za primerjavo razvoja proţilcev.
Na spletnem viru [19] najdemo prenos Oracle podatkovne baze ter razvojnega orodja.
Trenutna in najnovejša različica, ki je na voljo, je Oracle Database 12c Release 1, ki smo
jo uporabili.
Podobno kot pri prejšnjih dveh se tudi tukaj v paketu namesti podatkovna baza s SUPB-
jem ter z razvojnimi orodji. Kot vizualno razvojno orodje ter orodje za manipulacijo s
podatki je v paketu SQL Developer.
Po namestitvi se je potrebno prijaviti v Oracle streţnik kot sistem in tam ustvariti novega
uporabnika, s katerim bomo lahko kasneje ustvarjali tabele v bazi, triggerje in vse ostale
objekte.
V različici Oraclove podatkovne baze 12c je novost, in sicer si lahko izberemo, ali bomo
ustvarili COMMON USER račun ali LOCAL USER račun. COMMON USER bo videl vse
ţe obstoječe in prihodnje vtične baze, medtem kot bo LOCAL USER videl le določene, saj
ima omejene pravice, nastavljene s COMMON USER-jem.
Pri kreiranju COMMON USER-ja moramo slediti določenim zahtevam, kot so trenutni sejni
kontejner, ki mora biti CDB$ROOT, uporabniško ime se mora začeti z C##.
Uporabnika lahko ustvarimo preko SQL Developer-ja ali preko ukazne konzole.
20
V SQL developerju moramo biti prijavljeni s sistemskim uporabniškim računom. Z desnim
klikom na zavihek Other users ustvarimo novega uporabnika (Slika 3.13). Tako imamo
Oracle bazo pripravljeno [20].
Slika 3.13: Ustvarjanje novega uporabnika v SQL Developerju
3.3.4 Ustvarjanje fizične podatkovne baze
ER in logični diagram smo narisali v MySQL Workbenchu, iz katerega smo preprosto
generirali bazo. Ampak potrebno je ustvariti še dve bazi, ki bosta identični. Workbench je
seveda namenjen MySQL-u, in ne pozna sintakse za ostale podatkovne baze, zato je
potrebno ali diagram narisati ali generacijsko skripto napisati še v dveh drugih jezikih.
V našem primeru bi oboje šlo, vendar bi vzelo precej časa. V primeru, kjer bi imeli tabel še
nekajkrat več, bi bilo to praktično nemogoče in preveč časovno potratno.
V ta namen smo poiskali program, ki bi omogočal izdelavo ER modela in logičnega
diagrama, potem pa prenesel baze v drugo okolje ali pa vsaj generiral skrpito za različne
podatkovne baze.
Poskusili smo z razvojnim orodjem DBSchema [21].
Najprej se je bilo potrebno povezati na ţe obstoječe baze. S povezavo na MySQL (Slika
3.15) ni bilo teţav, saj nam ţe aplikacija DBSchema sama poišče in predvidi privzete
nastavitve za MySQL bazo. Potrebno je le vnesti uporabniško ime in geslo. Tudi na
Oracle (Slika 3.14) smo se povezali brez teţav, nekaj teţav je bilo edino pri povezavi na
Microsoftov SQL Server.
21
Slika 3.14: Povezava DBScheme na Oracle
Slika 3.15: Povezava DBScheme na MySQL
Pri povezavi na Microsoft SQL Server je potrebno s pomočjo SQL Server Configuration
Managerja najprej omogočiti povezavo preko TCP/IP, saj je po privzetih nastavitvah
izklopljena. TCP port mora biti nastavljen na 1433. Potrebno je izbrati tudi pravilen način
avtentikacije.
V nastavitvah projekta smo na začetku izbrali privzeto bazo, to je MySQL. Iz ţe obstoječe
podatkovne baze MySQL smo s povratnim inţenirstvom dobili logični diagram. Nato smo
se povezali s streţnikom podatkovne baze Oracle in projekt nastavili na Oracle. Med
menjavo iz MySQL na Oracle je bilo potrebno ročno popraviti nekaj podatkovnih tipov, ki
22
jih program sam ni zamenjal. To so bili na primer »MySQL INT« v »ORACLE NUMBER«,
»MySQL text« v »ORACLE CLOB« ter nastavitve privzetih vrednosti.
Praviloma je bilo vse pripravljeno za sinhronizacijo logičnega modela s podatkovno bazo
Oracle, s katero smo se uspešno povezali. Sinhronizacija in kreiranje nista uspeli.
Pojavljale so se napake, kot so nedoločena shema, nepravilni podatkovni tipi in privzete
vrednosti.
Podobni problemi so se pojavili tudi pri transformaciji v Microsoftovo bazo, zato smo
skripte generirali in jih nato ročno pregledali ter popravili.
Razlike in posebnosti med vsemi tremi bazami, ki smo jih ugotovili med generiranjem
podatkovnih baz, so prikazane v spodnji tabeli (Tabela 3.1).
Tabela 3.1: Razlike pri generiranju fizične sheme
MySQL Oracle DB Microsoft SQL Server
Primarni
ključ z
avtomatskim
številčenjem
AUTO_INCREMENT
poleg atributa in dodan
PRIMARY KEY
(`idDelovnoMesto`)
V 12c različici prvič
v uporabi
idUporabnik
NUMBER
GENERATED BY
DEFAULT ON
NULL AS
IDENTITY,
idPostavka int NOT
NULL IDENTITY
Celoštevilčni
podatkovni
tip
INT NUMBER brez
decimalnih mest.
Integer je označen
kot zastarel.
int
Časovna
značka
TIMESTAMP z
privzeto vrednostjo
CURRENT_TIMESTA
MP
TIMESTAMP z
privzeto vrednostjo
CURRENT_TIMES
TAMP
Timestamp je namenjen
verzioniranju in se
posodablja z vsakim
posodabljanjem vrstice. Iz
njega ni mogoče
izračunati časa. V ta
namen se uporablja date
s privzeto vrednostjo
GETDATE()
23
Dolžina
imena
objekta
Brez teţav in omejitev Dolţina imena
objekta, ki se kreira
(tabela, omejitev,
indeks …) mora biti
manjša od 30
Brez teţav in omejitev
3.3.4.1 Primer SQL stavka za kreiranje tabele MySQL
1. CREATE TABLE IF NOT EXISTS `iztirjevalnica`.`Pogodba` ( 2. `idPogodba` INT NOT NULL AUTO_INCREMENT, 3. `st` VARCHAR(15) NOT NULL, 4. `datum` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAM
P, 5. `Tip_pogodbe_idTip_pogodbe` INT NOT NULL, 6. `Narocnik_idNarocnik` INT NOT NULL, 7. `Podjetje_idPodjetje` INT NOT NULL, 8. `uspesnost` INT NOT NULL DEFAULT 0, 9. `pricakovan_zasluzek` DECIMAL(10,2) NOT NULL DEFAULT 0, 10. `Kraj_idKraj` INT NOT NULL, 11. `Dolznik_idDolznik` INT NOT NULL, 12. `privzeta_provizija` DECIMAL(10,2) NOT NULL, 13. `rang_pogodbe` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '0-nedefinirano, 1-
nizka, 2-srednja, 3-visoka, 4-zlata', 14. PRIMARY KEY (`idPogodba`), 15. UNIQUE INDEX `st_UNIQUE` (`st` ASC), 16. INDEX `fk_Pogodba_Tip_pogodbe1_idx` (`Tip_pogodbe_idTip_pogodbe` ASC), 17. INDEX `fk_Pogodba_Narocnik1_idx` (`Narocnik_idNarocnik` ASC), 18. INDEX `fk_Pogodba_Podjetje1_idx` (`Podjetje_idPodjetje` ASC), 19. INDEX `fk_Pogodba_Kraj1_idx` (`Kraj_idKraj` ASC), 20. INDEX `fk_Pogodba_Dolznik1_idx` (`Dolznik_idDolznik` ASC), 21. CONSTRAINT `fk_Pogodba_Tip_pogodbe1` 22. FOREIGN KEY (`Tip_pogodbe_idTip_pogodbe`) 23. REFERENCES `iztirjevalnica`.`Tip_pogodbe` (`idTip_pogodbe`) 24. ON DELETE NO ACTION 25. ON UPDATE NO ACTION, 26. CONSTRAINT `fk_Pogodba_Narocnik1` 27. FOREIGN KEY (`Narocnik_idNarocnik`) 28. REFERENCES `iztirjevalnica`.`Narocnik` (`idNarocnik`) 29. ON DELETE NO ACTION 30. ON UPDATE NO ACTION, 31. CONSTRAINT `fk_Pogodba_Podjetje1` 32. FOREIGN KEY (`Podjetje_idPodjetje`) 33. REFERENCES `iztirjevalnica`.`Podjetje` (`idPodjetje`) 34. ON DELETE NO ACTION 35. ON UPDATE NO ACTION, 36. CONSTRAINT `fk_Pogodba_Kraj1` 37. FOREIGN KEY (`Kraj_idKraj`) 38. REFERENCES `iztirjevalnica`.`Kraj` (`idKraj`) 39. ON DELETE NO ACTION 40. ON UPDATE NO ACTION, 41. CONSTRAINT `fk_Pogodba_Dolznik1` 42. FOREIGN KEY (`Dolznik_idDolznik`) 43. REFERENCES `iztirjevalnica`.`Dolznik` (`idDolznik`) 44. ON DELETE NO ACTION 45. ON UPDATE NO ACTION) 46. ENGINE = InnoDB;
24
3.3.4.2 Primer SQL stavka za kreiranje tabele ORACLE
1. CREATE TABLE pogodba ( 2. idPogodba NUMBER GENERATED BY DEFAULT ON NULL AS IDENTITY, 3. st nvarchar2(15) NOT NULL, 4. datum timestamp DEFAULT CURRENT_TIMESTAMP NOT NULL, 5. Tip_pogodbe_idTip_pogodbe number(9,0) NOT NULL, 6. Narocnik_idNarocnik number(9,0) NOT NULL, 7. Podjetje_idPodjetje number(9,0) NOT NULL, 8. uspesnost number(9,0) DEFAULT 0 NOT NULL, 9. pricakovan_zasluzek number(9,2) DEFAULT 0.00 NOT NULL, 10. Kraj_idKraj number(9,0) NOT NULL, 11. Dolznik_idDolznik number(9,0) NOT NULL, 12. privzeta_provizija number(9,2) NOT NULL, 13. rang_pogodbe number(1,0) DEFAULT 0 NOT NULL, 14. CONSTRAINT pk_pogodba PRIMARY KEY ( idPogodba ) , 15. CONSTRAINT st_UNIQUE UNIQUE ( st ) 16. ); 17. 18. CREATE INDEX fk_Pogodba_Tidbe1_idx ON pogodba ( Tip_pogodbe_idTip_pogodbe ); 19. 20. CREATE INDEX fk_Pogodba_Narocnik1_idx ON pogodba ( Narocnik_idNarocnik ); 21. 22. CREATE INDEX fk_Pogodba_Podjetje1_idx ON pogodba ( Podjetje_idPodjetje ); 23. 24. CREATE INDEX fk_Pogodba_Kraj1_idx ON pogodba ( Kraj_idKraj ); 25. 26. CREATE INDEX fk_Pogodba_Dolznik1_idx ON pogodba ( Dolznik_idDolznik ); 27. 28. COMMENT ON COLUMN pogodba.rang_pogodbe IS '0-nedefinirano, 1-nizka, 2-srednja, 3-
visoka, 4-zlata'; 29. 30. ALTER TABLE pogodba ADD CONSTRAINT fk_Pogodba_Dolznik1 FOREIGN KEY ( Dolznik_idDo
lznik ) REFERENCES dolznik( idDolznik ); 31. 32. ALTER TABLE pogodba ADD CONSTRAINT fk_Pogodba_Kraj1 FOREIGN KEY ( Kraj_idKraj ) R
EFERENCES kraj( idKraj ); 33. 34. ALTER TABLE pogodba ADD CONSTRAINT fk_Pogodba_Narocnik1 FOREIGN KEY ( Narocnik_id
Narocnik ) REFERENCES narocnik( idNarocnik ); 35. 36. ALTER TABLE pogodba ADD CONSTRAINT fk_Pogodba_Podjetje1 FOREIGN KEY ( Podjetje_id
Podjetje ) REFERENCES podjetje( idPodjetje ); 37. 38. ALTER TABLE pogodba ADD CONSTRAINT fk_Pogodba_Tip_pogodbe1 FOREIGN KEY ( Tip_pogo
dbe_idTip_pogodbe ) REFERENCES tip_pogodbe( idTip_pogodbe );
3.3.4.3 Primer SQL stavka za kreiranje tabele SQL Server
1. CREATE TABLE pogodba ( 2. idPogodba int NOT NULL IDENTITY, 3. st varchar(15) NOT NULL , 4. datum datetime NOT NULL CONSTRAINT defo1_datum DEFAULT GETDATE
() , 5. Tip_pogodbe_idTip_pogodbe int NOT NULL , 6. Narocnik_idNarocnik int NOT NULL , 7. Podjetje_idPodjetje int NOT NULL , 8. uspesnost int NOT NULL CONSTRAINT defo_uspesnost DEFAULT 0 , 9. pricakovan_zasluzek decimal(10,2) NOT NULL CONSTRAINT defo_pricakovan_zasluz
ek DEFAULT 0.00 , 10. Kraj_idKraj int NOT NULL , 11. Dolznik_idDolznik int NOT NULL ,
25
12. privzeta_provizija decimal(10,2) NOT NULL , 13. rang_pogodbe int NOT NULL CONSTRAINT defo_rang_pogodbe DEFAULT 0 , 14. CONSTRAINT pk_pogodba PRIMARY KEY ( idPogodba ), 15. CONSTRAINT st_UNIQUE UNIQUE ( st ) 16. ); 17. 18. ALTER TABLE pogodba ADD CONSTRAINT fk_Pogodba_Dolznik1 FOREIGN KEY ( Dolznik_idDo
lznik ) REFERENCES dolznik( idDolznik ) ON DELETE NO ACTION ON UPDATE NO ACTION;
19. 20. ALTER TABLE pogodba ADD CONSTRAINT fk_Pogodba_Kraj1 FOREIGN KEY ( Kraj_idKraj ) R
EFERENCES kraj( idKraj ) ON DELETE NO ACTION ON UPDATE NO ACTION; 21. 22. ALTER TABLE pogodba ADD CONSTRAINT fk_Pogodba_Narocnik1 FOREIGN KEY ( Narocnik_id
Narocnik ) REFERENCES narocnik( idNarocnik ) ON DELETE NO ACTION ON UPDATE NO ACTION;
23. 24. ALTER TABLE pogodba ADD CONSTRAINT fk_Pogodba_Podjetje1 FOREIGN KEY ( Podjetje_id
Podjetje ) REFERENCES podjetje( idPodjetje ) ON DELETE NO ACTION ON UPDATE NO ACTION;
25. 26. ALTER TABLE pogodba ADD CONSTRAINT fk_Pogodba_Tip_pogodbe1 FOREIGN KEY ( Tip_pogo
dbe_idTip_pogodbe ) REFERENCES tip_pogodbe( idTip_pogodbe ) ON DELETE NO ACTION ON UPDATE NO ACTION;
3.4 Aktivnosti, na katere so bo odzvala baza
Akcije, ki se morajo izvesti nad vnesenimi vrsticami ali vrsticami (podatki), ki so v kakršni
koli povezavi do njih, bodisi v isti ali drugi tabeli, takoj po vnosu, izbrisu ali spremembi,
lahko implementiramo s pomočjo proţilcev na nivoju podatkovne baze ali na nivoju
aplikacije.
Implementirali smo proţilce na nivoju podatkovne baze, ki prihranijo precej programiranja
pri aplikaciji.
3.4.1 Aktivnosti nad celotno PB
1. Onemogoči izbris tabele »Izbrisana_pogodba«.
2. V posebno tabelo zapisuj prijave v podatkovno bazo (uporabniško ime, datum in
čas prijave, streţnik, aplikacija).
3. V posebno tabelo shranjuj akcije, ki se zgodijo v bazi (vsaj kreiranje tabel in izbris
tabel. Če je mogoče, tudi ostale akcije).
3.4.2 Aktivnosti nad podatki
4. Pred vnosom naročnika, dolţnika ali podjetja preveri, če je davčni zavezanec. Če
je, dodaj davčni številki predpono 'SI'.
26
5. Po vnosu nakazila naredi zaznamek v kroniki, ki pripada terjatvi, za katero je bilo
izvedeno nakazilo.
6. Po vnosu terjatve ali izbrisu terjatve nastavi rang pogodbe glede na ustrezne
pogoje. Upoštevaj znesek glavnice.
7. Samostojno naj se izračunava plačan del terjatve glede na vnesena in izbrisana
nakazila v bazi. Nakazila ni mogoče urejati/spreminjati.
8. Izračunaj in posodabljaj uspešnost na pogodbi glede na to, koliko terjatev je
uspešno zaključenih.
9. Ob izbrisu pogodbe vnesi vrstico z osnovnimi podatki (dolţnik, naročnik in št.
pogodbe) v tabelo »Izbrisana_pogodba«.
10. Ob vnosu nove terjatve nastavi provizijo glede na ustrezne pogoje, ki so shranjeni
v proviziji pogodbe. Če datum dolga ne ustreza pogojem, izberi privzeto provizijo,
shranjeno na pogodbi. V primeru, da uporabnik vnese svojo provizijo, upoštevaj
tisto, ne glede na pogoje ali privzeto provizijo, shranjeno v pogodbi.
11. Ob vnosu nakazila izračunaj pričakovan dobiček glede na provizijo.
12. Onemogoči izbris vrstice iz tabele »Izbrisana pogodba«.
27
3.5 Implementacija proţilcev
3.5.1 MySQL proţilci
Tabela 3.2: MySQL prožilci
Pogodba Izbrisana pogodba Naročnik Dolžnik
BEFORE DELETE BEFORE DELETE BEFORE INSERT BEFORE INSERT
log_izbrisane_pogodbe
(9.)
prepreci_brisanje
(12.)
preveri_davcno (4.) preveri_davcno (4.)
Podjetje Nakazilo Terjatev Podatkovna baza
BEFORE INSERT AFTER INSERT AFTER INSERT Ne obstaja v MySQL
preveri_davcno (4.) zaznamek_v_kroniki
_nakazilo (5.)
(zdruţen (C))
doloci_rang_pogodbe
(6.) (zdruţen (A))
(1.)
BEFORE INSERT AFTER DELETE Ne obstaja v MySQL
izracunaj_predviden
_dobicek_nakazila
(11.)
doloci_rang_pogodbe
(6.) (zdruţen (B))
(2.)
AFTER INSERT BEFORE INSERT Ne obstaja v MySQL
posodobi_ze_placano
(7.) (zdruţen (C))
nastavi_provizijo
(10.)
(3.)
AFTER DELETE AFTER INSERT
posodobi_ze_placano
(7.)
statistika_uspesnosti
(8.) (zdruţen (A))
AFTER DELETE
statistika_uspesnosti
(8.) (zdruţen (B))
AFTER UPDATE
statistika_uspesnosti
(8.)
28
Verzija baze na kateri smo implementirali: 5.6.19-enterprise-commercial-advanced
MySQL ne omogoča več kot enega proţilca nad tabelo z enakim časom (BEFORE ali
AFTER) in dogodek (INSERT, UPDATE, DELETE). Se pravi, implementiramo lahko
največ 6 proţilcev na eni tabeli, ti pa se morajo vsi razlikovati po času proţenja.
Ker po naših zahtevah potrebujemo več kot en AFTER INSERT proţilec za terjatev, bomo
v takih primerih zdruţili logiko v enega (Tabela 3.2).
MySQL tudi ne omogoča, da bi se en proţilec proţil ob več dogodkih, primer AFTER
INSERT OR DELTE prozilec. Zato je potrebno napisati vsakega posebej, lahko pa
zdruţimo logiko, jo napišemo v shranjeno proceduro in jo kot funkcijo pokličemo v
proţilcu.
V MySQL-u ni bilo mogoče implementirati proţilcev, ki se proţijo ob DDL dogodkih. Tako
ni bilo mogoče napisati proţilcev, ki bi se proţili ob dogodkih 1., 2. in 3. točke.
Prepreči brisanje vrstice v tabeli Izbrisane_pogodbe (12.)
1. delimiter // 2. DROP TRIGGER if exists prepreci_brisanje // 3. CREATE TRIGGER prepreci_brisanje 4. BEFORE DELETE 5. ON izbrisana_pogodba 6. FOR EACH ROW 7. BEGIN 8. CALL do_not_delete(); -- klic funkcije ki ne obstaja 9. END;//
Tukaj prisilimo proţilec do napake, ki se zgodi ob klicu funkcije, ki ne obstaja, in ustavi
izvajanje procesa izbrisa, saj se zaradi neuspešnega proţilca akcija izbrisa ne izvede do
konca. Seveda to varuje samo vrstico pred vnosom, še vedno lahko z DROP ukazom nad
tabelo izgubimo celotno tabelo in vse podatke v njej.
Dodaj davčni številki SI, če je vnesena oseba davčni zavezanec (4.)
1. delimiter // 2. DROP TRIGGER if exists preveri_davcno_narocnik // 3. CREATE TRIGGER preveri_davcno_narocnik 4. BEFORE INSERT ON narocnik FOR EACH ROW 5. BEGIN 6. IF (NEW.davcni_zavezanec != 0) THEN 7. set NEW.davcna = CONCAT('SI', NEW.davcna); -- funkcija za združ. nizov 8. END IF; 9. END;//
Podjetje, naročnik in dolţnik vsebujejo podatek o davčni številki. Ker je aplikacija za
ciljnega uporabnika, ki bo upravljal samo s slovenskimi strankami, vemo, da bo davčna
številka vedno v takšni obliki. Naredili smo proţilec, ki uredi davčno številko pred vpisom.
Če je davčni zavezanec, dodamo predpono SI.
29
Nastavi provizijo (10.)
1. delimiter // 2. DROP TRIGGER if exists nastavi_provizijo // 3. CREATE TRIGGER nastavi_provizijo 4. BEFORE INSERT ON terjatev FOR EACH ROW 5. BEGIN 6. IF NEW.provizija IS NULL OR NEW.provizija='' THEN 7. SET NEW.provizija = (SELECT provizija FROM provizija 8. WHERE Pogodba_idPogodba=NEW.Pogodba_idPogodba 9. AND mlajse_od<NEW.datum_dolga 10. order by mlajse_od DESC LIMIT 1); 11. END IF; 12. IF NEW.provizija IS NULL OR NEW.provizija='' THEN 13. SET NEW.provizija = (SELECT privzeta_provizija 14. FROM Pogodba WHERE idPogodba=NEW.Pogodba_idPogodba);
15. END IF; 16. END;//
V prvem IF stavku preverjamo, če je nastavil provizijo uporabnik, preden je pognal vnos
v bazo. Če provizija ni nastavljena, se poišče pripadajoča provizija glede na datum.
Poiščemo prvo provizijo, ki ima manjši datum od datuma dolga. Če ta provizija ne obstaja,
se v drugem IF stavku nastavi provizija na privzeto provizijo iz pogodbe.
Zdruţen proţilec posodobi statistiko (8.) in določi rang (6.).
1. delimiter // 2. DROP TRIGGER if exists posodobi_statistiko_in_doloci_rang_pogodbe_izbris // 3. CREATE TRIGGER posodobi_statistiko_in_doloci_rang_pogodbe_izbris 4. AFTER DELETE ON terjatev FOR EACH ROW 5. BEGIN 6. 7. --spremenljivke za dolocilo ranga 8. DECLARE stevilo_terjatev INT; 9. DECLARE skupna_vrednost_terjanja DECIMAL; 10. DECLARE rang INT; 11. 12. --spremenljivke za izracun statistike 13. DECLARE usp INT; --uspesne 14. DECLARE vse INT; --vse 15. DECLARE kon INT; --koncane 16. 17. --doloci rang 18. SELECT SUM(glavnica) INTO skupna_vrednost_terjanja FROM Terjatev 19. Where Pogodba_idPogodba = OLD.Pogodba_idPogodba; 20. SELECT COUNT(idTerjatev) INTO stevilo_terjatev FROM Terjatev 21. WHERE Pogodba_idPogodba = OLD.Pogodba_idPogodba; 22. 23. IF(skupna_vrednost_terjanja>100000) THEN 24. SET rang = 4; 25. ELSEIF(stevilo_terjatev>10)AND(skupna_vrednost_terjanja>50000) THEN 26. SET rang = 3; 27. ELSEIF(stevilo_terjatev>8)OR(skupna_vrednost_terjanja>20000) THEN 28. SET rang = 2; 29. ELSEIF(stevilo_terjatev>1)AND(skupna_vrednost_terjanja>0) THEN 30. SET rang = 1; 31. ELSE 32. SET rang = 0;
30
33. END IF; 34. 35. UPDATE Pogodba SET rang_pogodbe = rang 36. WHERE idPogodba = OLD.Pogodba_idPogodba; 37. --/doloci rang 38. --posodobi statistiko 39. SELECT COUNT(idTerjatev) INTO kon FROM terjatev 40. WHERE Pogodba_idPogodba=OLD.Pogodba_idPogodba AND koncana=1; 41. SELECT COUNT(idTerjatev) INTO vse FROM terjatev 42. WHERE Pogodba_idPogodba=OLD.Pogodba_idPogodba; 43. 44. SET usp = kon/vse*100; 45. 46. UPDATE pogodba SET uspesnost = usp WHERE idPogodba=OLD.Pogodba_idPogodba; 47. --/posodobi statstiko 48. END;//
Kot ţe omenjeno, MySQL ne omogoča več proţilcev, ki bi se proţili ob istem času, zato
smo sintakso teh dveh zdruţili znotraj enega.
31
3.5.2 Oracle proţilci
Tabela 3.3: Oracle prožilci
Pogodba Izbrisana pogodba Naročnik Dolžnik
BEFORE DELETE BEFORE DELETE BEFORE INSERT BEFORE INSERT
log_izbrisane_pogodbe
(9.)
prepreci_brisanje
(12.)
preveri_davcno (4.) preveri_davcno (4.)
Podjetje Nakazilo Terjatev Podatkovna baza
BEFORE INSERT AFTER INSERT AFTER INSERT OR
DELET
BEFORE DROP OR
TRUNCATE ON
C##URBAN.SCHEMA
preveri_davcno (4.) zaznamek_v_kroniki
_nakazilo (5.)
doloci_rang_pogodbe
(6.)
onemogoci_brisanje
(1.)
BEFORE INSERT BEFORE INSERT AFTER DDL ON
SCHEMA
izracunaj_predviden
_dobicek_nakazila
(11.)
nastavi_provizijo
(10.)
ddl_events (2.)
AFTER INSERT OR
DELETE
AFTER INSERT OR
DELETE OR
UPDATE
AFTER LOGON ON
DATABASE
posodobi_ze_placano
(7.)
statistika_uspesnosti
(8.)
logon_log (3.)
Ker Oracle omogoča več proţilcev na isti tabeli in na istem dogodku, ni bilo teţav, kot smo
jih imeli pri MySQL-u. V primerih, ko se proţilec proţi ob več dogodkih (npr.: po izbrisu in
po vnosu), lahko to zdruţimo, in v pogoj napišemo »AFTER DELETE OR INSERT«.
V Oraclu lahko uporabljamo tudi proţilce, ki se proţijo ob DDL dogodkih, zato smo lahko
implementirali tudi prve tri iz seznama, ki jih v MySQL nismo mogli.
Teţava, na katero smo naleteli tukaj, je bila napaka z imenom »ORA-04091: table
ime_tabele is mutating, trigger/function may not see it«.
Zaradi zahtev smo morali prilagoditi shemo in to rešiti na način z dvema ločenima
proţilcema.
32
Posodobi ţe plačano (7.)
1. create or replace 2. trigger posodobi_ze_placano 3. AFTER INSERT OR DELETE ON NAKAZILA FOR EACH ROW 4. DECLARE 5. p NUMBER; 6. BEGIN 7. IF INSERTING THEN 8. BEGIN 9. SELECT placano INTO p FROM Terjatev WHERE idTerjatev = :new.Terjatev_idTerj
atev; 10. EXCEPTION 11. WHEN NO_DATA_FOUND THEN 12. p := NULL; 13. END; 14. p := p + :new.vrednost; 15. UPDATE Terjatev SET placano = p WHERE idTerjatev = :new.Terjatev_idTerjatev;
16. 17. ELSIF DELETING THEN 18. BEGIN 19. SELECT placano INTO p FROM Terjatev WHERE idTerjatev = :old.Terjatev_idTerj
atev; 20. EXCEPTION 21. WHEN NO_DATA_FOUND THEN 22. p := NULL; 23. END; 24. p := p - :old.vrednost; 25. UPDATE Terjatev SET placano = p WHERE idTerjatev = :old.Terjatev_idTerjatev;
26. END IF; 27. END;
Vidimo, da lahko določimo več dogodkov, ob katerih se proţi, pozorni pa moramo biti, da
implementiramo pravilno. Ob INSERT-u nimamo :old vrednosti, ob DELETE-u pa nimamo
:new vrednosti.
Izjemo ali EXCEPTION blok dodamo v primeru NO_DATA_FOUND, kar nastopi takrat, ko
poizvedba ne najde podatka.
DDL proţilec, ki shranjuje prijave (3.)
1. create or replace 2. trigger logon_log 3. AFTER LOGON ON DATABASE 4. BEGIN 5. insert into logon_log values( 6. user, 7. sys_context('USERENV','SESSIONID'), 8. sys_context('USERENV','HOST'), 9. current_timestamp 10. ); 11. END;
Za namen shranjevanja prijav smo seveda pred tem ustvarili preprosto tabelo, v kateri
smo hranili uporabnika, njegov ID, gostitelja ter čas prijave v bazo.
33
DDL proţilec, ki onemogoča izbris tabele (1.)
1. create or replace 2. trigger onemogoci_brisanje 3. BEFORE DROP OR TRUNCATE 4. ON C##URBAN.SCHEMA 5. BEGIN 6. IF ora_dict_obj_type = 'TABLE' AND ora_dict_obj_name = 'IZBRISANA_POGODBA' TH
EN 7. raise_application_error(-20900,'Izbris te tabele ni mogoc.'); 8. END IF; 9. 10. END;
Onemogočili smo samo DROP ali TRUNCATE nad objekti tabela in nad tabelami z
imenom 'IZBRISANA _POGODBA'.
Proţilcev določi rang pogodbe (6.) in posodobi statistiko uspešnosti (8.), zato nismo mogli
implementirati na način, kot smo si zamislili (kakor je šlo tudi pri MySQL-u).
Če uporabimo enako semantiko kot pri MySQL-u, se proţilec prevede pravilno, brez
napak. Vendar ob proţenju dobimo napako z nazivom : »ORA-04091: table TERJATEV
is mutating, trigger/function may not see it«, akcije pa se odvrtijo nazaj, torej ni mogoče
izvesti akcije, ki proţi ta proţilec.
1. create or replace 2. trigger doloci_rang_pogodbe 3. AFTER INSERT OR DELETE ON TERJATEV FOR EACH ROW 4. --manjkajoce vrstice 5. -------------------- 6. --manjkajoce vrstice 7. IF INSERTING THEN 8. SELECT SUM(glavnica) INTO skupna_vrednost_terjanja --napaka 9. FROM Terjatev Where Pogodba_idPogodba = :new.Pogodba_idPogodba; 10. SELECT COUNT(idTerjatev) INTO stevilo_terjatev --napaka 11. FROM Terjatev WHERE Pogodba_idPogodba = :new.Pogodba_idPogodba; 12. ELSIF DELETING THEN 13. SELECT SUM(glavnica) INTO skupna_vrednost_terjanja --napaka 14. FROM Terjatev Where Pogodba_idPogodba = :old.Pogodba_idPogodba; 15. SELECT COUNT(idTerjatev) INTO stevilo_terjatev --napaka 16. FROM Terjatev WHERE Pogodba_idPogodba = :old.Pogodba_idPogodba; 17. --manjkajoce vrstice 18. -------------------- 19. --manjkajoce vrstice 20. END;
Teţava je bila v poizvedovalnem SQL stavku, ki je vračala skupno vrednost vseh terjatev
in štela število terjatev. Oracle namreč ne dovoli, da znotraj proţilca izvajamo SQL
poizvedbe ali druge akcije nad tabelo, ki je proţilec proţila, v našem primeru tabela
Terjatev. Prav tako je nemogoče izvesti akcije nad to tabelo iz drugega proţilca, ki je bil
proţen zaradi tega. Recimo, da v tem proţilcu izvedemo UPDATE nad tabelo Pogodba, to
pomeni, da tudi v proţilcu, ki je proţen na UPDATE Pogodbe, ne moremo izvajati akcij
nad tabelo Terjatev.
34
Na spletu najdemo nekaj načinov in nasvetov, kako se izogniti omenjeni napaki. Nekateri
so precej zahtevni, drugi manj, izkazalo pa se je, da je najbolj pametno preoblikovati
proţilec tako, da do tega ne pride. Če uporabljamo proţilec nad tabelo, ne nad vrstico, se
ta napaka ne zgodi, vendar v našem primeru potrebujemo vrstico, saj moramo vedeti,
katera pogodba pripada vneseni vrstici.
Eden od načinov, kako rešiti teţavo s pomočjo paketov, lastnih podatkovnih tipov in
procedur, je predstavljen v [22] in [23].
Mi smo stvar rešili tako, da smo tabeli Pogodba dodali dva stolpca, ki sta hranila podatka
o številu pogodb in skupni vrednosti pogodb (glavnic). Tako nam v tem primeru tega ne bo
več potrebno izračunavati. Vendar smo potrebovali dodaten proţilec, ki skrbi za to, da se
stolpca osveţujeta in sta aţurna.
Proţilec, ki skrbi za osveţevanje podatkov o skupni vrednosti terjatev ter o številu terjatev.
1. create or replace 2. trigger doloci_rang_pogodbe 3. AFTER INSERT OR DELETE ON TERJATEV FOR EACH ROW 4. DECLARE 5. skup NUMBER; 6. rang NUMBER; 7. BEGIN 8. IF INSERTING THEN 9. SELECT skupna_vrednost_terjatev INTO skup 10. FROM pogodba WHERE idPogodba = :new.Pogodba_idPogodba; 11. skup := skup + :new.glavnica; 12. UPDATE Pogodba SET skupna_vrednost_terjatev = skup 13. WHERE idPogodba = :new.Pogodba_idPogodba; 14. ELSIF DELETING THEN 15. SELECT skupna_vrednost_terjatev INTO skup 16. FROM pogodba WHERE idPogodba = :old.Pogodba_idPogodba; 17. skup := skup - :old.glavnica; 18. UPDATE Pogodba SET skupna_vrednost_terjatev = skup 19. WHERE idPogodba = :old.Pogodba_idPogodba; 20. END IF; 21. 22. END;
Iz zgornje kode lahko razberemo, da se zgodi UPDATE nad tabelo Pogodba. Zato smo v
pogodbi napisali proţilec BEFORE UPDATE, ki nastavi ustrezen rang.
1. create or replace 2. trigger doloci_rang_pogodbe_upd 3. BEFORE UPDATE ON POGODBA 4. FOR EACH ROW 5. DECLARE 6. stevilo_terjatev NUMBER; 7. skupna_vrednost_terjanja NUMBER; 8. rang NUMBER; 9. BEGIN 10. stevilo_terjatev := :new.vse_terjatve; 11. skupna_vrednost_terjanja := :new.skupna_vrednost_terjatev; 12. IF(skupna_vrednost_terjanja>100000) THEN 13. rang := 4; 14. ELSIF(stevilo_terjatev>10)AND(skupna_vrednost_terjanja>50000) THEN 15. rang := 3; 16. ELSIF(stevilo_terjatev>8)OR(skupna_vrednost_terjanja>20000) THEN 17. rang := 2; 18. ELSIF(stevilo_terjatev>1)AND(skupna_vrednost_terjanja>0) THEN
35
19. rang := 1; 20. ELSE 21. rang := 0; 22. END IF; 23. :new.rang_pogodbe :=rang; 24. END;
36
3.5.3 MS SQL server proţilci
Tabela 3.4: SQL Server prožilci
Pogodba Izbrisana pogodba Naročnik Dolžnik
AFTER DELETE INSTEAD OF
DELETE
INSTEAD OF
INSERT
INSTEAD OF
INSERT
log_izbrisane_pogodbe
(9.)
prepreci_brisanje
(12.)
preveri_davcno (4.) preveri_davcno (4.)
Podjetje Nakazilo Terjatev Podatkovna baza
INSTEAD OF INSERT AFTER INSERT AFTER INSERT,
DELETE
FOR
DROP_TABLE
preveri_davcno (4.) zaznamek_v_kroniki
_nakazilo (5.)
doloci_rang (6.) onemogoči_izbris
_tabele (1.)
INSTEAD OF
INSERT
INSTEAD OF
INSERT
ON DATABASE
FOR [Event, …]
izracunaj_predviden
_dobicek_nakazila
(11.)
nastavi_provizijo
(10.)
audit_ddl (2.)
AFTER INSERT,
DELETE
AFTER UPDATE,
INSERT, DELETE
ON ALL SERVER
FOR DATABASE
posodobi_ze_placano
(7.)
statistika_uspesnosti
(8.)
Logon_audit (3.)
Sintaksa pisanja proţilcev se precej razlikuje od Oracle-ove in MySQL-ove. Posebnost je
tudi to, da SQL Server ne pozna BEFORE proţilca. Obstaja pa INSTEAD OF, s katerim
prepišemo določen SQL ukaz. SQL Server pozna tudi DDL proţilce.
Proţilec nastavi provizijo, ki se zgodi namesto vnosa v bazo ob vstavljanju nove terjatve v
bazo (10.).
1. CREATE TRIGGER [dbo].[nastavi_provizijo] 2. ON [dbo].[terjatev] 3. INSTEAD OF INSERT AS 4. DECLARE 5. @provizija int, 6. @pogodba_id int, 7. @datum_dolga datetime; 8. BEGIN
37
9. SELECT @provizija = provizija, 10. @datum_dolga=datum_dolga, 11. @pogodba_id = Pogodba_idPogodba FROM inserted; 12. 13. IF(@provizija IS NULL OR @provizija = '') 14. BEGIN 15. SELECT @provizija = provizija 16. FROM provizija 17. WHERE Pogodba_idPogodba = @pogodba_id AND mlajse_od = 18. (SELECT MAX(mlajse_od) 19. FROM provizija 20. WHERE mlajse_od < @datum_dolga); 21. END 22. IF(@provizija IS NULL OR @provizija = '') 23. BEGIN 24. SELECT @provizija = privzeta_provizija 25. FROM pogodba 26. WHERE idPogodba = @pogodba_id; 27. END 28. INSERT INTO [terjatev] SELECT [glavnica] 29. ,[placano] 30. ,[obresti] 31. ,[sodni_stroski] 32. ,[ostali_stroski] 33. ,@provizija 34. ,[Status_terjatve_id] 35. ,[Pogodba_idPogodba] 36. ,[datum_dolga] 37. ,[koncana] 38. ,[skupaj] 39. FROM inserted; 40. END
Logika iskanja ustrezne terjatve je enaka kot pri Oraclu in MySQL-u, vendar moramo
potem še izvesti vpis v bazo (INSERT), saj smo uporabili proţilec INSTEAD OF, ki ne
pokliče metode INSERT po uspešni izvršitvi proţilca, ampak metodo prepiše.
Podobna rešitev je tudi za preprečitev brisanja vrstic iz tabele Izbrisana pogodba (12.)
1. CREATE TRIGGER [dbo].[prepreci_brisanje] 2. ON [dbo].[izbrisana_pogodba] 3. INSTEAD OF DELETE AS 4. BEGIN 5. RAISERROR ('Brisanje zgodovine pogodb ni dovoljeno.', 16, 1) 6. END
Največ teţav smo imeli pri implementaciji proţilca, ki shranjuje v tabelo prijave v bazo,
proţi pa se ob prijavi vsakega uporabnika v bazo.
Proţilec se torej proţi nad bazo in ob dogodku LOGON. Če se znotraj njega zgodi kakšna
napaka, se ne izvedeta niti proţitev niti prijava v bazo. Ravno to se je zgodilo, ko smo
hoteli vpisati v tabelo, ki ni bila znotraj sheme MASTER, vse povezave do baze pa smo
imeli zaprte.
38
Tako se ni bilo več mogoče prijaviti v bazo, da bi lahko popravili ali izklopili proţilec. Ob
poskusu je streţnik javil napako: »Error: 17892 Logon failed for login due to trigger
execution. Changed database context to ‘master’«.
Našli smo način, kako se povezati na streţnik, brez da se izvede LOGON proţilec. Najprej
smo morali ustaviti streţnik in ga pognati v načinu z minimalno konfiguracijo [24]. V SQL
Server Configuration smo dodali –f pod zagonske parametre. Takšne nastavitve so
omogočile povezavo samo enega uporabnika na streţnik, vse začetne procedure pa se
niso izvedle. Nato smo zamenjali nepravilen LOGON proţilec.
1. CREATE TRIGGER LogonAuditTrigger 2. ON DATABASE 3. FOR LOGON 4. AS 5. BEGIN 6. DECLARE @LogonTriggerData xml, 7. @EventTime datetime, 8. @LoginName varchar(50), 9. @HostName varchar(50), 10. @AppName varchar(500) 11. 12. SET @LogonTriggerData = eventdata() 13. 14. SET @EventTime = @LogonTriggerData.value('(/EVENT_INSTANCE/PostTime)[1]', 'dateti
me') 15. SET @LoginName = @LogonTriggerData.value('(/EVENT_INSTANCE/LoginName)[1]', 'varch
ar(50)') 16. SET @HostName = HOST_NAME() 17. SET @AppName = APP_NAME() 18. 19. INSERT INTO [dbo].[logon_log] 20. ( 21. cas_prijave, 22. ime_gostitelja, 23. ime_programa, 24. uporabnisko_ime 25. ) 26. SELECT 27. @EventTime, 28. @HostName, 29. @AppName, 30. @LoginName; 31. 32. END
[25]
Pomembno je, da tabelo, ustvarjeno za namen vodenja prijav v bazo, in proţilec
napišemo v MASTER shemo, ki je sistemska shema, v katero bo lahko proţilec vedno
vstavljal podatke.
39
4 SKLEP
Namen diplomske naloge je bil preučiti in implementirati proţilce ter tako preseliti del
logike na nivo podatkovne baze. Ob zaključku lahko rečemo, da smo uspešno dosegli
zastavljene cilje, v kolikor je to bilo mogoče v posamezni podatkovni bazi.
MySQL se je izkazala kot najbolj preprosta podatkovna baza, ki omogoča preproste
proţilce, ki se proţijo nad tabelami podatkov oziroma nad vrsticami. Pri implementaciji
proţilcev nismo imeli posebnih teţav, dokler nismo ţeleli napisati proţilca, ki bi
onemogočil izbris tabele. MySQL namreč ne omogoča proţilcev, ki se proţijo ob DDL
dogodkih oziroma nad celotno podatkovno bazo. S shranjeno proceduro je sicer mogoče
napisati program, ki shranjuje vpise v bazo, vendar je bil naš cilj rešiti to teţavo s
proţilcem. V MySQL tudi ne obstaja način, ki bi neposredno ustavil izvajanje proţilca, kar
bi nam koristilo recimo pri nedovoljenem izbrisu vrstice iz tabele. V ta namen smo klicali
funkcijo, ki ne obstaja, katere nje pa je proţilec naletel na napako in se transakcija, torej
izbris, ni izvedla..
Oracle je za razliko od MySQL bolj kompleksna in napredna baza. To smo ugotovili ţe pri
precej bolj zapleteni arhitekturi in pri ustvarjanju prvega uporabnika, s katerim smo kreirali
bazo ter proţilce. Razlike v sintaksi v primerjavi z MySQL-om so majhne. Oracle zahteva,
da vse spremenljivke definiramo pred začetkom glavnega dela proţilca. Omogoča
proţilce, ki se izvedejo nad celotno shemo oziroma podatkovno bazo. Poleg tega je tudi
baza bolj robustna in varna. To smo ugotovili, ko smo naleteli na napako mutirane tabele.
Oracle ne dovoli, da bi brali oziroma izvajali druge SQL poizvedbe znotraj proţilca tabele,
ki ga je proţila, saj lahko takšen način privede do napačnih poizvedb. To teţavo smo rešili
s preoblikovanjem podatkovne baze.
Sintaksa proţilcev SQL Server-ja se precej razlikuje od zgornjih dveh. Do stolpcev, ki so
trenutno bili spremenjeni, dostopamo s poizvedovalnim stavkom SELECT, poizvedbo pa
delamo iz tabele INSERTED in DELETED, pri kateri nimamo :new ali :old vrednosti za
izbrane atribute. Tudi SQL Server omogoča številne proţilce nad podatkovno bazo, zato
smo lahko zadostili tudi tem zahtevam. Največ teţav smo imeli ob napaki, ki je opisana v
razdelku 3.5.3, ko smo izdelali proţilec, ki nas je zaklenil iz podatkovne baze.
MySQL baza je primerna za manjše aplikacije, ki ne zahtevajo dodatnih varnostnih
ukrepov in proţilcev nad celotno shemo, v nasprotnem primeru je pametno poseči po
Microsoftovem ali Oraclovem izdelku.
Kot nadaljevanje naloge bi lahko raziskali hitrost izvajanja proţilcev z enakovrednimi
nalogami nad isto količino podatkov v vseh treh bazah. Kot merilnik časa bi lahko sluţil
tudi vnos trenutnega časa v neko tabelo ob začetku in ob koncu proţilca, saj bi drugače
40
teţko dobili verodostojen rezultat, ki bi nam prikazal le čas izvajanja proţilca, brez časa
trajanja ostalih dogodkov, ki so proţile ta proţilec.
41
VIRI IN LITERATURA
[1] A Timeline of Database History. Dostopno na:
http://quickbase.intuit.com/articles/timeline-of-database-history [16. 8. 2014].
[2] Stephen Fortune. (2014, februar) A Brief History of Databases. Dostopno na:
http://vvvnt.com/media/history-of-databases [16. 8. 2014].
[3] Tea Lončarić, Andreja Vehovec, and Marko Kastelic. Obdobja. Dostopno na:
http://www.s-
sers.mb.edus.si/gradiva/rac/moduli/podatkovne_baze/02_obdobja/01_datoteka.html
[16. 8. 2014].
[4] Muhammad Haadi. (2010, Oct.) The Evolution of Database. Dostopno na:
http://mhaadi.wordpress.com/2010/10/18/the-evolution-of-database/
[16. 8. 2014].
[5] Tea Lončarić, Andreja Vehovec, and Marko Kastelic. Obdobja - post-relacijski
podatkovni sistemi. Dostopno na: http://www.s-
sers.mb.edus.si/gradiva/rac/moduli/podatkovne_baze/02_obdobja/03_datoteka.html
[16. 8. 2014].
[6] Database definition. Dostopno na: http://www.merriam-
webster.com/dictionary/database [16. 8. 2014].
[7] Tea Lončarić, Andreja Vehovec, and Marko Kastelic. Prednosti in slabosti uporabe
PB. Dostopno na: http://www.s-
sers.mb.edus.si/gradiva/rac/moduli/podatkovne_baze/02_obdobja/04_datoteka.html
[16. 8. 2014].
[8] Mike Chapple. What is SQL? Dostopno na:
http://databases.about.com/od/sql/a/What-Is-Sql.htm [16. 8. 2014].
[9] Wikipedia-SQL. Dostopno na: http://en.wikipedia.org/wiki/SQL [16. 8. 2014].
[10] Tore Risch. Active Database Systems. Dostopno na:
http://user.it.uu.se/~torer/kurser/dbt/adb.pdf [16. 8. 2014].
[11] MySQL. MySQL 5.0 Reference Manual. Dostopno na:
http://dev.mysql.com/doc/refman/5.0/en/create-trigger.html [16. 8. 2014].
[12] Oracle. CREATE TRIGGER. Dostopno na:
http://docs.oracle.com/cd/B19306_01/server.102/b14200/statements_7004.htm
[16. 8. 2014].
42
[13] Oracle Table Triggers. Dostopno na: http://psoug.org/reference/table_trigger.html
[16. 8. 2014].
[14] Oracle. 9 Coding Triggers. Dostopno na:
http://docs.oracle.com/cd/B19306_01/appdev.102/b14251/adfns_triggers.htm
[16. 8. 2014].
[15] Microsoft. CREATE TRIGGER (Transact-SQL). Dostopno na:
http://msdn.microsoft.com/en-us/library/ms189799.aspx [16. 8. 2014].
[16] Oracle. 22 Triggers. Dostopno na:
http://docs.oracle.com/cd/B19306_01/server.102/b14220/triggers.htm
[16. 8. 2014].
[17] Microsoft. DDL Triggers. Dostopno na: http://msdn.microsoft.com/en-
us/library/ms175941.aspx [16. 8. 2014].
[18] Oracle Software Delivery Cloud. MySQL Download. Dostopno na:
https://edelivery.oracle.com/EPD/GetUserInfo/get_form?caller=WelcomePage
[16. 8. 2014].
[19] Oracle. Oracle Database Software Downloads. Dostopno na:
http://www.oracle.com/technetwork/database/enterprise-
edition/downloads/index.html?ssSourceSiteId=ocomen [16. 8. 2014].
[20] Oracle. CREATE USER. Dostopno na:
http://docs.oracle.com/database/121/SQLRF/statements_8003.htm [16. 8. 2014].
[21] DbSchema. Dostopno na: http://www.dbschema.com/ [16. 8. 2014].
[22] Mutating Table Exceptions. Dostopno na: http://www.oracle-
base.com/articles/9i/mutating-table-exceptions.php [16. 8. 2014].
[23] Avoiding Mutating Tables. Dostopno na:
https://asktom.oracle.com/pls/asktom/ASKTOM.download_file?p_file=65511981190
97816936 [16. 8. 2014].
[24] Microsoft. Starting SQL Server with Minimal Configuration. Dostopno na:
http://msdn.microsoft.com/en-us/library/ms186400(SQL.90).aspx [16. 8. 2014].
[25] Paresh Prajapati. Logon trigger in SQL Server. Dostopno na:
http://beyondrelational.com/modules/2/blogs/88/Posts/18008/logon-trigger-in-sql-
server.aspx [16. 8. 2014].
[26] Burleson Consulting. Fix Oracle mutating trigger table errors. Dostopno na:
http://www.dba-oracle.com/t_avoiding_mutating_table_error.htm
43
[27] Wikpiedija. Avtentikacija (računalništvo). Dostopno na:
http://sl.wikipedia.org/wiki/Avtentikacija_(ra%C4%8Dunalni%C5%A1tvo)
[16. 8. 2014].