1 Universiteit Gent Faculteit Toegepaste Wetenschappen Vakgroep Electronica en Informatiesystemen Voorzitter : Prof. J. VAN CAMPENHOUT Ontwerp en impl...
Vakgroep Electronica en Informatiesystemen Voorzitter : Prof. J. VAN CAMPENHOUT
Ontwerp en implementatie van een epilepsiepatiëntendatabase door Katrien PENNEMAN
Promotors : Prof. R. VAN DE WALLE, Prof. I. LEMAHIEU Scriptiebegeleiders : M. D’HAVE, A. KHERA
Scriptie ingediend tot het behalen van de academische graad van licentiaat informatica optie informatie- en communicatietechnologie
Academiejaar 2001-2002
voorwoord
Voorwoord
In de eerste plaats wil ik Jan Verstuyft, mijn collega bij het ontwerpen en implementeren van de epilepsiepatiëntendatabank, bedanken.
Mijn dank gaat ook uit naar Peter Van Hese die ons een eerste rondleiding op de dienst Neurologie heeft gegeven. Ook wil ik mijn promotors prof. I. Lemahieu en prof. R. Van de Walle bedanken omdat ze ons het vertrouwen hebben gegeven om deze thesis te voltooien. Uiteraard wil ik ook Arvind Khera bedanken die de begeleiding van deze thesis voor zich heeft genomen alsook Michel D’Havé en prof. P. Boon voor de nodige informatie in verband met de dienst Neurologie.
Tot slot wil ik ook nog mijn ouders Alex en Erna, mijn zus Greet en mijn verloofde Tony vermelden en bedanken voor hun steun, vriendschap en genegenheid.
De auteur geeft de toelating deze SCRIPTIE voor consultatie beschikbaar te stellen en delen van de SCRIPTIE te kopiëren voor persoonlijk gebruik. Elk ander gebruik valt onder de beperkingen van het auteursrecht, in het bijzonder met betrekking tot de verplichting de bron uitdrukkelijk te vermelden bij het aanhalen van de resultaten uit deze SCRIPTIE. Katrien Penneman, 15 mei 2002.
i
overzicht
Ontwerp en implementatie van een epilepsiepatiëntendatabase door Katrien PENNEMAN
Scriptie ingediend tot het behalen van de academische graad van licentiaat informatica optie informatie- en communicatietechnologie
Academiejaar 2001-2002
Promotors : Prof. R. VAN DE WALLE, Prof. I. LEMAHIEU Scriptiebegeleiders : M. D’HAVE, A. KHERA Faculteit Toegepaste Wetenschappen Universiteit Gent
Vakgroep Elektronica en Informatiesystemen Voorzitter : Prof. J. VAN CAMPENHOUT
Samenvatting
Oracle mag beschouwd worden als één van de beste en krachtigste softwarepakketten voor databanken. Om de toegang tot de databank eenvoudig te houden opteren we voor het aanmaken van een webinterface. In hoofdstuk 1 worden enkele inleidende beschouwingen gegeven over de dienst Neurologie. Ook de bestaande databank en de werkomgeving worden in dit eerste hoofdstuk besproken. Vervolgens wordt in hoofdstuk 2 het softwarepakket Oracle besproken en worden met Oracle gerelateerde softwareproducten aangehaald die we gebruikt hebben tijdens de implementatie van de databank. Het ontwerp van de nieuwe databank wordt geschetst in hoofdstuk 3. Dit hoofdstuk vermeldt ook de veranderingen en uitbreidingen aan de bestaande databank. De implementatie van de nieuwe databank wordt uitvoerig besproken in hoofdstuk 4. hoofdstuk 5 geven we tot slot nog een kort besluit.
Bedenking bij het bewaren van resultaten in de databank........................................61
Databank in gebruik genomen ?....................................................................................61 v
inhoudstafel
4.
Gegevens van oude databank overzetten naar nieuwe databank...............................61
APPENDIX A: TABELDEFINITIES VAN DE OUDE DATABANK...........................64 APPENDIX B: TABELDEFINITIES VAN DE NIEUWE DATABANK.......................67 APPENDIX C: RECHTEN VOOR DE VERSCHILLENDE GROEPEN.....................72 REFERENTIES .........................................................................................................73
vi
lijst van figuren
Lijst van figuren Figuur 1.1 opvolging van een patiënt .........................................................................................2 Figuur 1.2 ontwerp bestaande databank .....................................................................................4 Figuur 1.3 login-venster..............................................................................................................6 Figuur 2.1 bufferoverflow...........................................................................................................7 Figuur 2.2 architectuur van Oracle9i ..........................................................................................8 Figuur 2.3 overzicht: server ontvangt aanvraag van cliënt .......................................................10 Figuur 2.4 SQL Navigator for Oracle.......................................................................................16 Figuur 3.1 gegevensmodel........................................................................................................19 Figuur 3.2 ontwerp van de databank.........................................................................................21 Figuur 4.1 bestand patienten.psp ..............................................................................................28 Figuur 4.2 screenshot procedure show_patienten.....................................................................28 Figuur 4.3 tabeldefinitie van de tabel TArtsen..........................................................................29 Figuur 4.4 view VArtsen ...........................................................................................................30 Figuur 4.5 view VNaamOnderzoekFull ....................................................................................30 Figuur 4.6 enkele constanten uit package global_k..................................................................32 Figuur 4.7 functie UZidentificatie uit package validate_input .................................................34 Figuur 4.8 procedure fillArts uit package tabrow .....................................................................37 Figuur 4.9 procedure formlistofValues uit package tabrow......................................................38 Figuur 4.10 procedure lovTable uit package tabrow ................................................................42 Figuur 4.11 screenshot van de berichtenpagina........................................................................48 Figuur 4.12 codefragment in verband met checksum...............................................................50 Figuur 4.13 het bestand epd-style.css .......................................................................................51 Figuur 4.14 voorbeeld van Javascript .......................................................................................52 Figuur 4.15 oproep van de functie vraagVerwijder(naam) ......................................................52 Figuur 4.16 codefragment met controle op gebruikersrol ........................................................54 Figuur 4.17 tabeldefinitie van de tabel resultaten ....................................................................55 Figuur 4.18 de relevante code uit de procedure uploadresultaat .............................................56 Figuur 4.19 de procedure showresultaat...................................................................................57 Figuur 4.20 screenshot zoekfunctie ..........................................................................................58 Figuur 5.1 het exportbestand klasse.txt.....................................................................................62 Figuur 5.2 het herwerkte exportbestand klasse.txt....................................................................62 Figuur 5.3 controlebestand klasse.ctl........................................................................................63
vii
lijst van afkortingen
Lijst van afkortingen AED
anti-epileptic drug
BLOB
binary large object
CSS
cascading stylesheet
EEG
electro-encefalogram
FK
foreign key
HTML
HyperText Markup Language
HTTP
HyperText Transfer Protocol
MRI
Magnetic Resonance Imaging
PET
Positron Emission Tomography
PK
primary key
PL/SQL
Procedural Language extensions to SQL
PSP
PL/SQL Server Pages
SQL
Structured Query Language
viii
Hoofdstuk 1 : Inleiding
Hoofdstuk 1 : Inleiding
1. Beschrijving van de thesis
Epilepsie is een hersenaandoening waarbij af en toe een overmatige synchrone elektrische hersenactiviteit optreedt.
Om te komen tot een doeltreffende behandeling voor een
epilepsiepatiënt worden tal van onderzoeken verricht, waaronder video-EEG-monitoring en medische beeldvorming, die resulteren in een grote hoeveelheid gegevens. Het ontwerp en de implementatie van een epilepsiepatiëntendatabank laat toe de resultaten van de verschillende onderzoeken op een efficiënte en eenvoudige manier te beheren.
De afdeling Neurologie van het Universitair Ziekenhuis te Gent vangt de patiënten op die een epileptische aandoening hebben. Voor een goede opvolging van hun patiënten worden er enkele gegevens van hun patiënten bijgehouden in een databank. Aangezien ze de bestaande databank willen vernieuwen en uitbreiden, hebben ze de opdracht gegeven een epilepsiepatiëntendatabank te ontwerpen en te implementeren met behulp van Oracle.
2. Opvolging van een patiënt
Een patiënt die voor het eerst op de dienst Neurologie komt, wordt toegewezen aan één van de artsen. Na deze eerste raadpleging beslist de arts of de patiënt enkele onderzoeken moet ondergaan of niet. Indien er geen onderzoeken nodig zijn, kan hij verder geholpen worden door het nemen van medicatie. Anders volgt er een reeks van zes onderzoeken. Uit de resultaten van deze onderzoeken kan de staf dan een beslissing nemen omtrent de verdere behandeling van de patiënt. Ofwel volgen er bijkomende onderzoeken ofwel gaat men reeds tot een behandeling over. Mogelijke keuzes zijn een operatie, een alternatieve behandeling of het nemen van medicatie. De opvolging van een patiënt staat geschetst in figuur 1.1. De bedoeling van onze thesis is alle gegevens vanaf de eerste raadpleging tot het slagen van de behandeling bij te houden in een databank.
1
Hoofdstuk 1 : Inleiding
patiënt
nee onderzoeken
medicatie AED (anti-epileptic drug)
ja
reeks van zes onderzoeken operatie
ja beslissing staf
behandeling alternatieve behandeling
nee
extra onderzoeken
Figuur 1.1 opvolging van een patiënt
3. Bestaande database 3.1. Ontwerp
Momenteel maakt men gebruik van een MS-Access databank die vijf tabellen (TPatientGegevens,
TBerichten,
TKlasseOnderzoeken,
TNaamOnderzoeken
en
TPlanningOnderzoeken) bevat. Het ontwerp van deze databank is afgebeeld in figuur 1.2. De tabeldefinities zijn opgenomen in Appendix A.
De tabel TPatientGegevens bevat in de eerste plaats de elementaire gegevens van de patiënt zoals naam, adres, telefoonnummer, … . In deze tabel worden ook nog de gegevens die verband houden met het UZ bijgehouden waaronder de UZ-identificatiecode van de patiënt en 2
Hoofdstuk 1 : Inleiding
het dossiernummer. Daarnaast bevat de tabel TPatientGegevens ook nog velden die niet thuis horen in deze tabel zoals kamernummer, opnamedag en medicatie.
De onderzoeken op de dienst Neurologie kunnen onderverdeeld worden in verschillende klassen. Deze klassen worden bijgehouden in de tabel TKlasseOnderzoeken.
De
mogelijke
onderzoeken
en
opdrachten
worden
bijgehouden
in
de
tabel
TNaamOnderzoeken. In deze tabel houdt men ook bij om welk soort onderzoek het gaat. Men kan de onderzoeken namelijk indelen in 2 categorieën, namelijk de onderzoeken en de opdrachten. Een onderzoek is een technisch onderzoek dat op de dienst Neurologie of op een andere dienst van het UZ kan uitgevoerd worden. Een opdracht daarentegen kan steeds op de dienst Neurologie zelf uitgevoerd worden.
Een voorbeeld van zo een opdracht is een
telefonisch contact met de patiënt maken om een volgende opnamedag vast te leggen.
Om onderzoeken te plannen voor een patiënt hebben we nog een tabel die de link legt tussen een patiënt en een onderzoek, namelijk TPlanningOnderzoeken.
Tot slot hebben we nog de tabel TBerichten. Deze wordt gebruikt om wijzigingen aan de gegevens in de databank bekend te maken aan de andere gebruikers. Voor elke wijziging die betrekking heeft op gegevens van een patiënt of op één van zijn onderzoeken zal er immers een automatisch bericht gegenereerd worden.
Alle dokters zijn in staat om gegevens te bekijken, te wijzigen, toe te voegen of te verwijderen. Het verplegend personeel heeft ook toegang tot de databank maar niet tot de gegevens die informatie bevatten over de resultaten van het onderzoek.
Het nadeel van de bestaande databank is dat ze gebruik maakt van MS-Access. MS-Access is eigenlijk voor slechts één gebruiker bedoeld. Op de dienst Neurologie omzeilt men dit probleem door de databank op een netwerkdrive te plaatsten. Hiervoor moet men wel op elke computer waarop men de databank wil bekijken MS-Access installeren.
Bovendien
ondersteunt MS-Access weinig databank faciliteiten zoals roles, packages, procedures, …
Momenteel worden de resultaten van de onderzoeken niet bijgehouden in een databank. Het resultaat van sommige onderzoeken kan bijgehouden worden in een eenvoudig tekstveld. Voor andere onderzoeken is het echter nodig om een video-opname, een EEG, een PET-scan 4
Hoofdstuk 1 : Inleiding
of een MRI bij te houden. Het gebeurt regelmatig dat men het resultaat van een onderzoek van een bepaalde patiënt niet meer terugvindt. Een video-opname van een EEG-onderzoek moet in principe steeds beschikbaar zijn aangezien het nuttig kan zijn deze later nog eens te herbekijken nadat er ook resultaten van andere testen bekend zijn. Het bijhouden van de resultaten van de onderzoeken in de databank zou dus een enorme verbetering zijn omdat deze resultaten dan snel opgevraagd kunnen worden. Bovendien wordt de kans om resultaten te verliezen sterk gereduceerd op voorwaarde dat men regelmatig een backup neemt van de gegevens in de databank.
3.3. Opmerking databank Klaas Van Imschoot
In het academiejaar 1999-2000 werd de bestaande databank reeds toegankelijk gemaakt voor meerdere gebruikers.
Dit werd gerealiseerd door Klaas Van Imschoot in zijn scriptie
“Ontwerp van een databank voor de planning en opvolging van medische onderzoeken”. Hij opteerde voor MySQL als databank, Apache als webserver en Netscape als browser. Hij liet zijn HTML-pagina’s dynamisch genereren door gebruik te maken van Java Servlets.
De uitbreidingen die hij in zijn scriptie vermeldt zijn onder meer het kalendersysteem, de evaluatie van de patiënten en een kleine uitbreiding over het opnemen van onderzoeksresultaten in de databank. Aangezien we gestart zijn op basis van de huidige databank en niet op basis van de databank die door Klaas Van Imschoot ontworpen en geïmplementeerd werd, zullen we deze uitbreidingen ook vermelden onder de categorie uitbreidingen in deze scriptie.
Naast de scriptie van Klaas Van Imschoot hebben we niks concreet gezien in verband met zijn implementatie. We konden ons dus noch op zijn code noch op zijn webinterface baseren. Zijn werk is bovendien nooit in gebruik genomen omdat het nooit geïnstalleerd geweest is op de dienst Neurologie.
Waar Klaas Van Imschoot vrij werd gelaten in zijn keuze van
databank, werd ons expliciet opgedragen te werken met Oracle.
5
Hoofdstuk 1 : Inleiding
4. Bestaande werkomgeving
Men beschikt over een Solaris machine die als server werkt en een netwerk van Windows NT machines die elk als cliënt fungeren. Omdat de gegevens uit de databank bereikbaar moeten zijn op alle machines van de dienst Neurologie zullen we de databank toegankelijk maken via een webbrowser.
5. Beveiliging
Daar de dienst Neurologie gebruik maakt van een intern netwerk waarop alle pc’s binnen deze dienst aangesloten zijn, wordt het gemakkelijker om de databank te beveiligen.
Elke
gebruiker zal zijn eigen paswoord hebben waarmee hij toegang krijgt tot de databank. Het systeem van gebruikersnaam en paswoord wordt volledig door Oracle ondersteund. Figuur 1.3 toont het login-venster dat verschijnt wanneer men één van de procedures oproept. Ook voor het uitloggen kunnen we gebruik maken van de standaardprocedure logmeoff.
Figuur 1.3 login-venster
Een andere vorm van beveiliging ontstaat door het toekennen van een rol aan elke gebruiker. Zo ontstaan er verschillende groepen van gebruikers. Per groep van gebruikers worden er privileges toegekend. Deze privileges voorkomen dat een gebruiker van een bepaalde groep iets kan uitvoeren dat leden van zijn groep helemaal niet hoeven uit te voeren of zelfs niet mogen uitvoeren. Om dit te realiseren maken we gebruik van SQL views en roles.
6
Hoofdstuk 2 : Oracle
Hoofdstuk 2 : Oracle We zullen bij elke paragraaf van dit hoofdstuk een onderscheid maken tussen de installatie op de dienst Neurologie en de installatie op onze eigen computers. Tijdens het jaar hebben we de implementatie van de databank immers op onze eigen computers gemaakt. Vlak na de paasvakantie hebben we onze implementatie overgebracht naar de dienst Neurologie.
1. Versie 1.1. Installatie op onze computers
We maken gebruik van Oracle versie 9.0.1. Aangezien dit de nieuwste versie van Oracle is, hopen we dat ze op de dienst Neurologie een aantal jaren gebruik zullen kunnen maken van die versie. Een nieuwe versie heeft echter ook nadelen. Zo heeft Oracle 9.0.1 zoals elk nieuw product enkele kinderziekten. Voor de meeste van deze kinderziekten worden er patches of oplossingen beschikbaar gesteld via hun website. Al vrij snel ontdekten we een probleem in verband met bufferoverflow.
Wanneer we gegevens uit de databank toonden via onze
webinterface, verscheen er meestal wel ergens op de pagina een hele reeks tekens uit de buffer.
Figuur 2.1 is een voorbeeld van deel van een webpagina waarop duidelijk het
probleem van de bufferoverflow zichtbaar is. Al vlug bleek het probleem niet rechtstreeks bij Oracle 9.0.1 te liggen. De bufferoverflow was een gevolg van het gebruik van de HTTP Apache Server versie 1.3 die niet voldoende was afgestemd op deze nieuwe versie van Oracle.
Figuur 2.1 bufferoverflow
7
Hoofdstuk 2 : Oracle
1.2. Installatie op de dienst Neurologie
Daar onze begeleider versie 8.1.7 voor Solaris reeds voor handen had en we toch geen gebruik hadden gemaakt van nieuwe eigenschappen uit versie 9.0.1 besloten we op de server van de dienst Neurologie Oracle versie 8.1.7 te installeren. Aangezien de HTTP Apache Server mee geïnstalleerd wordt met Oracle verkiezen we de Apache Server boven de Oracle Application Server. Bovendien moet men voor het gebruik van de Oracle Application Server extra betalen. De samenwerking met de Apache Server versie 1.3 levert hier geen problemen op in verband met bufferoverflow.
2. Architectuur Oracle9i 2.1. Installatie op onze computers
Figuur 2.2 stelt een 3-lagen architectuur voor. Client machines in de eerste laag verbinden zich met behulp van het HTTP protocol met een Oracle9i Application Server in de tweede laag. De Oracle9i Application Server verbindt zich met een Oracle9i databank in de derde laag. In ons geval worden deze drie lagen op dezelfde computer ondergebracht. Bovendien vervangen we bij onze installatie de Oracle9i Application Server uit figuur 2.2 door de Apache HTTP Server 1.3 .
Figuur 2.2 architectuur van Oracle9i
8
Hoofdstuk 2 : Oracle
2.2. Installatie op de dienst Neurologie
We kunnen terug refereren naar figuur 2.2 alleen moeten we in acht nemen dat we hier versie 8.1.7 hebben geïnstalleerd in plaats van versie 9.0.1 . Op de dienst Neurologie maken we ook gebruik van de HTTP Apache Server 1.3 in plaats van de Oracle Application Server. Deze server zal op de computer draaien waar de databank is ondergebracht. In dit geval zijn de cliënts de verschillende computers die aangesloten zijn op het netwerk van de dienst Neurologie.
3. Gebruikte Tools
Voor de webinterface maken we gebruik van Apache HTTP Server met extra modules van Oracle.
Daar we voor onze implementatie gebruik maken van PL/SQL zullen we ook een korte beschrijving geven van deze programmeertaal.
We hebben twee versies geïmplementeerd. De eerste versie maakt gebruik van psp-pagina’s. De tweede versie maakt gebruik van stored procedures in de databank.
We zullen in
hoofdstuk 5 dieper ingaan op de verschillen tussen beide versies.
3.1. Apache HTTP Server
We maken gebruik van Apache 1.3 als webserver. Wanneer je de procedures wil oproepen via een webbrowser moet je eerst nog de webserver configureren. Je moet eerst een naam geven aan de indicator die je toegang zal geven tot de databank. Wanneer je bijvoorbeeld aan deze indicator de naam epd (EpilepsiePatientenDatabank) geeft, kan je de procedures oproepen via http://localhost/pls/epd/. Het pad pls/epd/ wordt dus in feite gezien als een virtueel pad waardoor de module plsql wordt opgeroepen.
Bij de configuratie moet je bovendien ook een Oracle gebruikersnaam en het bijhorend paswoord opgeven zodat er ook effectief een verbinding kan gemaakt worden met de Oracle 9
Hoofdstuk 2 : Oracle
databank. Wanneer je de Oracle gebruikersnaam en het bijhorend paswoord leeg laat bij de configuratie wordt bij de eerste procedure oproep aan de gebruiker gevraagd zich te identificeren. Op de dienst Neurologie zullen wij uiteraard voor deze laatste werkwijze opteren. De gebruikers behoren immers tot verschillende groepen. Via hun identificatie loggen ze in onder hun gebruikersnaam en krijgen ze de privileges van de groep waar ze deel van uitmaken. Wanneer een gebruiker zijn browser sluit, wordt hij automatisch uitgelogd. Een
andere
manier
om
uit
te
loggen
is
het
aanroepen
van
de
URL
http://localhost/pls/epd/logmeoff. We zullen dan ook deze standaard voorziene procedure gebruiken om een gebruiker af te melden.
Figuur 2.3 geeft een overzicht van de verschillende gebeurtenissen die optreden wanneer een server een aanvraag van een cliënt ontvangt. We zullen de verschillende stappen in deze figuur hieronder bespreken.
Figuur 2.3 overzicht: server ontvangt aanvraag van cliënt
10
Hoofdstuk 2 : Oracle
1. De Oracle HTTP Server ontvangt een URL aanvraag van een cliënt via een browser. Deze URL wijst naar een PL/SQL Server Page.
2. De Oracle HTTP Server zendt de aanvraag door naar de PL/SQL Gateway.
3. De aanvraag wordt door de PL/SQL Gateway doorgestuurd naar de Oracle9i Database. De PL/SQL Gateway maakt gebruik van informatie uit de configuratie om een verbinding met de databank te maken. Meer bepaald van de informatie die je ingevuld hebt bij het aanmaken van je indicator.
4. De PL/SQL Gateway stelt de parameters in en roept de PL/SQL procedure aan in de applicatie.
5. De PL/SQL procedure genereert een HTML pagina door gebruik te maken van de gegevens en de PL/SQL Web Toolkit die bereikt worden vanuit de databank.
6. Het resultaat wordt teruggegeven aan de PL/SQL Gateway.
7. De Oracle HTTP Server zendt het resultaat naar de browser van de cliënt.
3.2. Programmeertaal PL/SQL 3.2.1 Beschrijving
PL/SQL is de procedurale taalextensie van SQL gemaakt door Oracle. PL/SQL combineert de eenvoud en flexibiteit van SQL met de procedurale functionaliteit van een gestructureerde programmeertaal.
Met PL/SQL kan men SQL instructies gebruiken om gegevens te manipuleren en instructies uitvoeren om de gegevens te verwerken. Tevens kan men controle structuren gebruiken. Men kan constanten en variabelen declareren, procedures en functies maken en fouten opvangen.
11
Hoofdstuk 2 : Oracle
3.2.2 SQL
SQL of Structured Query Language wordt gebruikt om gegevens uit een databank te lezen, te verwerken, te wissen, … . Dit is een gestandaardiseerde taal.
Oracle maakt zeer veel gebruik van deze taal en heeft met PL/SQL de taal verrijkt. Wanneer een Oracle-applicatie gegevens uit de databank haalt, gebeurt dit met SQL. Dikwijls is dit transparant voor de gebruiker (m.a.w. de gebruiker merkt er niets van).
3.2.3 Blok structuur
PL/SQL is een blokgestructureerde taal. Er zijn dus standaard gedeeltes (procedures en functies), die ook nog een aantal subblokken kunnen bevatten. Normaal gezien komt een logisch blok overeen met een opgelost (sub)probleem. PL/SQL ondersteunt dus de ‘divideand-conquer’ methode (verdeel-en-heers methode) om een probleem op te lossen.
Een blok is een groep van declaraties en instructies die een logisch verband houden met elkaar. Declaraties in een blok zijn lokaal en houden op met bestaan wanneer het blok verlaten wordt.
PL/SQL heeft drie gedeeltes: een declaratie, een programmagedeelte en een gedeelte voor foutafhandeling (exceptie). (In PL/SQL wordt een fout een exceptie genoemd.) Alleen het programmagedeelte is vereist.
De volgorde van deze delen is logisch.
Eerst komt het declaratiegedeelte, waarin de
variabelen worden gedeclareerd. Daarna kunnen deze variabelen gemanipuleerd worden in het programmagedeelte. Fouten worden afgehandeld in het exceptiegedeelte.
12
Hoofdstuk 2 : Oracle
3.2.4 Variabelen en constanten
Met PL/SQL kan men variabelen en constanten declareren en deze dan gebruiken in SQLstatements, functies en procedures. De variabelen moeten wel altijd op voorhand worden gedeclareerd.
Variabelen kunnen elk SQL-datatype zoals CHAR (karakter), DATE (datum), NUMBER (nummer) of een PL/SQL datatype zoals BOOLEAN (kan maar twee waarden bevatten: TRUE of FALSE) of BINARY_INTEGER zijn. Men kan ook complexe datatypes gebruiken zoals een record of een tabel.
Een waarde kan op twee manieren aan een variabele toegekend worden. De eerste manier is door de toekenningsoperator te gebruiken die bestaat uit een dubbelpunt gevolgd door een gelijkheidsteken (:=). De tweede manier maakt gebruik van een SQL instructie die gegevens uit de databank haalt en deze aan de variabele toekent.
Een constante declareren gebeurt op ongeveer dezelfde wijze als een variabele declareren. Men moet het woord CONSTANT gebruiken en onmiddellijk een waarde toekennen aan de variabele.
3.2.5 Cursors
Oracle gebruikt werkgebieden om SQL-instructies uit te voeren en gegevens te bewaren. Een PL/SQL constructie, namelijk een cursor, geeft een naam aan een werkgebied en laat je toe om de gegevens erin op te halen.
Een cursor wijst naar een bepaalde rij in de resultaattabel (verkregen na gebruik van een SQL instructie). Om een cursor te gebruiken moet men deze eerst openen. Daarna kan men met PL/SQL instructies die cursor gebruiken. Met een lus kan men de volledige tabel doorlopen. Na gebruik moet men de cursor weer sluiten.
13
Hoofdstuk 2 : Oracle
3.2.6 Controlestructuren
Controlestructuren zijn de belangrijkste PL/SQL uitbreiding bij SQL. Niet alleen kan men met PL/SQL gegevens manipuleren, maar men kan ook de data verwerken met behulp van conditionele, iteratieve en sequentiële controle-instructies zoals de gekende IF-THEN-ELSE, FOR-LOOP, WHILE-LOOP, EXIT-WHEN en GOTO statements.
3.2.7 Architectuur
PL/SQL is een technologie en geen onafhankelijk product. Deze technologie kan beschouwd worden als een programma die PL/SQL blokken en subprogramma’s uitvoert.
Dit
programma kan geïnstalleerd worden in een Oracle Server of in een applicatie.
Het PL/SQL programma voert de niet-SQL-instructies zelf uit en stuurt de SQL-instructies naar de SQL verwerker. Deze bevindt zich op de Oracle 9.0.1 server. Men kan hier dus spreken van gedistribueerde verwerking waarbij de server en de applicaties nauw samenwerken. De server kan ook een PL/SQL programma bevatten dat daar uitgevoerd kan worden.
3.2.8 Procedures en functies
De programmeertaal PL/SQL ondersteunt ook het principe van functies en procedures. Deze kunnen gebruikt worden in verschillende applicaties. Een functie is in principe hetzelfde als een procedure maar met één wezenlijk verschil. Een functie geeft een waarde terug, een procedure doet dit niet.
Zowel functies als procedures kunnen parameters gebruiken waardoor een meer generieke code mogelijk is. Beiden kunnen dan in meerdere gevallen gebruikt worden.
14
Hoofdstuk 2 : Oracle
3.2.9 Packages
Een package is een PL/SQL constructie die ervoor zorgt dat types, objecten, procedures en functies die logisch met elkaar verband houden gegroepeerd zijn.
Packages hebben
gewoonlijk twee gedeelten: de specificatie en de code.
De specificatie is de interface naar de package toe. De specificatie declareert de variabelen, de constanten, de excepties, de cursors en de subprogramma’s (procedures en functies) die men kan gebruiken. De code zelf definieert volledig de cursors en de subprogramma’s. De code implementeert zo de volledige specificatie.
3.3. PSP-bestanden
PSP’s zijn databank procedures die uitgevoerd worden op de databank server om de dynamische inhoud te produceren voor Web toepassingen.
PSP’s maken gebruik van
mod_plsql om hun output te genereren. PL/SQL procedures en procedures in een package worden uitgevoerd om HTML te genereren.
Deze procedures kunnen SQL opdrachten
uitvoeren en zo gegevens ophalen van gelijk welke Oracle databank. PSP’s zijn eenvoudige bestanden die bestaan uit HTML code gemengd met PL/SQL code. PSP bestanden kunnen aangemaakt worden in een gewone HTML editor maar de code wordt opgeslagen als gecompileerde PL/SQL code. PSP’s gelijken zeer sterk op Java Server Pages qua lay-out en syntax. De meeste opdrachten zijn identiek.
3.4. SQL Navigator for Oracle
SQL Navigator biedt een geïntegreerde omgeving aan voor het ontwikkelen en testen van onder andere procedures, schema’s en objecten die bewaard worden in Oracle.
SQL
Navigator heeft bovendien een grafische gebruikersinterface die gemakkelijk te gebruiken is. Figuur 2.4 geeft een beeld van deze grafische gebruikersinterface.
Tevens kan men
eenvoudig select statements opbouwen en onmiddellijk uittesten. De gegevens in de databank kunnen ook rechtstreeks bekeken worden met behulp van SQL Navigator.
15
Hoofdstuk 2 : Oracle
Figuur 2.4 SQL Navigator for Oracle
16
Hoofdstuk 3 : Ontwerp
Hoofdstuk 3 : Ontwerp
1. Entiteit-relatiemodel
Het entiteit-relatiemodel is een gegevensmodel dat gebruikt wordt voor het vastleggen van specificaties van databanksystemen en hulpmiddelen bevat waarmee een totaaloverzicht kan worden gekregen van de gebruikersgegevensbehoefte. Het is daarom geschikt voor een topdown aanpak. Dit model omvat een taal waarin het gebruikersgegevensmodel kan worden gespecificeerd. Men kan er de structuur en de relaties van de gegevensentiteiten uit de gebruikersomgeving mee beschrijven.
Zoals bij het programmeren pseudocode en
stroomdiagrammen worden gebruikt voor het specificeren van programmafuncties, gebruikt men gegevensmodellen voor het specificeren van databankfuncties.
1.1. Entiteiten
Een entiteit is een grootheid uit de werkomgeving van een gebruiker. Het is iets dat betekenis heeft voor de gebruiker binnen de context van het te bouwen systeem. Voorbeelden van entiteiten zijn patiënt Penneman Katrien, onderzoek EEG-monitoring en
klasse EEG.
Entiteiten worden ondergebracht in entiteitklassen, collecties van entiteiten van hetzelfde type. Zo is patiënt bijvoorbeeld de naam van een entiteitklasse van patiënt-entiteiten.
Een entiteitklasse is de algemene omschrijving van iets, bijvoorbeeld patiënt. Een instantie uit een entiteitklasse is een verwijzing naar een bestaande entiteit uit die klasse, bijvoorbeeld patiënt Penneman Katrien. Meestal bevat een entiteitklasse vele instanties. In de klasse patiënt zitten bijvoorbeeld alle instanties van alle patiënten die in de databank zullen worden opgenomen.
17
Hoofdstuk 3 : Ontwerp
1.2. Attributen
Entiteiten hebben eigenschappen of attributen die bijzonderheden van de entiteit aangeven. Voorbeelden zijn naam, adres, UZidentificatie, dossiernummer. Een attribuut kan één of meerdere waarden aannemen en kan enkelvoudig of samengesteld zijn.
Entiteitinstanties worden geïdentificeerd met bepaalde grootheden. Deze identificatie wordt dus tot stand gebracht via één van de attributen. Om een bepaalde instantie te kunnen identificeren, moet dit attribuut per instantie een unieke waarde hebben.
1.3. Relaties
Er kan een verband bestaan tussen entiteiten. Dergelijke verbanden worden relaties genoemd. Ook bij relaties onderscheiden we relatieklassen en relatie-instanties. Relatieklassen zijn verbanden tussen entiteitklassen en relatie-instanties zijn verbanden tussen entiteitinstanties. Ook relaties kunnen eigenschappen of attributen hebben.
Er kunnen relaties bestaan tussen twee of meer entiteiten. Het aantal entiteiten in een relatie heet de graad van die relatie. Toepassingen van graad twee worden binaire relaties genoemd.
1.4. Drie types binaire relaties
In een 1:1 relatie is steeds één enkele instantie van de ene entiteit verbonden met één enkele instantie van een andere entiteit. Bij een 1:N relatie bevat één instantie van een entiteit meer instanties van een andere entiteit. Tenslotte is er nog de N:M relatie, hierbij kunnen meerdere instanties van de ene entiteit (entiteit 1) verbonden worden met een instantie van de andere entiteit (entiteit 2) en andersom (dit wil zeggen: meerdere instanties van entiteit 2 kunnen verbonden worden met een instantie van entiteit 1).
18
Hoofdstuk 3 : Ontwerp
1.5. Toepassing entiteit-relatiemodel op epilepsiepatiëntendatabank
Het gegevensmodel van de epilepsiepatiëntendatabank staat afgebeeld in figuur 3.1. De entiteiten zijn in een ellips geplaatst en de relaties worden weergegeven door de verbindingslijnen tussen de entiteiten.
eenheid
soort
1
1
N
N
medicatie
M
N
N
arts
1
N
bericht
1
patiënt 1
N 1
N
evaluatie
M
klasse
1
N
onderzoek N
resultaat
Figuur 3.1 gegevensmodel
1.5.1 Entiteiten
klasse
onderzoek
soort
eenheid
medicatie
arts
patiënt
bericht
evaluatie
resultaat
19
Hoofdstuk 3 : Ontwerp
1.5.2 Relaties
entiteit1
entiteit2
relatie tussen entiteit1 en entiteit2
soort
medicatie
1:N
eenheid
medicatie
1:N
patiënt
bericht
1:N
patiënt
evaluatie
1:N
arts
patiënt
1:N
klasse
onderzoek
1:N
patiënt
onderzoek
N:M
patiënt
medicatie
N:M
patiënt-onderzoek
resultaat
1:N
2. Ontwerp van de epilepsiepatiëntendatabank
Figuur 3.2 toont het ontwerp van de door ons gemaakte databank. De veranderingen en uitbreidingen ten opzichte van de bestaande databank zullen in dit hoofdstuk aangehaald worden.
Zoals je kan zien op figuur 3.2 bevat het ontwerp van de databank ook enkele losstaande tabellen. De tabel ListOfValues houdt een aantal vaste objecten bij die gebruikt worden bij het tonen van een keuzelijst. Wanneer we de kolom soort uit de tabel TNaamOnderzoeken willen tonen op het scherm, wordt er een keuzelijst aangemaakt met twee vaste waarden, namelijk onderzoek en opdracht.
Het object met tablename TNaamOnderzoeken,
columnname soort, optiondisplay opdracht, optionvalue 2 en seq 2 kan dan bijgehouden worden in de tabel ListOfValues. In de keuzelijst zal men dan als inhoud het woord opdracht terugvinden. Wanneer opdracht geselecteerd wordt, zal men de waarde 2 meegeven. Het woord opdracht zal bovendien op de tweede plaats in de keuzelijst verschijnen.
20
Hoofdstuk 3 : Ontwerp
TMEDICATIEPATIENT PK
NUMMER
FK2 FK1
PATIENT MEDICATIE DOSIS DELETED
PK
TMEDICATIE PK
MEDICATIEID NAAM AFKORTING SOORT EENHEID DELETED
FK2 FK1
FK1
PK
PK
ARTSID NAAM DELETED
NAAM ADRES GEMEENTE POSTCODE TELEFOON OPMTELEFOON TWEEDETELEFOON OPMTELEFOON2 VOLGNRMONITOR UZIDENTIFICATIE DOSSIERNUMMER VRAAGSTELLING VERWIJZENDEARTS ARTSEERSTECONTACT DATUMEERSTECONTACT OPMERKING STATUSPROTOCOL OPMERKINGSTATUS DELETED
De tabel Gebruikersnamen bevat de namen van de gebruikers. Alle namen van gebruikers worden ook bijgehouden in een interne tabel van Oracle, namelijk de tabel all_users. Wanneer men echter een andere databank, die gebruik maakt van Oracle, op de server zou installeren dan zouden de gebruikers van deze databank ook toegevoegd worden aan de tabel all_users. Het is dus handig om een extra tabel Gebruikersnamen bij te houden die alleen de gebruikers van de epilepsiepatientendatabank bevat.
De tabel Rechten wordt enkel door ons gebruikt om rechten toe te kennen aan de verschillende groepen van gebruikers. Een voorbeeld van een object uit de tabel Rechten is het object met role administrator, object VArtsen en privilege select, update, insert, delete. We kunnen dus voor elk object in de tabel Rechten een SQL-statement aanmaken van de vorm grant privilege on object to role;. In het geval van ons voorbeeld krijgen we dus grant select, update, insert, delete on VArtsen to administrator;.
3. Veranderingen
Een eerste verandering is de aanmaak van de tabel TArtsen. Deze tabel houdt de namen bij van de artsen die op de dienst Neurologie werken. Wanneer iemand dan bij de gegevens van een patiënt de naam van de arts van het eerste contact vastlegt, kan hij uit een keuzelijst de juiste naam selecteren. In de bestaande databank vonden we immers Dr. Paul Boon, Dr. P. Boon of gewoon BP terug terwijl dit allemaal verwijzingen waren naar dokter Paul Boon. Met de aanmaak van onze tabel TArtsen wordt dit dus verholpen en zal er een standaardnotatie zijn voor de naam van een arts.
Een tweede aanpassing is het toepassen van de techniek lazy deletion. Wanneer we gegevens verwijderen, moeten we ervoor zorgen dat ze nog steeds ergens beschikbaar zijn.
Een derde aanpassing is het verplaatsen van het veld kamernummer en het verwijderen van het veld opnamedag. Vroeger vond men de velden kamernummer en opnamedag terug in de tabel TPatientGegevens. We besloten het veld opnamedag te wissen daar de dag van een onderzoek al werd bijgehouden in de databank. Het veld kamernummer hebben we verplaatst naar de tabel TPlanningOnderzoeken.
22
Hoofdstuk 3 : Ontwerp
In de tabel TPatientGegevens hebben we twee velden waar telefoonnummers kunnen worden opgegeven. Toch is er maar één veld voorzien in verband met opmerkingen omtrent de telefoonnummers. Het is dus logisch dat we een extra veld aanmaken. Het oorspronkelijke veld kan dan gebruikt worden voor het eerste telefoonnummer.
Het extra veld dat we
aanmaken kan gebruikt worden om informatie over het tweede telefoonnummer bij te houden. We maken hier echter geen expliciet onderscheid tussen vaste telefoon, gsm of fax.
In de tabel TPlanningOnderzoeken hebben we een veld dat kan gebruikt worden om een opmerking neer te schrijven.
Dit veld wordt echter dubbel gebruikt.
Wanneer een
receptionist een telefonische afspraak maken met de patiënt omtrent een onderzoek, schrijft de receptionist in dit veld een opmerking naar de arts in verband met het telefoongesprek. Maar dit veld wordt echter ook gebruikt door de arts die informatie omtrent de planning van het onderzoek wil doorgeven aan de receptionist.
4. Uitbreidingen
Een eerste uitbreiding bestaat uit de aanmaak van de tabellen TSoortMedicatie, TEenheidMedicatie, TMedicatie en TPatientMedicatie. We houden de soort medicatie in een aparte tabel bij omdat er geen verschillende benamingen voor dezelfde soort zouden voorkomen. Zo zullen we ervoor zorgen dat een bepaald medicament steeds verbonden is met een bepaalde soort. Een medicament kan dus niet de ene keer voorkomen met soort pillen en de andere keer met soort tabletten. Het is duidelijk dat met pillen hetzelfde bedoeld wordt als tabletten en we willen dan ook maar één van deze twee woorden verbonden zien met hetzelfde medicament. Wel is het mogelijk dat een bepaald medicament voorkomt in de vorm van pillen en in de vorm van siroop. Het gaat dan in principe om twee verschillende medicamenten die dezelfde naam hebben.
De eenheid van een medicament wordt ook
bijgehouden in een aparte tabel. We zullen de standaardafkortingen gebruiken voor elke eenheid. Milligram zal dus steeds bijgehouden worden als mg. Met behulp van deze tabellen is het mogelijk de tabel TMedicatie aan te maken. Deze tabel houdt de namen van de medicatie bij samen met hun eenheid en soort. Om de relatie bij te houden tussen een patiënt en een medicament zullen we gebruik maken van de tabel TPatientMedicatie.
23
Hoofdstuk 3 : Ontwerp
Een tweede uitbreiding bestaat uit de aanmaak van de tabellen TPlanningResultaten en Resultaten. Hierdoor wordt het mogelijk om de resultaten van de onderzoeken bij te houden in de databank. In het vijfde hoofdstuk zullen we meer vertellen over deze uitbreiding en zullen we ook beide tabellen bespreken.
De verschillende rollen die we kunnen toekennen aan gebruikers vormen een derde uitbreiding. Zo hebben we rollen van studenten, receptionisten, dokters en administrators.
Thesis- en doctoraatstudenten van de dienst Neurologie vormen dus de groep van de studenten. Deze groep mag in principe alle gegevens bekijken maar mag absoluut niks wijzigen, toevoegen of verwijderen uit de databank. Ze hebben eigenlijk weinig privileges. De studenten kunnen met behulp van de databank gegevens bekijken die hun mogelijk een beter zicht geven op de werking binnen de dienst Neurologie. Het klinkt misschien raar dat studenten ook de resultaten van de onderzoeken mogen bekijken, maar deze resultaten zijn juist het studiegebied van de meeste studenten.
De receptionisten vormen een tweede groep met beperkte privileges. Ze mogen gegevens van patiënten alsook de planning van de onderzoeken bekijken en wijzigen. Het is wel belangrijk dat de receptionisten nooit de resultaten van de onderzoeken te zien krijgen. Door gebruik te maken van de databank kunnen de receptionisten reeds enkele gegevens van de patiënten invullen.
Daarnaast kunnen receptionisten met behulp van de databank ook beter de
onderzoeken plannen. Door middel van berichten in de databank kunnen dokters immers doorgeven aan de receptionisten dat er een afspraak gemaakt moet worden met een patiënt. En omgekeerd kunnen de receptionisten door middel van berichten aan de dokters laten weten dat er een datum voor een onderzoek vastgelegd is.
De dokters van de dienst Neurologie vormen een derde groep.
Deze hebben dezelfde
privileges als de receptionisten en kunnen bovendien de resultaten van de onderzoeken bekijken. Ze kunnen de resultaten van de onderzoeken echter niet wijzigen, toevoegen of verwijderen.
Een laatste groep wordt de groep van de administrators genoemd. Deze laatste groep heeft uiteraard geen beperkingen en zal bestaan uit de hoofdartsen. Ze hebben bovendien ook de mogelijkheid zeldzame aanpassingen te maken aan de databank zoals het toevoegen van een 24
Hoofdstuk 3 : Ontwerp
nieuw medicament of de naam van een nieuwe arts op de dienst Neurologie. Daarnaast kunnen ze ook verwijderde gegevens bekijken of zelfs terug toevoegen aan de databank. Een andere administratieve taak die enkel voor de administrators weggelegd is, is het toevoegen van nieuwe gebruikers.
Appendix C toont een tabel die het verband weergeeft tussen de rollen en de mogelijke bewerkingen op de tabellen van de databank.
25
Hoofdstuk 4 : Implementatie
Hoofdstuk 4 : Implementatie
1. Eerste versie
De eerste stap bestaat uit het aanmaken van de bestaande tabellen. Daar we al vrij zeker zijn over het uitbreiden van het medicatie gedeelte van de databank, maken we ook reeds de extra tabellen TSoortMedicatie, TEenheidMedicatie, TMedicatie en TMedicatiePatient aan die we nodig hebben voor deze aanpassing.
Onze eerste implementatie van de epilepsiepatiëntendatabank maakt gebruik van PSP. Deze implementatie is een eerste kennismaking met PL/SQL. Van alle tabellen die we tot hiertoe hebben aangemaakt kunnen we nu via onze webbrowser gegevens bekijken, wijzigen, verwijderen en toevoegen. Figuur 4.1 is een voorbeeld van een psp-bestand. Wanneer men het bestand patienten.psp inlaadt en compileert, wordt de procedure show_patienten aangemaakt. Deze procedure kan opgeroepen worden via een browser. Het resultaat hiervan kan u zien in figuur 4.2 .
Om een psp-bestand te laden in de databank moet je gebruik maken van het loadpsp programma (vanuit de prompt van het besturingssysteem). Elk psp-bestand correspondeert met een opgeslagen procedure. De pagina’s worden in één stap gecompileerd en geladen in de databank.
Als je psp-programma syntax fouten bevat in de PL/SQL code, dan faalt loadpsp en geeft loadpsp een lijnnummer, kolomnummer en een ora-foutmelding weer. Deze foutmelding heeft de vorm ora-xxxxx waarbij x staat voor een cijfer. Met behulp van de documentatie van Oracle kan je deze ora-foutmelding opzoeken en te weten komen wat de foutmelding juist inhoudt. Om databankfouten in je code te behandelen, kan je een exceptie blok toevoegen in je psp-bestanden.
Je kan een ‘when others’ clausule toevoegen die alle onbehandelde
uitzonderingen behandelt. 26
Hoofdstuk 4 : Implementatie
Aan de hand van figuur 4.1 zullen we het bestand patienten.psp bespreken. Bij het bekijken van de code valt reeds onmiddellijk op dat men vooral HTML code moet schrijven. Tussen de verschilllende HTML tags worden de PL/SQL statements geschreven. Deze statements moeten vooraf gegaan worden door de tag <% en afgesloten worden met de tag %>. We zullen nu elke regel apart bespreken uitgezonderd de regels die enkel HTML code bevatten.
regel 01 pagina definitie Deze wordt gebruikt om de scripttaal aan te duiden.
regel 02 procedure definitie Wanneer je een psp-bestand laadt, zal de naam van de procedure automatisch dezelfde zijn als de psp-bestandsnaam (zonder de extensie psp). Als je een andere naam wil geven aan de databank procedure, dan kan je gebruik maken van de procedure definitie.
regel 10 PL/SQL statement Zuiver PL/SQL statement dat een lus uitvoert voor elk element dat voldoet aan het SQLstatement.
regels 12, 14, 16, 19 en 22 variabele uitschrijven De inhoud tussen de scheidingstekens <%= en %>wordt verwerkt door de procedure prn in de package htp. Alle witte ruimte aan het begin of het einde wordt overgeslagen. Elke opeenvolging van letters (i.e. tekst) moet omsloten worden met enkele aanhalingstekens. Je kan ook een concatenatie gebruiken zoals je zou doen in PL/SQL (i.e. gebruik maken van volgende tekens || ). Er wordt geen puntkomma gebruikt aan het eind van de uitschrijving van de variabele.
regel 24 PL/SQL statement Een zuiver PL/SQL statement dat het einde van de lus weergeeft. Het begin van deze lus vindt men terug op regel 10.
Een nadeel van psp-bestanden is dat je alle parameters moet meegeven wanneer je de procedure oproept. Waardoor je al vlug vele kleine bestanden schrijft en bijgevolg veel procedures hebt. Bijvoorbeeld om medicatie te tonen, te wijzigen, te verwijderen en toe te voegen schrijf je dan best vier verschillende psp-bestanden die dan elk apart geladen worden en zo vier procedures als resultaat geven. De bestaande versie van de databank samen met de uitbreiding op gebied van medicatie neemt bij onze implementatie reeds 72 psp-bestanden in. Het wordt dus moeilijk om het overzicht te bewaren. Aangezien we te veel procedures hebben, zoeken we naar een methode om minder procedures te verkrijgen.
Bovendien
schrijven we de psp-bestanden in een gewone teksteditor, namelijk WordPad.
Het
ontwikkelen van de procedures verliep zeer traag op deze manier.
We beginnen een tweede implementatie waarbij we gebruik maken SQL Navigator 4.1 for Oracle.
2. Tweede versie
Met behulp van SQL Navigator for Oracle hebben we tabellen, views en sequences aangemaakt alsook de packages en procedures geïmplementeerd.
2.1. Tabellen
Bij het aanmaken van een tabel kan je alle kolomnamen opgeven samen met hun type, lengte, standaardwaarde en een aanduiding of het betreffende veld de null-waarde mag hebben of niet. Voor de tabel TArtsen hebben we deze tabeldefinitie opgenomen in figuur 4.3. De tabeldefinities van alle tabellen uit onze databanken kun je terugvinden in Appendix B.
kolomnaam type artsid
lengte
number
not null
default
uniek
not null
naam
varchar2 40
deleted
number
1
not null
PK PK
0
Figuur 4.3 tabeldefinitie van de tabel TArtsen
29
FK tabelnaam
Hoofdstuk 4 : Implementatie
2.2. Views
Een view is een gedeeltelijke voorstelling van gegevens uit één of meer tabellen (of andere views). Een view voert het bijhorende select-statement uit en behandelt deze uitvoer als een tabel. Je kan een view dus het beste zien als een virtuele tabel. Views worden gebruikt op de meeste plaatsen waar een tabel gebruikt kan worden. Zo is het handig om een view te creëren die enkel de gegevens bevat die nog niet verwijderd zijn. Analoog kunnen we bij het tonen van de verwijderde gegevens gebruik maken van een view die enkel de verwijderde gegevens uit een tabel bevat. Als voorbeeld tonen we in figuur 4.4 de view op de tabel TArtsen die de niet verwijderde gegevens zal bevatten.
create or replace view VArtsen (artsid, naam) as select “artsid”, “naam” from Tartsen where deleted=0
Figuur 4.4 view VArtsen
Views kunnen zoals eerder gezegd ook gebruikt worden om verschillende kolommen uit verschillende tabellen te combineren in één tabel. Een voorbeeld hiervan vindt u terug in de view VNaamOnderzoekFull, afgebeeld in figuur 4.5 .
create or replace view VNaamOnderzoekFull(nummer,soort,naam,korte_naam,klasse) as select n.nummer,n.soort,n.naam,n.korte_naam,k.naam from VNaamOnderzoeken n, VKlasseOnderzoeken k where n.klasse = k.nummer
Figuur 4.5 view VNaamOnderzoekFull
2.3. Sequences
We gebruiken sequences om automatisch unieke waarden te genereren voor de primaire sleutels van onze tabel. Deze sequences worden dus enkel gebruikt bij het toevoegen van een object aan een van onze tabellen.
Bij het aanmaken van zo’n sequence moet je een
minimumwaarde, een maximumwaarde, een startwaarde en een waarde die als increment dient opgeven. Voor de sequence SArtsen, een sequence op de tabel TArtsen, nemen we
30
Hoofdstuk 4 : Implementatie
minimumwaarde 1, maximumwaarde 1028-1, startwaarde 1 en waarde die als increment dient 1. Hoewel we voor de tabel TArtsen niet zoveel gegevens zullen hebben, nemen we voor maximumwaarde toch de maximum toegelaten waarde. Zo zijn we zeker dat we nooit een overflow van objecten kunnen hebben in deze tabel.
2.4. Packages
Een package is een logische groepering van functies en procedures. We zullen nu onze packages uitvoerig bespreken.
2.4.1 Package global_k
In de package global_k houden we de constanten van de applicatie bij zoals bijvoorbeeld de lengte van de kolommen uit onze tabellen. Eigenlijk zouden we deze kolomlengtes ook kunnen opvragen aan de hand van de tabeldefinitie, maar we hebben er hier voor gekozen om deze lengte ook nog eens als constante te definiëren in de package global_k. Zo kan de lengte sneller en eenvoudiger opgevraagd worden.
Daarnaast worden hier ook nog enkele constanten gedefinieerd die te maken hebben met layout. We zullen ze gebruiken in een volgende package die HTML code genereert.
Deze package bevat ook nog een aantal foutmeldingen die gebruikt worden in de applicatie. Zo’n foutmelding komt onder andere voor wanneer men gegevens van een patiënt toe wil voegen zonder een naam voor die patiënt op te geven.
In figuur 4.6 ziet u een voorbeeld van enkele constanten die gedefinieerd worden in deze package.
31
Hoofdstuk 4 : Implementatie
01 02 03 04 05 06 07 08 09
-- lengtes van velden naamlength number := 40 ; UZidentificatielength number := 13; --- fontsettings tabletitlecolor varchar2(10) := '#000080'; detailwidth varchar(3) := '100'; -- mogelijke foutmeldingen foutNaam varchar2(100) := 'Fout in het veld naam '; foutUZ varchar2(30) := 'Fout in het veld UZidentificatienummer ';
Figuur 4.6 enkele constanten uit package global_k
2.4.2 Package validate_input
Package validate_input controleert of de invoer die de gebruiker opgeeft correct is. Indien één van de velden onjuiste gegevens bevat of niet is ingevuld, wordt een gepaste foutmelding uitgeschreven. Deze package maakt gebruik van de reeds beschreven package global_k. Als voorbeeld zullen we hier de functie UZidentificatie bespreken, waarvan de code afgebeeld staat in figuur 4.7.
Op de volgende manier roepen we de functie aan:
validate_input.UZidentificatie(UZid);
error :=
waarbij error en UZid variabelen van het type
varchar2 zijn.
regel 01 functie definitie De functie UZidentificatie wordt steeds opgeroepen met één parameter. Deze parameter moet van het type varchar2 zijn. In het codefragment zal deze parameter gebruikt worden onder de naam UZidentificatie. Het resultaat dat door deze functie wordt weergegeven zal van het type varchar2 zijn.
regel 09 PL/SQL functies ltrim en rtrim Ltrim en rtrim zijn twee PL/SQL functies die respectievelijk alle spaties aan het begin en aan het eind van een string verwijderen.
regel 10 gebruik van constanten uit de package global_k Het UZidentificatienummer heeft een vaste lengte die we opvragen uit de package global_k. Zo kunnen we controleren of de invoer van de juiste lengte is.
32
Hoofdstuk 4 : Implementatie
regels 12, 20 en 26 gebruik van foutboodschappen uit de package global_k We kennen hier aan een variabele van het type varchar2 een foutboodschap toe. Deze foutboodschap wordt gedefinieerd in de package global_k en vermeld de naam van het veld waar de gebruiker een foutieve waarde ingevuld heeft. In dit geval zal de foutboodschap dus zeker het woord UZidentificatienummer bevatten. Als we in de package global_k kijken vinden we als foutmelding voor foutUZ het volgende terug:
‘Fout in het veld
UZidentificatienummer ’.
regel 15 PL/SQL functie substr Met behulp van de PL/SQL functie substr kan je een reeks opeenvolgende karakters uit een string halen. Deze opeenvolgende karakters vormen dan in zijn geheel een nieuwe string. Men gebruikt hier meestal de term substring voor. De substring wordt gedefinieerd door de string, de startpositie van de substring in de string en de lengte van de substring.
In
onderstaande code halen we dus een substring uit de string UZ, onze substring begint bij het eerste karakter van de string UZ en is zes karakters lang. We halen dus met andere woorden de zes eerste karakters uit de string UZ. We hebben deze eerste zes karakters nodig om te controleren of ze een geldige datum vormen. Het UZidentificatienummer begint immers met 6 cijfers die de geboortedatum van de patient voorstellen. Wanneer je bijvoorbeeld op 9 oktober 1979 geboren bent, zullen de cijfers 791009 de eerste zes karakters van je UZidentificatienummer zijn.
regel 16 PL/SQL functie to_date De PL/SQL functie to_date converteert een string naar het datatype date.
Als eerste
parameter wordt de string opgegeven die geconverteerd moet worden. Je kan als tweede parameter het formaat opgeven waarin de datum geschreven is. In dit geval heeft de datum het formaat ‘YYMMDD’ waarbij elke letter voor één cijfers staat. Zo kunnen we afleiden dat de eerste twee karakters van het UZidentificatienummer een jaartal voorstellen, de twee volgende karakters een maand voorstellen en de twee daarop volgende karakters een dag voorstellen. De functie to_date geeft een foutboodschap weer wanneer de karakters een ongeldige datum voorstellen.
Wanneer men bijvoorbeeld 791420 opgeeft als eerste zes
karakters van het UZidentificatienummer dan zal men een foutmelding krijgen aangezien er geen veertiende maand bestaat.
33
Hoofdstuk 4 : Implementatie
regel 18 PL/SQL functie instr Instr is een PL/SQL functie die een substring zoekt in een string en de positie van het eerste karakter van de substring in de string als resultaat geeft. Als de substring niet voorkomt in de string wordt 0 als resultaat gegeven. We controleren in de functie UZidentificatie dus of het zevende karakater in het opgegeven UZidentificatienummer een spatie is.
regel 23 exception Indien er in de functie UZidentificatie een fout optreedt die nog niet opgevangen is, wordt deze behandeld in het exceptieblok. Zo zal men hier bijvoorbeeld de fout opvangen die optreedt wanneer de zes eerste karakters van het UZidentificatienummer geen geldige datum vormen.
function UZidentificatie (UZidentificatie IN varchar2) return varchar2 is errmsg varchar2(100) default NULL; deel varchar2(6); getal number(2); UZ varchar2(15); datum date; begin UZ := ltrim(rtrim(UZidentificatie)) ; if (length(UZ) != global_k.UZidentificatielength) then errmsg := global_k.foutUZ; return errmsg; end if; deel := substr(UZ,1,6); datum := to_date(deel,'YYMMDD'); -- na de datum moet een spatie komen if (instr(UZ,' ') != 7) then errmsg := global_k.foutUZ; end if; return errmsg; exception when others then errmsg := global_k.foutUZ; return errmsg; end ;
Figuur 4.7 functie UZidentificatie uit package validate_input
De overige functies in de package validate_input controleren ook de invoer van de gebruiker. Aangezien ze analoog zijn aan de functie UZidentificatie zullen we ze hier niet bespreken. 34
Hoofdstuk 4 : Implementatie
2.4.3 Package tabrow
Aangezien alle procedures uit de package tabrow HTML-code genereren, zullen we hier slechts één procedure van bespreken.
We zullen echter wel de moeilijkste procedure
beschrijven, namelijk deze die een keuzelijst toont op het scherm waarbij de items in deze keuzelijst uit een tabel gehaald moeten worden.
De procedure lovTable die we zullen
beschrijven is afgebeeld in figuur 4.10 . Naast de procedure lovTable bevat de package tabrow ook nog de procedures plain, textarea en lov voor het uitschrijven van gegevens. De procedure plain schrijft eenvoudige gegevens uit zoals een nummer of een korte string, de procedure textarea schrijft een lange string uit die gespreid wordt over meerdere lijnen en de procedure schrijft een keuzelijst uit met vaste waarden. Het verschil tussen de procedure lov en lovTable bestaat er dus uit dat men in het geval van lovTable de keuzelijst moet opvullen met waarden die uit een databanktabel komen en in het geval van lov vaste waarden heeft die niet afhankelijk zijn van de inhoud van één of andere tabel. De package tabrow bevat ook nog de procedures fillArts, fillEenheidMedicatie, fillJaar, fillKamer, fillKlasse, fillMedicatie, fillNaamOnderzoek, fillSoortOnderzoek en formlistofValues die allen hulpprocedures zijn binnen deze package.
Deze hulpprocedures worden opgeroepen in verband met het
uitschrijven van de keuzelijsten en worden bijgevolg enkel opgeroepen in de procedures lov en lovTable.
Om de procedure lovTable beter te kunnen beschrijven, hebben we de
procedures fillArts en formlistofValues opgenomen als figuur 4.8 en figuur 4.9 . We zullen aan de hand van de code uit figuur 4.10 bespreken hoe de HTML code tot stand komt. Wanneer er in onze code een oproep is naar de procedures waarvan de code in figuur 4.8 of in figuur 4.9 staat, zullen we overspringen naar die code om vervolgens weer terug te keren naar onze hoofdprocedure uit figuur 4.10 .
figuur 4.10 regels 01 tot 11 proceduredefinitie De parameter celldata houdt de inhoud bij die in de betreffende cel van een tabel op het scherm moet uitgeschreven worden. Om aan te geven of de inhoud die uitgeschreven wordt in deze cel gewijzigd mag worden door de gebruiker wordt de parameter editable meegegeven.
Wanneer men een cel een naam wil geven moet men de waarde true geven aan de parameter title. Wanneer de parameter title op true staat, kan men de titel of naam die men aan een cel wil geven doorgeven met behulp van de parameter title_text_in. Deze naam zal dan juist voor 35
Hoofdstuk 4 : Implementatie
de cel op het scherm verschijnen. De parameter align bepaalt of de naam die toegekend is aan zo’n cel via de parameter title_text_in links uitgelijnd, rechts uitgelijnd of gecentreerd op het scherm verschijnt.
Wanneer men de parameter hidden op true zet, wordt de betreffende inhoud doorgegeven zonder dat de inhoud op het scherm verschijnt. De gebruiker zal dus niet op de hoogte zijn dat deze verborgen inhoud wordt doorgegeven aan een volgende procedure.
Meestal wordt met behulp van een formulier een volgende procedure opgeroepen.
De
parameter form_var_name zal de naam aanduiden van een variabele die de inhoud van de cel bijhoudt. De inhoud van een cel zal dan ook via zo een variabele doorgegeven worden aan de volgende procedure.
Deze procedure moet in zijn definitie een parameter bevatten met
dezelfde naam als de variabele die wordt doorgegeven.
Wanneer men een keuzelijst uitschrijft op het scherm, moet men ook nog bepalen welke gegevens in deze keuzelijst moeten staan. Dit wordt bepaald door de parameter kolom. Om de breedte van een datacel expliciet op te geven, kan je gebruik maken van de parameter detail.
Tot slot hebben we nog de parameter fluo die bepaalt of de gegevens uitgeschreven moeten worden op een gekleurde achtergrond. Deze gekleurde achtergrond wordt gebruikt om de gegevens te benadrukken die zopas door de gebruiker toegevoegd of gewijzigd zijn.
Al deze parameters worden gebruikt in de controle-statements van de procedure. Tussen deze controle-statements wordt met behulp van de package htp HTML code gegenereerd.
figuur 4.10 regel 19 htp.tablerowopen Deze procedure zorgt voor de aanmaak van de HTML tag
.
figuur 4.10 regel 27 htp.tabledata(‘ ’,cattributes=>attributen) Met behulp van htp.tabledata worden de HTML tags
en
geproduceerd. De eerste parameter ‘ ’ bepaalt dat er als inhoud van deze cel één enkele spatie moet komen. Het plaatsen van deze spatie is noodzakelijk omdat anders de randen van de datacel niet getoond worden. Het zichtbaar maken van de randen van lege datacellen heeft enkel met lay-out te 36
Hoofdstuk 4 : Implementatie
maken. De parameter cattributes=>attributen bepaald de attributen die in de eerste HTML tag bijgevoegd kunnen worden. Deze attributen worden aangemaakt op regel 22 en regel 25. Als we ervan uitgaan dat de parameters detail en fluo opgegeven zijn, dan wordt in regel 22 width=“100” toegekend aan de variabele attributen en wordt deze variabele in regel 25 uitgebreid tot width=“100” class=“fluo” .
Zo wordt op regel 27 de HTML code
width=“100” class=“fluo”> ‘ ’ gegenereerd.
figuur 4.10 regels 34 tot 37 htp.fontopen, htp.tabledata en htp.fontclose Als we er weer van uitgaan dat de parameter fluo op true staat, dan wordt op deze regels de HTML code
title_text_in
aangemaakt.
figuur 4.10 regels 44 en 45 tab_optDisp.DELETE en tab_optValue.DELETE Tab_optDisp en tab_optValue hebben we gedefinieerd als tabellen die elementen bevatten van het type varchar2 en maximum 80 karakters lang zijn. Tab_optDisp houdt de items bij die getoond kunnen worden in een keuzelijst. Tab_optValue houdt de bijhorende waarden bij. Wanneer we deze twee rijen nu willen opvullen, moeten we eerst de vorige waarden verwijderen. Dit verwijderen gebeurt dus op de regels 44 en 45.
figuur 4.10 regel 49 fillArts We gaan er in onze beschrijving vanuit dat we voor de parameter kolom de waarde arts hebben meegegeven. Dit wil dus zeggen dat we een keuzelijst met namen van artsen willen tonen. Onze procedure lov_table roept hiervoor de procedure fillArts op.
01 02 03 04 05 06 07 08 09 10 11 12
procedure fillArts is cursor arts_cur is select * from VArtsen; i number := 1; begin for arts in arts_cur loop tab_optValue(i) := arts.artsid; tab_optDisp(i) := arts.naam; i := i+1 ; end loop; end;
Figuur 4.8 procedure fillArts uit package tabrow
37
Hoofdstuk 4 : Implementatie
figuur 4.8 regels 03 en 04 cursor arts_cur We maken een cursor aan die elk object in de view VArtsen zal beschouwen.
figuur 4.8 regels 07 tot 11 tab_optValue(i) en tab_optDisp(i) Voor elk object dat door de cursor beschouwd wordt, zullen we een lus overlopen die de naam van de arts toekent aan tab_optDisp(i) en het bijhorend artsid toekent aan tab_optDisp(i). De teller i wordt bij elke stap met één verhoogd zodat elk object een volgend element in de rij voorstelt.
figuur 4.10 regel 69 formlistofValues De procedure formlistofValues wordt opgeroepen om de HTML code te genereren die de keuzelijst effectief zal weergeven op het scherm.
procedure formlistofValues (form_submit_in IN varchar2, selected_in IN varchar2, attrib IN varchar2) is none_checked boolean := TRUE; begin htp.print('
'); htp.formselectopen(form_submit_in); for i in tab_optValue.first..tab_optValue.last loop if selected_in=tab_optvalue(i) then none_checked := false; htp.formselectoption(tab_optDisp(i),'SELECTED', cattributes=>'value="'||tab_optValue(i)|| '"'); else htp.formselectoption(tab_optDisp(i), cattributes=>'value="'||tab_optValue(i)|| '"'); end if ; end loop ; if none_checked then htp.formselectoption(' ','SELECTED'); end if; htp.formselectclose; htp.print('
'); end ;
Figuur 4.9 procedure formlistofValues uit package tabrow
38
Hoofdstuk 4 : Implementatie
figuur 4.9 regel 07 htp.print Wanneer we gebruik zouden maken van htp.tabledata dan moeten we de inhoud en de extra attributen als parameters opgeven. Daar we echter voor de inhoud een keuzelijst willen uitschrijven, kunnen we geen gebruik maken van htp.tabledata. Daarom schrijven we met behulp van htp.print zelf de tag uit waar htp.tabledata steeds mee begint, daarna zullen we onze keuzelijst genereren en vervolgens zullen we terug met behulp van htp.print de tag aanmaken waarmee htp.tabledata normaal afsluit. De HTML tag die hier dus aangemaakt wordt is
.
figuur 4.9 regel 08 htp.formselectopen Hier maken we kenbaar dat we een keuzelijst wensen te gebruiken. De parameter die we meegeven is de naam van de variabele die de waarde van de keuze van de gebruiker moet bijhouden.
De HTML code <select name=“form_submit_in” > wordt op deze regel
aangemaakt.
figuur 4.9 regels 09 tot 21 aanmaken van keuzelijst Voor alle waarden die in de keuzelijst moeten voorkomen overlopen we een lus.
De
parameter selected_in van de procedure formlistofValues wordt gebruikt om één item uit de keuzelijst bovenaan de keuzelijst te zetten.
Dit item wordt dan beschouwd als het
geselecteerde item en wordt getoond als inhoud van die datacel. De andere items kan men maar zien wanneer men ook effectief op de keuzelijst klikt. Wanneer één van de items uit de keuzelijst overeenkomt met de parameter selected_in wordt bij het doorlopen van de lus voor dit item de code van regel 12 tot regel 15 uitgevoerd. Deze regels genereren als HTML code . Voor de andere items wordt de code van regel 17 tot regel 19 uitgevoerd bij het doorlopen van de lus. Deze regels genereren als HTML code . Wanneer er geen enkel item overeenkomt met de opgegeven parameter selected_in of wanneer er geen waarde is opgegeven voor de parameter selected_in wordt de code op regel 24 uitgevoerd. Deze regel zorgt voor de aanmaak van de HTML code . De keuzelijst geeft nu een leeg veld weer als eerste item in de lijst. Dit lege veld is dus zichtbaar op het scherm. Wanneer men de echte waarden uit de keuzelijst wil zien, moet men op de keuzelijst klikken.
39
Hoofdstuk 4 : Implementatie
figuur 4.9 regel 26 htp.formselectclose De HTML code wordt aangemaakt om aan te geven dat dit het einde is van de keuzelijst.
figuur 4.9 regel 27 htp.print Zoals reeds gezegd bij de beschrijving van regel 07, schrijven we de
tag uit met behulp van htp.print.
figuur 4.10 regels 77 en 78 htp.tabledata Deze
regels
maken
de
HTML
code
width=“300”
class=“fluo”>
class=“veld”>tab_optDisp(item)||‘ ’ aan. De tag div staat voor indeling van de inhoud. Deze tag wordt dus gebruikt om bepaalde attributen toe te passen op de inhoud. In dit geval worden de celgegevens ingedeeld bij de klasse veld. Daar de tag
aangeeft dat de celgegevens bij de klasse fluo behoren, zullen de celgegevens de attributen erven van beide klassen. De indeling in klassen gebruiken we om een vaste stijl te geven aan onze webinterface.
Alle stijlkenmerken van een bepaalde klasse zullen in één bestand
bewaard worden. Als we een bepaald lettertype willen wijzigen of een bepaalde kleur willen vervangen voor een reeks gelijkaardige gegevens dan hoeven we dit slechts op één plaats aan te passen, namelijk in de definitie van deze klasse. De concatenatie van de inhoud met een spatie (‘ ’) zorgt ervoor dat er steeds een veld wordt uitgeschreven. Wanneer de inhoud van de cel dus eigenlijk leeg zou moeten blijven, moeten we toch een spatie weergeven opdat men anders geen veld zou tonen op het scherm.
figuur 4.10 regel 82 htp.tablerowclose Hier wordt het einde van de tag
aangegeven, waardoor de rij van de tabel nu als volledig wordt beschouwd. De HTML code die dus wordt afgedrukt is
.
figuur 4.10 regel 85 htp.formhidden De HTML code om een verborgen parameter door te geven, wordt met behulp van deze regel aangemaakt.
procedure lovTable (celldata IN varchar2 default null, editable IN boolean default true, title IN boolean default false, hidden IN boolean default false, form_var_name IN varchar2 default null, title_text_in IN varchar2 default null, align IN varchar2 default 'right', kolom IN varchar2, detail IN boolean default false, fluo IN boolean default false) is attributen varchar2(100) ; disp varchar2(100) ; begin if not hidden then if title then htp.tablerowopen; if detail then attributen := 'width="'||global_k.detailwidth||'"' ; if fluo then attributen := attributen || ' class="fluo"' ; end if ; htp.tabledata(' ',cattributes=>attributen); end if; attributen := 'width="'||global_k.titlewidth||'"' ; if fluo then attributen := attributen || ' class="fluo"' ; end if ; htp.fontopen(global_k.tabletitlecolor,global_k.tabletitlefont, global_k.tabletitlesize); htp.tabledata(title_text_in,align,cattributes=>attributen); htp.fontclose; end if ; attributen := 'width="'||global_k.datawidth||'"' ; if fluo then attributen := attributen || ' class="fluo"' ; end if ; tab_optDisp.DELETE; tab_optValue.DELETE; -- opvullen van lijsten voor de values. if (upper(kolom) = 'ARTS') then fillArts; elsif (upper(kolom) = 'EENHEID') then fillEenheidMedicatie; elsif (upper(kolom) = 'SOORT') then fillSoortMedicatie;
elsif (upper(kolom) = 'MEDICATIE') then fillMedicatie; elsif (upper(kolom) = 'KLASSE') then fillKlasse ; elsif (upper(kolom) = 'ONDERZOEK') then fillNaamOnderzoek; elsif (upper(kolom) = 'OPDRACHT') then fillNaamOpdracht; elsif (upper(kolom) = 'KAMER') then fillKamer; elsif (upper(kolom) = 'JAAR') then fillJaar ; end if; if editable then formlistofValues(form_var_name,celldata,attributen); else for item in tab_optvalue.first..tab_optvalue.last loop if tab_optvalue(item) = celldata then disp := tab_optdisp(item) ; end if ; end loop ; htp.tabledata('
'|| disp||' '||'
', cattributes=>attributen) ; end if; if title then htp.tablerowclose; end if; elsif editable then htp.formhidden(form_var_name,celldata); end if; end;
Figuur 4.10 procedure lovTable uit package tabrow
2.4.4 Package datum
Package datum bevat een aantal functies en procedures die gebruikt worden bij het kalendersysteem. We zullen elke procedure en functie uit deze package kort bespreken.
De procedure vulWeekdagen is een procedure die de PL/SQL array weekdagen, een rij waarvan de elementen van het type varchar2 zijn, opvult met waarden. Weekdagen(0) krijgt de waarde maandag en zo vult men de dagen verder aan tot en met weekdagen(6). Deze laatste krijgt dan uiteraard de waarde zondag. 42
Hoofdstuk 4 : Implementatie
De procedure vulMaanden vult de PL/SQL array maanden, ook een rij waarvan de elementen van het type varchar2 zijn, op met de maanden uit een jaar. We beginnen maanden(0) op te vullen met de waarde januari en eindigen met de waarde december die toegekend wordt aan de variabele maanden(11).
De functie weekdag geeft een nummer tussen 0 en 6 terug. Waarbij 0 staat voor maandag en 6 voor zondag. Deze functie maakt gebruik van de standaard functie trunc. Stel nu dat we onze datum voorstellen door de variabele dag. Met behulp van trunc(dag,‘DAY’) kunnen we dan de datum bekomen die de eerste dag van die week geeft. Maandag wordt in dit geval gezien als de eerste dag van de week. We kunnen met behulp van de functie weekdag aangeven of een bepaalde datum effectief in een werkweek valt. Wanneer men immers een EEG-onderzoek wil plannen, moet men er zeker van zijn dat met dit onderzoek niet op een zondag plant.
De functie maand geeft de maand van een opgegeven datum terug als nummer. Als onze opgegeven datum bijvoorbeeld 12 oktober 2002 is, dan zullen we het nummer 10 terugkrijgen van deze functie. Oktober is immers de tiende maand van een jaar.
De functie eerstedagmaand geeft een datum terug. Deze datum zal dezelfde maand en hetzelfde jaartal hebben als de opgegeven datum. De dag van de opgegeven datum zal echter vervangen worden door de eerste dag van die maand van dat jaar. Dus eigenlijk zal de dag steeds 1 zijn. Dit kan eenvoudig gerealiseerd worden met behulp van de trunc-functie. Als we onze opgegeven datum voorstellen door de variabele dag, wordt de eerste dag van de maand bekomen door de functie trunc(dag,‘MONTH’). We nemen als voorbeeld terug de datum 12 oktober 2002. De functie eerstedagmaand zal voor deze datum, als resultaat de datum 1 oktober 2002 teruggeven.
De functie dagvanmaand geeft het nummer van de dag uit een opgegeven datum terug. Als we dus ons voorbeeld 12 oktober 2002 als datum opgeven, zullen we het nummer 12 als resultaat krijgen.
De functie naarString zal een opgegeven datum omzetten naar een standaard string voor het volledig uitschrijven van een datum. Onze voorbeelddatum zal dus resulteren in de string zaterdag 12 oktober 2002. 43
Hoofdstuk 4 : Implementatie
2.4.5 Package codegenerator
De procedures in de package codegenerator worden gebruikt door mezelf en Jan als hulpmiddel om snel alle privileges toe te kennen voor de verschillende groepen van gebruikers. In plaats van meer dan honderd keer het statement grant privilege on object to role; manueel te moeten uitvoeren, kunnen we éénmaal de procedure toekenning aanroepen. Deze procedure zal al deze statements dan voor ons genereren. We moeten natuurlijk wel de tabel Rechten aanmaken om te definiëren welke privileges een bepaalde role heeft op een bepaald object. Deze package hoort dus net zoals de tabel Rechten niet bij de feitelijke databank. We zullen net als bij de bespreking van de vorige package elke procedure apart bespreken.
De procedure synoniemen maakt synoniemen aan voor tabellen, views en sequences. Al deze elementen worden normaal opgeroepen als JAN.elementnaam waarbij JAN de persoon is die de betreffende elementen heeft aangemaakt en elementnaam de naam van het element voorstelt. Met behulp van onze procedure synoniemen kunnen we er nu voor zorgen dat al deze elementen ook opgeroepen kunnen worden door enkel de naam van het element te gebruiken.
Dit doen we door het synoniem elementnaam aan te maken voor
JAN.elementnaam.
De procedure drop_synoniemen verwijdert de synoniemen die bij de elementen horen die door JAN aangemaakt zijn.
De procedure toekenning kent privileges toe voor de verschillende elementen uit de databank aan verschillende rollen van gebruikers. De gegevens voor het toekennen zullen uit de tabel Rechten gehaald worden. Deze tabel Rechten wordt aangemaakt door de procedure fill_rechten die hierna zal besproken worden. Zowel de privileges die toegekend moeten worden als het betreffende element uit de databank als de rol van gebruikers worden uit de tabel Rechten gehaald.
De procedure fill_rechten zal dus objecten toevoegen aan de tabel Rechten. De waarden die hierdoor in de tabel Rechten komen zullen gebruikt worden in de procedure toekenning voor het effectief toekennen van de privileges.
De inhoud van deze tabel is opgenomen in
Appendix C. 44
Hoofdstuk 4 : Implementatie
2.5. Procedures
Bij de procedures kunnen parameters meegegeven worden. Afhankelijk van deze parameters wordt dan dynamisch een HTML-pagina aangemaakt. Er worden ook regelmatig verborgen parameters meegegeven aan een procedure oproep. De gebruiker heeft met andere woorden geen weet van deze parameters. Aan de hand van de naam van de knop weten we welke opdracht de gebruiker wilt uitvoeren. Deze naam wordt automatisch doorgegeven onder de vorm van een parameter. De verschillende knoppen van een formulier roepen eenzelfde procedure op. Afhankelijk van de waarde van de parameter, weet men op welke knop de gebruiker geklikt heeft. Bijgevolg weet men welke opdracht de gebruiker gegeven heeft en welke delen van de procedure bijgevolg moeten uitgevoerd worden.
De procedures die in deze paragraaf (paragraaf 2.5) zullen besproken worden, zijn procedures die vooral de implementatie van de reeds bestaande databank omvatten.
Verder in dit
hoofdstuk zullen we ook de uitbreidingen bespreken aan de bestaande databank.
De
procedures die verband houden met deze uitbreidingen zullen dan ook daar besproken worden in plaats van in deze paragraaf.
2.5.1 Procedure patienten
De procedure patienten geeft de mogelijkheid aan de gebruiker om een patiënt op te zoeken of toe te voegen. Wanneer men een patiënt opzoekt met behulp van de beginletters van zijn naam krijgt men als resultaat een lijst van alle patiënten die overeenstemmen met de opgegeven criteria.
De lijst van patiënten wordt gevolgd door de gegevens van deze
patiënten. Deze gegevens kunnen hier bovendien gewijzigd worden. Bij elke patiënt heeft men bovendien de mogelijkheid om naar de onderzoeken, de medicatie of de berichten van de patiënt te gaan. Tot slot kan men hier ook een patiënt verwijderen uit de databank. Wanneer je een patiënt verwijdert, wordt niet enkel de patiënt verwijderd maar worden tevens zijn onderzoeken, zijn medicatie en zijn berichten verwijderd. Deze extra verwijderingen zijn logisch en bovendien noodzakelijk om de patiënt zelf te kunnen verwijderen. De objecten die mee verwijdert worden met een patiënt hebben immers allemaal een link (vreemde sleutel) naar de patiënt.
45
Hoofdstuk 4 : Implementatie
Later in dit hoofdstuk zullen we de zoekcriteria uitbreiden zodat het ook mogelijk wordt een patiënt op te zoeken met behulp van zijn UZ-identificatienummer. 2.5.2 Procedure onderzoekpatient
Met behulp van de procedure onderzoekpatient kan men voor elke patiënt de geplande onderzoeken bekijken, wijzigen of verwijderen. Hier kan men ook een nieuw onderzoek plannen voor een patiënt.
Voor de planning van de onderzoeken hebben we een kalendersysteem ontworpen en geïmplementeerd. Daar dit kalendersysteem één van de uitbreidingen aan de databank is, zullen we er later in dit hoofdstuk meer over schrijven.
Het kamernummer dat vroeger werd bijgehouden in de tabel TPatientGegevens wordt nu bijgehouden in de tabel TPlanningOnderzoeken. Dit kamernummer hoort immers bij een gepland EEG-onderzoek. Met kamernummer bedoelen we dus niet het nummer van de kamer waar de patiënt zal verblijven tijdens zijn opname op de dienst Neurologie.
Het
kamernummer is namelijk het nummer van één van de drie kamers waar een EEG-onderzoek kan worden uitgevoerd. Bij de planning van een onderzoek zullen we dus een controle inbouwen zodat enkel onderzoeken van de klasse EEG een kamernummer kunnen invullen. Bovendien voeren we ook nog een controle uit die een dubbele boeking van een kamer moet voorkomen. Voor deze laatste controle maken we gebruik van het kalendersysteem. Het kalendersysteem houdt immers de bezetting van de kamers voor EEG-onderzoeken bij.
Bij elk onderzoek zullen we ook een link leggen naar de resultaten van het onderzoek. Aangezien een bepaald onderzoek meerdere bestanden met resultaten kan hebben, zullen de resultaten bijgehouden worden in een aparte tabel. Bij elk resultaat zal er dan een link gelegd worden naar het bijhorende onderzoek.
2.5.3 Procedure medicatiepatient
Met behulp van de procedure medicatiepatient kan men de medicatie bekijken, wijzigen of verwijderen die een patiënt neemt. Daarnaast kan men ook nog nieuwe medicatie toevoegen 46
Hoofdstuk 4 : Implementatie
voor een patiënt. Men zal hier enkel een medicament en een dosis moeten opgeven. De soort en eenheid van een medicament blijven immers vast verbonden met het medicament.
2.5.4 Procedure berichtpatient
Berichten worden automatisch aangemaakt wanneer gegevens toegevoegd, gewijzigd of verwijderd worden. Deze berichten kan men dus enkel bekijken of verwijderen.
We hebben de berichten ingedeeld in verschillende categorieën. De berichten kunnen dan per categorie opgevraagd worden via een keuzelijst. Omdat de berichten in verband met de planning van de onderzoeken het belangrijkste zijn, toont men eerst de berichten in verband met de onderzoeken wanneer de berichten worden opgevraagd. De andere berichten kunnen dan bekeken worden door de bijhorende categorie te kiezen uit de keuzelijst.
Aangezien er veel berichten gegenereerd worden, is het ook mogelijk om alle berichten tot een bepaalde datum te verwijderen in plaats van elk bericht afzonderlijk te verwijderen. Wanneer we een datum opgeven, zullen alle berichten die voor deze datum gegenereerd zijn verwijderd worden.
De berichten in verband met onderzoeken worden beschouwd als een vorm van communicatie tussen de receptionist en de arts. Wanneer een arts ziet dat de gegevens van een gepland onderzoek gewijzigd zijn, weet hij dat de receptionist een datum voor dat onderzoek heeft vastgelegd of dat de geplande datum voor het betreffende onderzoek gewijzigd is. Bovendien is deze berichtenpagina een soort logboek aangezien het alle wijzigingen aan de databank vermeldt.
Dit alles wordt gerealiseerd met behulp van de procedure berichtpatient. Een screenshot van het resultaat van de procedure berichtpatient is te zien in figuur 4.11 .
47
Hoofdstuk 4 : Implementatie
Figuur 4.11 screenshot van de berichtenpagina
2.5.5 Procedure onderzoeken
De gegevens omtrent onderzoeken kunnen ook per naam van het onderzoek opgevraagd worden via de procedure onderzoeken. Hier zal men onderzoeken kunnen bekijken, wijzigen of verwijderen. Uiteraard zal men hier geen onderzoek kunnen toevoegen. Het is hier immers de bedoeling om een overzicht te geven van alle onderzoeken.
We zullen deze onderzoeken sorteren volgens datum. De onderzoeken met de meest recente datum zullen bovenaan komen te staan. Wanneer er nog geen datum vastgelegd is voor een gepland onderzoek zal dit onderzoek zelfs boven de recente onderzoeken staan. Dit is dus handig voor de receptionist. Wanneer de receptionist deze lijst van onderzoeken bekijkt, weet hij voor welke onderzoeken er nog een datum moet vastgelegd worden.
48
Hoofdstuk 4 : Implementatie
2.5.6 Procedure administratie
Het administratiegedeelte wordt verzorgd door de procedure administratie. Deze procedure is veruit de grootste van alle procedures. De gegevens die men hier kan bekijken, wijzigen, toevoegen of verwijderen zijn administratieve gegevens die zelden aangepast moeten worden. Het gaat bijvoorbeeld om het toevoegen van een nieuwe arts op de dienst Neurologie of om het toevoegen van een nieuwe klasse voor onderzoeken. Het administratiegedeelte biedt ook de mogelijkheid om een nieuw medicament op te nemen in de lijst van medicatie. Men kan hier ook een eenheid van medicatie of een soort medicatie toevoegen, wijzigen of verwijderen. Gebruikers van de webinterface (of van de databank om precies te zijn) worden zelfs hier aangemaakt of verwijderd door de administrator.
3. Verdere uitwerking
3.1. Checksum
Wanneer twee mensen ongeveer tegelijkertijd gegevens wijzigen kan het voorkomen dat er gegevens verloren gaan. Neem als voorbeeld dat een receptioniste en een dokter beiden de onderzoeken van dezelfde patiënt bekijken op hun eigen computer.
Stel nu dat de
receptioniste de datum van het EEG-onderzoek van de patiënt wijzigt. De receptioniste krijgt de bevestiging dat de gegevens gewijzigd zijn. Ondertussen bekijkt de dokter nog steeds de oude pagina. Wanneer de dokter nu een opmerking schrijft bij dit onderzoek geeft hij tevens de oude datum van het onderzoek door. De opmerking en de datum zullen dus gewijzigd worden. Hierdoor zal de wijziging van de datum die de receptioniste heeft doorgevoerd ongedaan gemaakt worden. Om dit probleem op te lossen voeren we een checksum in.
Wanneer de gegevens op het scherm getoond worden wordt er voor deze gegevens een som berekend op basis van de waarden die dan in de databank zitten. Voordat de gegevens gewijzigd worden, zal er voor dezelfde gegevens opnieuw een som berekend worden op basis van de waarden in de databank. Indien de gegevens niet veranderd zijn, dan zal de databank dezelfde waarden bevatten voor deze gegevens als bij de vorige berekening. Deze identieke waarden zullen dan ook resulteren in een checksum die identiek is aan de vorige cecksum. 49
Hoofdstuk 4 : Implementatie
Wanneer beide sommen niet identiek blijken te zijn, weet men dat de gegevens ondertussen reeds gewijzigd werden door een andere gebruiker van de databank.
Men kan dit dan
meedelen aan de gebruiker samen met de nieuwe waarden van de gewijzigde gegevens. De gebruiker kan aan de hand van deze nieuwe waarden opnieuw proberen om zijn wijzigingen door te voeren. Om een beter beeld te kunnen geven van deze checksum hebben we de berekening ervan opgenomen in figuur 4.12.
Zoals we al vermeld hebben in ons ontwerp willen we bij het verwijderen van gegevens de techniek van lazy deletion toepassen. Daarom hebben we een kolom deleted toevoegd in elke tabel. Voor elk object dat aangemaakt wordt, zal het veld deleted standaard op 0 geplaatst worden. Wanneer echter een object uit de databank verwijderd wordt, zal dit object niet echt verwijderd worden uit de databank maar wordt het veld deleted dat bij het object hoort op 1 geplaatst. Wanneer objecten opgevraagd worden, worden deze opgevraagd uit een view die enkel de objecten met het veld deleted op 0 toont. Dit geeft de indruk aan de gebruiker dat de objecten met het veld deleted op 1 ook effectief verwijderd zijn. Een eerste voordeel van het gebruik van dit extra veld is dat men ook nog deze verwijderde objecten kan bekijken. Een tweede voordeel dat eigenlijk een logisch gevolg is van het eerste voordeel is dat men deze verwijderde objecten zelfs eenvoudig terug kan toevoegen aan de databank. Een van de administrators hoeft hiervoor enkel op een knop activeren te klikken in het administratiegedeelte waarna het veld deleted van dit object terug op 0 geplaatst wordt.
We voorzien in het administratiegedeelte ook een mogelijkheid om verwijderde gegevens effectief uit de databank te verwijderen. Dit om te voorkomen dat de databank alle gegevens zou blijven bijhouden die niet meer nodig zijn. Deze onnodige gegevens vertragen immers het ophalen van andere gegevens uit de databank.
50
Hoofdstuk 4 : Implementatie
3.2.1 Procedure administratie
Als gevolg van het toevoegen van de kolom deleted in elke tabel, hebben we dus de procedure administratie uitgebreid.
Bij het administratiegedeelte kan men nu ook de verwijderde
gegevens bekijken en terug activeren.
3.3. Stylesheets
Daar onze implementatie reeds ver gevorderd is, wordt het tijd om wat meer aandacht aan de webinterface te besteden. We zullen hiervoor onder andere gebruik maken van stylesheets. Met behulp van stylesheets kennen we een stijl toe aan HTML tags. We verzamelen de verschillende stijlen die we gebruiken dus in één css-bestand. Wanneer we een stijl willen aanpassen, hoeven we dit enkel in dit bestand te doen. Gelijkaardige gegevens zullen gebruik maken van eenzelfde klasse. Zo zorgen we er bijvoorbeeld voor dat alle verzendknoppen eenzelfde stijl hebben. Daarnaast gebruiken we deze stylesheets ook om een toegevoegd of een gewijzigd object op te laten lichten.
Dit oplichten wordt gerealiseerd door het
toegevoegde of gewijzigde object in een oranje kadertje te zetten. Het bestand epd-style.css uit figuur 4.13 is het door ons gebruikte stylesheetbestand. Men kan duidelijk de koppeling zien tussen de HTML tags en de stijl.
Wanneer een object verwijderd wordt, willen we met zekerheid weten dat het ook effectief de bedoeling was om dat object te verwijderen. Daarom tonen we steeds een berichtvenster met de vraag of men zeker is dat men het object wilt verwijderen waarvan men zojuist op de verwijdertoets geklikt heeft.
Voor het tonen van een berichtvenster hebben we gebruik
gemaakt van Javascript. In figuur 4.14 hebben we een voorbeeld opgenomen van Javascript. Javascript wordt in de header van een HTML-pagina geplaatst. In figuur 4.15 zien we een oproep naar de functie vraagVerwijder(naam). Deze oproep zal voorkomen in het bodygedeelte van de HTML-pagina. Indien de functie vraagVerwijder(Katrien Penneman) wordt opgeroepen zal er een berichtenvenster verschijnen met de vraag Bent u zeker dat u de gegevens van Katrien Penneman wilt verwijderen? .
Figuur 4.15 oproep van de functie vraagVerwijder(naam)
Met behulp van Javascript kunnen we de beperkingen van HTML omzeilen of oplossen. Bij het aanmaken van een formulier waarbij de onderzoeken, de medicatie en de berichten van een patiënt kunnen opgevraagd worden, maakten we gebruik van knoppen in aparte HTML formulieren om onderscheid te kunnen maken tussen de onderzoeken, de medicatie en de berichten. We kwamen echter tot de vaststelling dat de verzendknoppen van het formulier onder elkaar getoond werden op het scherm met veel witte ruimte tussen de verschillende knoppen. We maakten gebruik van Javascript om deze verzendknoppen naast elkaar op het
52
Hoofdstuk 4 : Implementatie
scherm te tonen daar we de pagina niet te lang willen maken zodat de gebruikers niet te veel hoeven te scrollen.
Wanneer er een foutpagina getoond wordt op het scherm, is het meestal handig om terug te kunnen keren naar de vorige pagina. De gebruiker kan hiervoor gebruik maken van de backknop in de werkbalk van zijn browser. Maar om de gebruiker beter te bedienen plaatsen we bij elke foutpagina een knop terugkeren. Met behulp van de functie javascript:history.back() kunnen we de gebruiker zo laten terugkeren naar de vorige pagina.
3.4.1 Procedure hoofding
Als gevolg van het gebruik van stylesheets en Javascript, hebben we een procedure hoofding gemaakt. Deze procedure bevat de code die anders in elke procedure bovenaan zou staan. Het is dus eenvoudiger om deze code één keer in een procedure te schrijven. Bovendien is het gemakkelijker om met een aparte hoofding te werken. Indien we later wijzigingen of uitbreidingen willen aanbrengen aan de hoofding, hoeven we maar één procedure aan te passen.
3.4.2 Procedure sluiting
Analoog aan de procedure hoofding hebben we ook een procedure sluiting gemaakt. Deze is echter vrij beknopt en was niet echt noodzakelijk, maar omdat het mooier is om naast de procedure hoofding ook een procedure sluiting te hebben, hebben we de gemeenschappelijke eindcode van alle procedures gegroepeerd in een procedure sluiting.
3.5. Roles
Er is nu een volledige implementatie waarbij er geen beperkingen zijn op de toegang tot de databankgegevens. De rol van administrator is dus beschikbaar. Voor de andere rollen moeten we nog enkele if-statements toevoegen aan de code.
Er is ook een foutpagina
aangemaakt voor het geval een gebruiker iets wilt uitvoeren waartoe hij geen recht heeft.
53
Hoofdstuk 4 : Implementatie
Figuur 4.16 is een codefragment dat controleert of de gebruiker het recht heeft de betreffende pagina op te roepen. De view VRoles selecteert de door ons aangemaakt gebruikersrollen uit de tabel sys.session_roles.
select role into rol from VRoles ; if rol!='ADMINISTRATOR' then htp.print('
U probeert een pagina op te vragen waar u geen toegang tot hebt. Gelieve contact op te nemen met de administrator.
Figuur 4.16 codefragment met controle op gebruikersrol
3.6. Kalendersysteem
Voor de planning van de onderzoeken hebben we een kalendersysteem geïmplementeerd zodat de receptionisten niet meer met een agenda hoeven te werken maar over een online agenda beschikken.
3.6.1 Procedure kalender
De procedure kalender geeft de gebruiker een overzicht van de bezetting van de kamers voor het EEG-onderzoek. De gebruiker kan een maand en een jaartal kiezen waarvoor hij de bezetting van de onderzoekskamers wil bekijken. Er is een controle ingebouwd zodat men enkel een kamer kan reserveren voor een EEG-onderzoek . Wanneer men een kamer probeert te reserveren voor een onderzoek van een andere klasse zal men een foutboodschap krijgen. Er is ook een controle ingebouwd zodat men geen kamer kan reserveren die reeds gereserveerd was.
54
Hoofdstuk 4 : Implementatie
3.7. Opslag van resultaten van onderzoeken
Om het opslaan van bestanden in de databank mogelijk te maken moeten we de informatie in verband met de indicator die we aangemaakt hebben wijzigen. Meer specifiek moeten we het gedeelte over Document Access Information invullen. We zullen opteren om een bestand op te laden als een blob. We kunnen een bestand ook opladen als een long raw als we de extensie van dit bestand vermelden in het veld Extensions to be uploaded as Long Raw. In het veld Document Table moeten we de tabelnaam invullen van de tabel waar de bestanden zullen in bijhouden. Deze tabel moet wel voldoen aan de standaard definitie. In figuur 4.17 ziet u zo’n definitie, namelijk van de tabel resultaten.
Deze tabel houdt voor ons de
bestanden bij die het resultaat zijn van een onderzoek.
varchar2(256) unique not null, varchar2(128), number, varchar2(128), date, varchar2(128), blob
Figuur 4.17 tabeldefinitie van de tabel resultaten
Wanneer je de bestanden terug wil tonen op het scherm moet je de velden Document Access Path en Document Access Procedure ook invullen. Deze velden zijn dus nodig voor het downloaden van bestanden uit de databank. Het veld Document Access Path heeft een naam nodig die het pad specificeert om het bestand te bereiken. Deze naam volgt in de URL op de naam van de indicator. Wanneer we bijvoorbeeld files invullen voor deze naam en we in onze tabel resultaten een bestand hebben met de naam result.avi dan kunnen we dit bestand opvragen met de URL http://localhost/pls/epd/files/result.avi. In het veld Document Access Path moet je de naam van de procedure invullen die instaat voor het downloaden van de bestanden uit de databank. Deze procedure roept wpg_docload.download_file(result.avi) op om het bestand result.avi te tonen op het scherm. In onze implementatie heeft deze procedure de naam showresultaat gekregen. Met deze aanpassing aan onze indicator, kunnen we nu onze procedures showresultaat en uploadresultaat aanmaken. Want ook voor het opladen
55
Hoofdstuk 4 : Implementatie
van bestanden moeten we een procedure schrijven. Deze procedure moeten we echter niet vermelden in onze configuratie.
3.7.1 Procedure uploadresultaat
De relevante code uit de procedure uploadresultaat om een bestand op te laden in de tabel resultaten is vrij kort. U kan deze code bekijken in figuur 4.18. Het bestand uploadresultaat is echter veel langer dan het codefragment in figuur 4.18 omdat het niet enkel een bestand moet opladen naar de tabel resultaten maar ook nog een link naar dit bestand moet leggen in een andere tabel van de databank, namelijk in de tabel TPlanningResultaten.
PROCEDURE UPLOADRESULTAAT ( resultaatin IN varchar2 default null, opdracht IN varchar2 default null) IS BEGIN hoofding ; if opdracht='toevoegen' htp.print('bestand ' || resultaatin || ' succesvol opgeladen'); else htp.print('