Business-manual
inleiding
OVERZICHT:
-
TIPS EN AANWIJZINGEN VOOR HET MAKEN VAN EEN BESLISSINGSTABEL.
- VOORBEELDPROGRAMMA 1
-
- ONDERSCHEID TUSSEN PROPOSITIE EN ATTRIBUUT (EN DOELATTRIBUUT).
-
-
MOGELIJKHEDEN OM EEN PROPOSITIE TE BEWIJZEN
-
gevraagd aan de gebruiker
-
aanwezigheid van gegevens in de database via een databaseview
-
bewijzen/afleiden door middel van een of meer beslissingstabellen
-
-
-
MOGELIJKHEDEN OM EEN WAARDE TE VERKRIJGEN VOOR EEN ATTRIBUUT
-
gevraagd aan de gebruiker
-
ophalen uit een gekoppelde database
-
afleiden uit een of meer beslissingstabellen
-
afleiden uit een formule
-
-
- MET CASES IN HET DOELATTRIBUUT-STATEMENT WORDT AANGEGEVEN WELKE ACTIES WORDEN UITGEVOERD.
-
- MET DATABASE-VIEWS WORDEN GEGEVENS OPGEHAALD UIT EEN DATABASE.
-
-
MET EEN DATABASEVIEW EN EEN HERHAALBAAR DOELATTRIBUUT WORDEN ALLE GEGEVENS VOOR DEZE VIEW SEQUENTIEEL OPGEHAALD UIT EEN DATABASE.
-
VOORBEELDPROGRAMMA 2
-
-
-
MET DATABASEVIEWS EN OPEENVOLGENDE HERHAALBARE DOELATTRIBUTEN WORDEN ALLE GEGEVENS EN ALLE ONDERLIGGENDE GEGEVENS SEQUENTIEEL OPGEHAALD UIT EEN DATABASE.
-
VOORBEELDPROGRAMMA 3
-
doelgericht, achterwaarts redeneren
Het ingebouwde redeneermechanisme in BusinessRuler is gebaseerd op doelgericht, achterwaarts redeneren.
Dat betekent: elke variabele of attribuut die aanwezig is als conditie in een beslissingstabel of is opgenomen in een formule wordt: 1. gevraagd aan de gebruiker (door middel van askable_using), of 2. opgehaald uit een database (bijv. Sqlite, PostgreSQL, enz.), of 3. bewezen/afgeleid in andere beslissingstabellen (indien opgenomen in het conclusiegedeelte van deze tabellen), of 4. bewezen/afgeleid via een formule.
Elk attribuut/variabele dat opgenomen is als conclusie in een beslissingstabel die - niet kan worden gekoppeld aan een conditie in een andere tabel en - niet wordt toegepast in een formule/expressie wordt automatisch opgevat als een doelattribuut.
Dit betekent dat elk programma in BusinessRuler tenminste één beslissingstabel bevat waar in het conclusiegedeelte alle mogelijke waarden voor het doelattribuut als conclusie aan bod komen.
Veel vaker zullen alle mogelijke waarden voor het doelattribuut in veel meer opeenvolgende beslissingstabellen worden beschreven.
Het redenereermechanisme probeert nu waarden voor het doelattribuut te bewijzen in de volgorde waarin ze zijn opgenomen in het conclusiegedeelte van alle opeenvolgende beslissingstabellen.
Hiermee begint het redeneermechanisme niet per sé met de eerste beslissingstabel, maar wel met de eerste tabel waarin één of meerdere waarden voor het doelattribuut worden geconcludeerd.
De algemene structuur van een beslissingstabel ziet er als volgt uit:
Table x: Willekeurige beschrijving van de tabel of leeg.
If: | 0| 1| 2| 3|
conditie 1 | Y| Y| Y| N|
conditie 2 | Y| N| N| -|
conditie n | -| Y| N| -|
Then:
actie 1/conclusie 1 | | | | X|
actie 2/conclusie 2 | X| X| | |
actie n/conclusie n | | | X| |
# .......
Door middel van de aanwezige streepjes in de genummerde kolommen (of beslissingsregels) in de tabel kan worden bepaald of de tabel compleet is.
Elk streepje "-" in een kolom staat voor een combinatie van 2 mogelijkheden, namelijk Y en N, dus 2 streepjes in een kolom staan voor 4 mogelijkheden (22), 3 streepjes voor 8 mogelijkheden (22*2), enzovoort.
Drie conditie's in een tabel leveren 2 tot de macht 3 mogelijke combinaties (=8), en dat moet gelijk zijn aan de som van de mogelijke combinaties van de opeenvolgende kolommen; in bovenstaande voorbeeld dus 2+1+1+4 (=8).
Deze controle op compleetheid wordt door de generator voor iedere tabel uitgevoerd, maar kan ook worden uitgeschakeld door Table te vervangen door rTable:
rTable x:
If: | 0| 1| 2|
conditie 1 | Y| Y| Y|
conditie 2 | Y| N| N|
conditie n | -| Y| N|
Then:
actie 2/conclusie 2 | X| X| |
actie n/conclusie n | | | X|
# .......
Waarbij rTable staat voor reduced table.
Eenvoudig voorbeeld
Als voorbeeld worden nu enkele eenvoudige beslissingstabellen gemaakt voor een heel eenvoudig beslissingsprobleem:
=== Op basis van de aanwezigheid van een drietal symptomen wordt bepaald of 1. aanvullende PCR-tests nodig zijn, of 2. standaard quarantainepraktijk kan worden aangehouden, of 3. geen vervolgactie nodig is.
Bij stap 1 wordt een patient gevraagd of er sprake is van niezen en/of hoesten als symptomen. Bij stap 2 wordt bepaald of de patient koorts heeft. De standaardkoortsdrempel is 38°C; vanwege verschillende meetmethoden voor jonge kinderen en de bijbehorende nauwkeurigheid, wordt voor patiënten jonger dan 10 jaar aangenomen dat de koortsdrempel 37,2°C is.
Op basis van de eerste twee stappen wordt het aantal gepresenteerde symptomen bepaald.
Als een patiënt ten minste twee (2) van deze symptomen vertoont, worden daaropvolgende PCR-tests uitgevoerd,
anders worden standaard quarantainepraktijken geadviseerd. Als er geen symptomen zijn is een vervolgactie niet nodig.
====
TIPS EN AANWIJZINGEN VOOR HET MAKEN VAN EEN BESLISSINGSTABEL:
- Maak tabellen, zeker de meer ingewikkelde, eerst op papier en niet direct in een editor zoals Notepad++.
- Maak de kolommen (of beslissingsregels) van links naar rechts en werk van 'Y' naar 'N'; de meest linker kolom zal dan alleen 'Y' en '-' bevatten.
- Het streepje in een beslissingskolom betekent 'niet mogelijk' of 'maakt niet uit' (don't care).
- Zet de condities op volgorde van afnemende relevantie in de tabel. Als stap 1 in het voorbeeld 2 symptomen aantoont hoeft stap 2 niet meer uitgevoerd te worden; de conditie 'Koorts' is voor de beslissing niet meer relevant.
Met deze aanwijzingen kan het volgende voorbeeldprogramma voor BusinessRuler worden gemaakt:
VOORBEELDPROGRAMMA 1:
Table 0:
If: | 0| 1| 2| 3| 4| 5|
'Volgende Client?' | Y| Y| Y| Y| Y| N|
Stap1_symptomen = 2 | Y| N| N| N| N| -|
Stap1_symptomen = 1 | -| Y| Y| N| N| -|
Koorts = 1 | -| Y| N| Y| N| -|
Then:
Actie is AlleClientenVerwerkt | | | | | | X|
Actie is PCR_test | X| X| | | | |
Actie is InQuarantaine | | | X| X| | |
Actie is AllesOK | | | | | X| |
# .......
Proposition: 'Volgende Client?' Askable_using: "Volgende Client?"
Attribute: Stap1_symptomen Equals: Niezen + Hoesten
Attribute: Niezen Type: Integer Askable_using: "Niest de client (0=Nee, 1=Ja)?" Attribute: Hoesten Type: Integer Askable_using: "Hoest de client (0=Nee, 1=Ja)?"
Table 1:
If: | 0| 1| 2| 3|
Leeftijd >= 10 | Y| Y| N| N|
Temperatuur >= 38.0 | Y| N| -| -|
Temperatuur >= 37.2 | -| -| Y| N|
Then:
Koorts = 1 | X| | X| |
Koorts = 0 | | X| | X|
# .......
Attribute: Leeftijd Askable_using: "Wat is de leeftijd?" Attribute: Temperatuur Askable_using: "Wat is de temperatuur?"
GoalAttribute: Actie Repeat_until: AlleClientenVerwerkt
CASE
Case: AlleClientenVerwerkt
Print: "Klaar met verwerken!"
Case: PCR_test
Print: "Resultaat: doe een PCR-test!"
Print: "------------------------------------"
Case: InQuarantaine
Print: "Resultaat: standaard quarantaine praktijk."
Print: "------------------------------------"
Case: AllesOK
Print: "Resultaat: geen actie vereist.."
Print: "------------------------------------"
-----------------------------------------------------------------------------------------------------------------------------------
TIP: print bovenstaand scriptbestand op 1 A4-tje om deze naast de vervolgtekst te leggen.
In bovenstaand scriptbestand worden de propositie 'Volgende Client?' en de attributen Stap1_symptomen, Niezen en Hoesten voorzien van het statement: Askable_using:, zodat dit bestand interactief kan worden uitgevoerd:
"Volgende Client? (y/n)? > y "Niest de client (0=Nee, 1=Ja)?" (int)> 1
"Hoest de client (0=Nee, 1=Ja)?" (int)> 1
Resultaat: doe een PCR-test!
"Volgende Client? (y/n)? > y "Niest de client (0=Nee, 1=Ja)?" (int)> 0
"Hoest de client (0=Nee, 1=Ja)?" (int)> 1
"Wat is de leeftijd?" (int)> 9
"Wat is de temperatuur?" (real)> 37.1
Resultaat: standaard quarantaine praktijk.
"Volgende Client? (y/n)? > n Klaar met verwerken!
Merk op dat beslissingstabel 1 niet wordt uitgevoerd als er sprake is van Hoesten EN Niezen. Dat is precies het effect van de eerste kolom in de eerste beslissingstabel.
Over het gegeven scriptbestand in BusinessRuler kunnen wel wat opmerkingen worden gemaakt die kunnen worden opgevat als een eerste handleiding om met deze tool te werken.
- ONDERSCHEID TUSSEN PROPOSITIE EN ATTRIBUUT (EN DOELATTRIBUUT).
Een propositie is een willekeurige uitspraak of bewering (of vraag) tussen SINGLE quotes ('), die waar of onwaar kan zijn. In het scriptbestand dus de conditie: 'Volgende Client?'
Een attribuut is een variabele die kan worden opgenomen in een conditie of conclusie in een beslissingstabel of in een formule.
In het scriptbestand komen de volgende attributen voor: - Stap1_symptomen in de condities: Stap1_symptomen = 2 en Stap1_symptomen = 1; gegevenstype: Integer - Koorts in de conditie: Koorts = 1 en in de conclusies Koorts = 1 en Koorts = 0 - Niezen en Hoesten in de formule: Niezen + Hoesten - Leeftijd in de conditie: Leeftijd >= 10 - Temperatuur in de conditie: Temperatuur >= 38.0 en Temperatuur >= 37.2; gegevenstype: Real - Actie in de conclusies: Actie is AlleClientenVerwerkt, Actie is PCR_test, Actie is InQuarantaine, Actie is AllesOK; gegevenstype: Symbol
Een bijzonder attribuut is Actie, die automatisch wordt aangemerkt als DOELATTRIBUUT, omdat er niet een andere beslissingstabel is waar dit attribuut als conditie is opgenomen en ook niet een formule is waar dit attribuut in voorkomt.
Dit attribuut is ook bijzonder vanwege het gegevenstype; het is niet een Integer of een Real, maar ook niet van het type Text - bijvoorbeeld: Actie = "AllesOK" - maar van het type Symbool: Actie is AllesOK.
De mogelijke symboolwaarden die attribuut Actie kan aannemen in het voorbeeldprogramma zijn AlleClientenVerwerkt, PCR_test, InQuarantaine, AllesOK; kortom, in de volgorde waarin deze waarden in opeenvolgende beslissingstabellen (maar hier één) worden aangetroffen.
Deze symboolwaarden kunnen niet als tekst worden behandeld en hebben een bijzondere betekenis in de taal zelf.
Het redenereermechanisme probeert symboolwaarden voor het doelattribuut te bewijzen in de volgorde waarin ze zijn opgenomen in het conclusiegedeelte van alle opeenvolgende beslissingstabellen.
In het voorbeeldprogramma dus precies in de volgorde: AlleClientenVerwerkt, PCR_test, InQuarantaine, AllesOK.
Let dus goed op de flow binnen een scriptbestand: deze begint niet automatisch met de eerste beslissingstabel, maar met de eerste beslissingstabel die één of meer waarden voor het doelattribuut afleidt. Worden in het voorbeeldprogramma de 2 beslissingstabellen omgewisseld, dan zal het redeneermechanisme dus met de tweede tabel beginnen!
Zodra een symbolische waarde voor een doelattribuut wordt bewezen worden de bijbehorende instructies onder de betreffende Case zoals vermeld onder het Doelattribuut-statement uitgevoerd, zoals terug te vinden in het voorbeeldprogramma.
De instructies onder een Case in het doelattribuut kunnen zijn:
- Print: - voor het uitvoeren van print-opdrachten naar het scherm, zie het voorbeeldprogramma,
maar bijvoorbeeld ook voor het maken van CSV-bestanden.
- >SQL:, -SQL:,
waarbij ook deze volgorde wordt aangehouden als er meerdere worden gebruikt.
Ook kan een doelattribuut worden herhaald door er Repeat_until: onder te zetten, gevolgd door het symbool (of de symbolen) die de herhaling zal beeindigen.
- MOGELIJKHEDEN OM EEN PROPOSITIE TE BEWIJZEN
A. In het voorbeeldprogramma wordt een propositie bewezen door een vraag te stellen aan de gebruiker door middel van 'Askable_using':
Proposition: 'Volgende Client?' Askable_using: "Volgende Client?"
B. Maar een propositie kan ook worden gebruikt om te controleren of er een volgend voorkomen (of instantie) van een bepaalde database view aanwezig is in de aangesloten database:
Proposition: 'Volgende_Client?' Obtain_instance_from_database_view: client
Dat kan als deze database view verderop in het scriptbestand is beschreven:
Database_view: client
With_attributes:
persoonid, naam, leeftijd, temperatuur, niezen, hoesten
Query:
SELECT *
FROM client
LIMIT 1 OFFSET %s
With_arguments: client.auto_index
C. Tot slot kan een propositie ook worden bewezen door deze af te leiden uit een andere beslissingstabel.
Zo kan in het voorbeeldprogramma de vierde conditie van de eerste tabel worden omgezet in een propositie 'Er is sprake van koorts'.
De tweede tabel wordt dan:
rTable 1: If: | 0| 1| Leeftijd >= 10 | Y| N| Temperatuur >= 38.0 | Y| -| Temperatuur >= 37.2 | -| Y| Then: 'Er is sprake van koorts' | X| X|
.......
die overigens wordt verkregen door in de volledige tabel:
Table 1: If: | 0| 1| 2| 3| Leeftijd >= 10 | Y| Y| N| N| Temperatuur >= 38.0 | Y| N| -| -| Temperatuur >= 37.2 | -| -| Y| N| Then: 'Er is sprake van koorts' | X| | X| |
.......
de overbodige kolommen te verwijderen (wat overigens ook niet per sé nodig is).
In het geval een propositie wordt afgeleid in een andere beslissingtabel kan het statement: Proposition: "Er is sprake van koorts" worden weggelaten.
- MOGELIJKHEDEN OM EEN WAARDE TE VERKRIJGEN VOOR EEN ATTRIBUUT.
A. In het voorbeeldprogramma wordt een waarde voor het attribuut verkregen door een vraag te stellen aan de gebruiker door middel van 'Askable_using':
Attribute: Temperatuur Askable_using: "Wat is de temperatuur?"
Maar ook:
Attribute: Niezen Type: Integer Askable_using: "Niest de client (0=Nee, 1=Ja)?"
Wat hierbij opvalt is dat Temperatuur niet voorzien is van een type-aanduiding en Niezen wel.
De regel is eenvoudig: als het type van een attribuut kan worden bepaald in één van de condities of conclusies van de aanwezige beslissingstabellen wordt vermelding van het type afgekeurd; in het andere geval is het juist verplicht.
Als gevolg van de conditie Temperatuur >= 38.0 wordt dit attribuut automatisch opgevat als Real. Zou dit attribuut alleen voorkomen in een conditie als Temperatuur >= Koortsdrempel_kind, dan kan het type niet worden bepaald en moet het dus wel in het attribuutstatement worden vermeld.
De gegevenstypen die op dit moment mogelijk zijn: Integer, Real, Text (en impliciet: Symbol).
B. Een waarde kan voor een attribuut worden verkregen door deze op te halen uit een gekoppelde database:
Attribute: Temperatuur Obtain_value_from_database_view: client.temperatuur
als de volgende view in het script aanwezig is:
Database_view: client
With_attributes:
persoonid, naam, leeftijd, temperatuur, niezen, hoesten
Query:
SELECT *
FROM client
LIMIT 1 OFFSET %s
With_arguments: client.auto_index
en als met de eerder genoemde propositie 'Volgende_Client?' (2B) is geconstateerd dat er een volgende instantie in de database aanwezig is.
In plaats van het attribuut Temperatuur kan in condities in beslissingstabellen en in formules ook direct naar een veld in een databaseview worden verwezen via: client.temperatuur; in dat geval is een "Obtain_value_from_database_view:" dus niet nodig.
Kan het gegevenstype van een database(view)veld niet worden bepaald in één van de beslissingstabellen, dan moet dat alsnog via: Attribute: client.temperatuur Type: Real
C. Een waarde voor een atttribuut kan worden bepaald door deze af te leiden uit een beslissingstabel.
In het voorbeeldprogramma:
Table 1: If: | 0| 1| 2| 3| Leeftijd >= 10 | Y| Y| N| N| Temperatuur >= 38.0 | Y| N| -| -| Temperatuur >= 37.2 | -| -| Y| N| Then: Koorts = 1 | X| | X| | Koorts = 0 | | X| | X|
.......
In feite wordt een integer hier als een soort Boolean gebruikt: 1 = Waar, 0 = Onwaar.
Ook hier is gebruik van het attribuut-statement niet nodig, behalve als het gegevenstype niet is vast te stellen in één van de beslissingstabellen.
D. Een waarde voor een atttribuut kan worden bepaald door deze af te leiden uit een formule.
In het voorbeeldprogramma:
Attribute: Stap1_symptomen Equals: Niezen + Hoesten
Andere voorbeelden:
Aanroepen van een python-functie leeftijd_op_uitvoerdatum met 2 argumenten, die de atttributen van een databaseview betreffen:
Attribute: PrikLeeftijd
Equals: leeftijd_op_uitvoerdatum(prik.uitvoerdatum, prik.geboortedatum)
De zelfgemaakte python-functies kunnen worden opgenomem in het bestand DTFunctions.py.
Geboortedatum in de database in formaat 'yyyy-mm-dd' omgezet naar datum waarop een persoon 12 jaar is in integerformaat yyyymmdd
Attribute: Datum_client_12_jaar Type: Integer Equals: to_integer(fdatum(prik.geboortedatum) + fdeltajaren(12))
Formules kunnen ook betrekking hebben op tekst:
Attribute: label_basis_volgend Type: Text Equals: "Basis" + str(aNr_volgend)
Formules kunnen ook verspreid worden over meerdere regels:
Attribute: units_in_tier3 Equals: End - Start if Start > Tier_3 \ else End - Tier_3 if End > Tier_3 \ else 0
Opmerking: deze conditionele expressie (met if en else) kan ook met een beslissingstabel:
Table 3: Units in tier 3 If: | 0| 1| 2| Start > Tier_3 | Y| N| N| End > Tier_3 | -| Y| N| Then: units_in_tier3 = End - Start | X| | | units_in_tier3 = End - Tier_3 | | X| | units_in_tier3 = 0 | | | X|
.......
- MET CASES IN HET DOELATTRIBUUT-STATEMENT WORDT AANGEGEVEN WELKE ACTIES WORDEN UITGEVOERD.
De instructies onder een Case in het doelattribuut kunnen zijn:
- Print: - voor het uitvoeren van print-opdrachten naar het scherm, zie het voorbeeldprogramma,
maar bijvoorbeeld ook voor het maken van CSV-bestanden.
- >SQL:, -SQL:,
waarbij ook deze volgorde wordt aangehouden als er meerdere worden gebruikt.
Een voorbeeld waarin de eerste 2 gecombineerd worden toegepast:
Case: Aanpassen_schema_DKTP_Hib_HepB_en_Pneu
Print: "Schema aangepast voor: %s met id: %s." Client.Naam Client.Clientid
Print: "-- Schema DKTP_Hib_HepB gewijzigd van %s naar %s." Client.DKTP_Hib_HepB_Schema DKTP_Hib_HepB_Schema_DT
Print: "-- Schema Pneu gewijzigd van %s naar %s." Client.Pneu_Schema Pneu_Schema_DT
SQL: "UPDATE Serie_Vaccin " -SQL: " SET Schema = %s " DKTP_Hib_HepB_Schema_DT -SQL: " WHERE Clientid = %s " Client.Clientid -SQL: " AND Serie_Vaccin_Info_id = %s " DKTP_Hib_HepB_id <SQL: " AND Volgnr = 1 "
SQL: "UPDATE Serie_Vaccin " -SQL: " SET Schema = %s " Pneu_Schema_DT -SQL: " WHERE Clientid = %s " Client.Clientid -SQL: " AND Serie_Vaccin_Info_id = %s " Pneu_id <SQL: " AND Volgnr = 1 "
Case: ....
Voor de hier gebruikte variabelen zijn alle afleidingsregels van toepassing: - een variabele met een '.' verwijst naar een database view met een bijbehorende attribuutnaam, bijvoorbeeld Client.Naam, als elders in het script de volgende database view is beschreven: Database_view: Client With_attributes: Clientid, Naam, Geslacht, Geboortedatum, .. Query: < SQL query > End_Query
- een variabele kan worden verkregen uit een formule achter Equals: in het Attribuut-statement, bijvoorbeeld: Attribute: label_basis_volgend Type: Text Equals: "Basis" + str(aNr_volgend)
Voor de variabelen/attributen binnen een formule zijn alle afleidingsregels weer van toepassing.
- een variabele kan worden verkregen uit een beslissingstabel, ook als deze geen rol heeft gespeeld bij het afleiden van een waarde voor het doelattribuut.
Table 4: Bepaal schema voor Pneu op draaidatum
If: | 0| 1| 2| 3|
Jobdatum < Datumwaarop6maanden | Y| N| N| N|
Jobdatum < Datumwaarop1jaar | -| Y| N| N|
Jobdatum < Datumwaarop2jaar | -| -| Y| N|
Then:
Pneu_Schema_DT = 1 | X| | | | Pneu_Schema_DT = 2 | | X| | | Pneu_Schema_DT = 3 | | | X| | Pneu_Schema_DT = 4 | | | | X|
Een voorbeeld van het gebruik van '>>:' voor het uitvoeren van instructies op lokale variabelen/attributen:
Case: Eligible
: month_ok = month_ok + 1 : period_textstring = period_textstring + ok_periodinfo : nr_current_month_ok = nr_current_month_ok + 1 : last_month_ok_string = current_month_ok_string
Als onder een Case alle mogelijke instructies, namelijk Print:, .SQL en >>: worden toegepast, dan in deze volgorde.
Als onder een Case geen enkele van de mogelijke instructies benodigd zijn, kan de Print: instructie worden gebruikt, die vervolgens wordt uitgeschakeld door #REM# op te nemen na de eerste double quote:
Case: Finished Print: "#REM# - "
Ook eventuele volgende regels met Print: onder dezelfde Case: worden hiermee uitgeschakeld. Een Case: zonder één van de vervolginstructies is dus niet mogelijk.
- MET DATABASE-VIEWS WORDEN GEGEVENS OPGEHAALD UIT EEN DATABASE.
Afhankelijk van de gekoppelde database moet ergens bovenaan in het script één van de volgende instructies worden opgenomen:
PostgreSQL_database: "teamperformance" SQLite_database: "Database/TeamPerformance.sqlite3"
Database views kennen 2 varianten, namelijk met en zonder argumenten.
Zonder argumenten wordt een database view afgesloten met End_Query:
Database_view: cancelled_flight With_attributes: flight, from, to, dep, arr, capacity, status Query: SELECT * FROM Flights WHERE status = 'cancelled' LIMIT 1 End_Query
Met argumenten wordt een database view afgesloten met With_arguments:
Database_view: cancelled_passenger With_attributes: name, status, miles, flight, flightstatus Query: SELECT * FROM Passenger WHERE Flight = '%s' LIMIT 1 OFFSET %s With_arguments: cancelled_flight.flight, cancelled_passenger.auto_index
-
Een SQL-query mag maximaal 1 voorkomen (occurence) opleveren (of geen), vandaar de 'LIMIT 1' in elke query.
-
Als in de query "SELECT *" wordt gebruikt, dan moet de query net zoveel velden opleveren als genoemd achter With_attributes, die vervolgens één op één hierin worden overgenomen.
-
Als in de SELECT in de query wel de kolomvelden worden genoemd, dan geldt hetzelfde, maar de naamgeving hoeft niet overeen te komen. In onderstaand voorbeeld is 'AS playername', 'AS teamname' en 'AS avgpoints' eigenlijk niet nodig.
VOORBEELD Database_view: highest_rated_players With_attributes: playerid, playername, teamname, totalpoints, totalgames, avgpoints Query: SELECT a.playerid, b.name AS playername, c.name AS teamname, a.totalpoints, a.totalgames, round(totalpoints1.0/totalgames, 2) AS avgpoints FROM sum_per_player AS a JOIN player AS b on (a.playerid = b.id) JOIN (SELECT playerid, name FROM game JOIN team WHERE game.teamid = team.id) AS c on a.playerid = c.playerid WHERE totalpoints1.0/totalgames = (SELECT max(totalpoints*1.0/totalgames) FROM sum_per_player) GROUP BY a.playerid LIMIT 1 OFFSET %s With_arguments: highest_rated_players.auto_index
-
De queries in een database view kunnen zeer complex zijn, maar het wordt zeer aanbevolen om deze complexiteit juist te verplaatsen naar de beslissingstabellen en de databaseviews zo eenvoudig (en leesbaar) als mogelijk te houden!
-
De opsomming van attributen mag ook direct na "With_attributes:" op dezelfde regel.
-
Ieder attribuut van een databaseview kan in condities in beslissingstabellen en in formules worden toegepast door middel van de notatie: viewnaam.atttibuutnaam; in dat geval is een "Obtain_value_from_database_view:" dus niet nodig.
Kan het gegevenstype van een database-attribuut niet worden bepaald in één van de beslissingstabellen, dan moet dat alsnog via: Attribute: viewnaam.attribuutnaam Type: [Integer|Real|Text]
-
Een attribuut van een databaseview is niet toepasbaar in het conclusiegedeelte van beslissingstabellen of afleidbaar uit een formule.
Wijzigen van gegevens in de database verloopt via >SQL:,-SQL:,<SQL onder de Case: van doelattributen. -
Voor argumenten van databaseviews kunnen alle attributen en database-attributen worden gebruikt, behalve... de attributen die juist met de betreffende databaseview worden opgehaald!
-
Hierop is precies 1 uitzondering: iedere database-view heeft ook 1 attribuut die niet uit de database wordt opgehaald en wel gebruikt kan worden als argument voor de eigen database-view, namelijk: auto_index.
Bij eerste instantiatie van de databaseview wordt het attribuut auto_index VOORAF al op 0 gezet, zodat in combinatie met de aanwezige "OFFSET %s" in de query automatisch het eerste voorkomen uit de database wordt opgehaald (hierbij ook rekening houdend met een eventuele ORDER in de query). Na het uitvoeren van de query wordt auto_index met 1 verhoogd, zodat bij een volgende uitvoer van de query, bijvoorbeeld als gevolg van een herhaalbaar doelattribuut (Repeat_until: ... onder GoalAttribute: ...) automatisch het volgende voorkomen van de query wordt opgehaald.
Met deze combinatie van herhaalbare doelattributen en de auto_index kunnen alle voorkomens van een bedrijfsentiteit, zoals klanten, leveranciers, etc. worden opgehaald en afgehandeld => voorbeeldprogramma 2.
Met een combinatie van opeenvolgende herhaalbare doelattributen en auto_indexen kunnen ook alle onderliggende voorkomens van een bedrijfsentiteit worden afgehandeld, zoals bijvoorbeeld alle adressen die zijn vastgelegd bij een klant of leverancier => voorbeeldprogramma 3.
- MET EEN DATABASEVIEW EN EEN HERHAALBAAR DOELATTRIBUUT WORDEN ALLE GEGEVENS VOOR DEZE VIEW SEQUENTIEEL OPGEHAALD UIT EEN DATABASE.
Op basis van het voorgaande kan voorbeeldprogramma 1 worden aangesloten op een database:
VOORBEELDPROGRAMMA 2:
SQLite_database: "Database/Coviddemo.sqlite3"
Table 0:
If: | 0| 1| 2| 3| 4| 5|
'Volgende Client?' | Y| Y| Y| Y| Y| N|
Stap1_symptomen = 2 | Y| N| N| N| N| -|
Stap1_symptomen = 1 | -| Y| Y| N| N| -|
Koorts = 1 | -| Y| N| Y| N| -|
Then:
Actie is AlleClientenVerwerkt | | | | | | X|
Actie is PCR_test | X| X| | | | |
Actie is InQuarantaine | | | X| X| | |
Actie is AllesOK | | | | | X| |
.......
Proposition: 'Volgende Client?' Obtain_instance_from_database_view: client
Attribute: Stap1_symptomen
Equals: client.niezen + client.hoesten
Attribute: client.niezen Type: Integer Attribute: client.hoesten Type: Integer
Table 1: If: | 0| 1| 2| 3| client.leeftijd >= 10 | Y| Y| N| N| client.temperatuur >= 38.0 | Y| N| -| -| client.temperatuur >= 37.2 | -| -| Y| N| Then: Koorts = 1 | X| | X| | Koorts = 0 | | X| | X|
.......
Database_view: client
With_attributes: persoonid,naam,leeftijd,temperatuur,niezen,hoesten
Query:
SELECT *
FROM client
LIMIT 1 OFFSET %s
With_arguments: client.auto_index
GoalAttribute: Actie Repeat_until: AlleClientenVerwerkt
Case: AlleClientenVerwerkt Print: "Klaar met verwerken!"
Case: PCR_test Print: "Resultaat %s: doe een PCR-test!" client.naam
SQL: "UPDATE client " -SQL: " SET result = 'PCR test', " -SQL: " fever = %s " Koorts.getvalue
<SQL: " WHERE name = '%s' " client.naam
Case: InQuarantaine Print: "Resultaat %s: standaard quarantaine praktijk." client.naam
SQL: "UPDATE client " -SQL: " SET result = 'Standaard quarantaine praktijk', " -SQL: " fever = %s " Koorts.getvalue
<SQL: " WHERE name = '%s' " client.naam
Case: AllesOK Print: "Resultaat %s: geen actie vereist..." client.naam
SQL: "UPDATE client " -SQL: " SET result = 'Geen actie vereist', " -SQL: " fever = %s " Koorts.getvalue
<SQL: " WHERE name = '%s' " client.naam
Initial_database_setup: delete_clients Query: DELETE FROM client End_Query
Initial_database_setup: insert_new_clients Query: INSERT INTO client (personid, name, age, temperature, sneezing, coughing, fever, result) VALUES (1, 'TC0', 33, Null, 1, 1, Null, Null), (2, 'TC1a', 10, 38.0, 0, 1, Null, Null), (3, 'TC1b', 9, 37.2, 1, 0, Null, Null), (4, 'TC2a', 10, 37.9, 0, 1, Null, Null), (5, 'TC2b', 9, 37.1, 1, 0, Null, Null), (6, 'TC3', 10, 38.0, 0, 0, Null, Null), (7, 'TC4', 9, 37.1, 0, 0, Null, Null) End_Query
Uitvoer van bovenstaand script levert op het scherm:
Resultaat TC0: doe een PCR-test! Resultaat TC1a: doe een PCR-test! Resultaat TC1b: doe een PCR-test! Resultaat TC2a: standaard quarantaine praktijk. Resultaat TC2b: standaard quarantaine praktijk. Resultaat TC3: standaard quarantaine praktijk. Resultaat TC4: geen actie vereist... Klaar met verwerken! Time elapsed: 0:00:01.139586
en in tabel client in de database:
1 TC0 33 Null 1 1 Null PCR test 2 TC1a 10 38 0 1 1 PCR test 3 TC1b 9 37.2 1 0 1 PCR test 4 TC2a 10 37.9 0 1 0 Standaard quarantaine praktijk 5 TC2b 9 37.1 1 0 0 Standaard quarantaine praktijk 6 TC3 10 38 0 0 1 Standaard quarantaine praktijk 7 TC4 9 37.1 0 0 0 Geen actie vereist
Korte toelichting op het voorbeeldprogramma voorzover nog niet eerder behandeld:
-
De queries die opgenomen zijn onder "Initial_database_setup:" worden als eerste - voordat het redeneermechanisme aan de slag gaat - uitgevoerd in de volgorde waarin ze zijn opgenomen in het script. En ze mogen overal in het script staan.
-
De toevoeging ".getvalue" aan de attribuutnaam Koorts heeft een heel eenvoudig reden: zonder deze toevoeging zou het redeneermechanisme alsnog een waarde voor dit attribuut proberen te achterhalen als deze nog onbekend is (None/Null); kortom, niet van belang was in de genomen beslissing, zoals bij het eerste proefgeval.
-
De toevoeging ".getvalue" kan ook gebruikt worden om doelattributen als conditie in een beslissingstabel op te nemen zonder dat er automatisch een gewoon attribuut van gemaakt wordt. Doelattributen kunnen nooit als conditie in een beslissingstabel voorkomen, maar dus wel door ".getvalue" aan de doelattribuutnaam toe te voegen.
-
Voordat bovenstaand script wordt uitgevoerd moet er uiteraard een database Coviddemo met daarin een tabel client worden gemaakt. In SQLite kan dat eenvoudig met de volgende query: CREATE TABLE client (personid integer, name text, age integer, temperature real (2,1), sneezing boolean, coughing boolean, fever boolean, result text); en in PostgreSQL gaat dat niet veel anders. En het mag ook gewoon in het Nederlands.
-
MET DATABASEVIEWS EN OPEENVOLGENDE HERHAALBARE DOELATTRIBUTEN WORDEN ALLE GEGEVENS EN ALLE ONDERLIGGENDE GEGEVENS SEQUENTIEEL OPGEHAALD UIT EEN DATABASE.
In plaats van één covidtest per client, zoals in het vorige programma, kunnen per client meerdere covidtests met bijbehorende beslissingen worden vastgelegd.
Binnen dezelfde database Coviddemo wordt nu een tweede clienttabel Client2 gemaakt, die alleen zal bestaan uit de velden: personid, name en age: CREATE TABLE client2 (personid integer, name text, age integer)
Daarnaast een tabel covidtest met de velden:
CREATE TABLE covidtest (personid integer,
testdate date DEFAULT ('0000-00-00'),
temperature real (2,1),
sneezing boolean,
coughing boolean,
fever boolean,
result text);
Door deze opsplitsing kunnen nu bij iedere client 0, 1 of meer covidtesten worden vastgelegd en beoordeeeld.
VOORBEELDPROGRAMMA 3:
SQLite_database: "Database/Coviddemo.sqlite3"
Table 0:
If: | 0| 1|
'Volgende Client?' | Y| N|
Then:
Actie1 is AlleClientenVerwerkt | | X|
Actie1 is ClientGeselecteerd | X| |
.......
Proposition: 'Volgende Client?' Obtain_instance_from_database_view: client2
Table 1:
If: | 0| 1| 2| 3| 4| 5|
'Volgende Test?' | Y| Y| Y| Y| Y| N|
Stap1_symptomen = 2 | Y| N| N| N| N| -|
Stap1_symptomen = 1 | -| Y| Y| N| N| -|
Koorts = 1 | -| Y| N| Y| N| -|
Then:
Actie2 is AlleTestenVerwerkt | | | | | | X|
Actie2 is PCR_test | X| X| | | | |
Actie2 is InQuarantaine | | | X| X| | |
Actie2 is AllesOK | | | | | X| |
.......
Proposition: 'Volgende Test?' Obtain_instance_from_database_view: test
Attribute: Stap1_symptomen
Equals: test.niezen + test.hoesten
Attribute: test.niezen Type: Integer Attribute: test.hoesten Type: Integer
Table 2: If: | 0| 1| 2| 3| client2.leeftijd >= 10 | Y| Y| N| N| test.temperatuur >= 38.0 | Y| N| -| -| test.temperatuur >= 37.2 | -| -| Y| N| Then: Koorts = 1 | X| | X| | Koorts = 0 | | X| | X|
.......
Database_view: client2
With_attributes: persoonid, naam, leeftijd
Query:
SELECT *
FROM client2
LIMIT 1 OFFSET %s
With_arguments: client2.auto_index
Database_view: test
With_attributes: persoonid, testdatum, temperatuur, niezen, hoesten
Query:
SELECT *
FROM covidtest
WHERE personid = %s
LIMIT 1 OFFSET %s
With_arguments: client2.persoonid, test.auto_index
GoalAttribute: Actie1 Repeat_until: AlleClientenVerwerkt
Case: AlleClientenVerwerkt Print: "Klaar met verwerken!"
Case: ClientGeselecteerd Print: "#REM# -"
GoalAttribute: Actie2 Repeat_until: AlleTestenVerwerkt
Case: AlleTestenVerwerkt Print: "#REM# -"
Case: PCR_test Print: "Client %s.%s op %s: doe een PCR-test!" client2.persoonid client2.naam test.testdatum
SQL: "UPDATE covidtest " -SQL: " SET result = 'PCR test', " -SQL: " fever = %s " Koorts.getvalue
-SQL: " WHERE personid = %s " client2.persoonid <SQL: " AND testdate = '%s' " test.testdatum
Case: InQuarantaine Print: "Client %s.%s op %s: standaard quarantaine praktijk." client2.persoonid client2.naam test.testdatum
SQL: "UPDATE covidtest " -SQL: " SET result = 'Standaard quarantaine praktijk', " -SQL: " fever = %s " Koorts.getvalue
-SQL: " WHERE personid = %s " client2.persoonid <SQL: " AND testdate = '%s' " test.testdatum
Case: AllesOK Print: "Client %s.%s op %s: geen actie vereist..." client2.persoonid client2.naam test.testdatum
SQL: "UPDATE covidtest " -SQL: " SET result = 'Geen actie vereist', " -SQL: " fever = %s " Koorts.getvalue
-SQL: " WHERE personid = %s " client2.persoonid <SQL: " AND testdate = '%s' " test.testdatum
Initial_database_setup: verwijder clienten Query: DELETE FROM client2 End_Query
Initial_database_setup: verwijder testen Query: DELETE FROM covidtest End_Query
Initial_database_setup: opvoeren clienten Query: INSERT INTO client2 (personid, name, age) VALUES (1, 'TC0', 33), (2, 'TC1a', 10), (3, 'TC1b', 9), (4, 'TC2a', 10), (5, 'TC2b', 9), (6, 'TC3', 10), (7, 'TC4', 9) End_Query
Initial_database_setup: opvoeren testen Query: INSERT INTO covidtest (personid, testdate, temperature, sneezing, coughing) VALUES (1, '2023-01-05', Null, 1, 1), (1, '2023-01-10', 38.0, 0, 1), (1, '2023-01-15', 37.2, 1, 0), (2, '2023-01-05', 38.0, 0, 1), (2, '2023-01-10', 37.2, 1, 0), (2, '2023-01-15', 37.0, 0, 0), (3, '2023-01-05', 37.2, 1, 0), (5, '2023-01-05', 37.1, 1, 0), (5, '2023-01-10', 37.0, 0, 0), (6, '2023-01-05', Null, 1, 1), (6, '2023-01-10', 38.0, 0, 1), (6, '2023-01-15', 37.2, 1, 0), (6, '2023-01-20', 37.9, 0, 0) End_Query
Uitvoer van bovenstaand script levert op het scherm:
Client 1.TC0 op 2023-01-05: doe een PCR-test! Client 1.TC0 op 2023-01-10: doe een PCR-test! Client 1.TC0 op 2023-01-15: standaard quarantaine praktijk. Client 2.TC1a op 2023-01-05: doe een PCR-test! Client 2.TC1a op 2023-01-10: standaard quarantaine praktijk. Client 2.TC1a op 2023-01-15: geen actie vereist... Client 3.TC1b op 2023-01-05: doe een PCR-test! Client 5.TC2b op 2023-01-05: standaard quarantaine praktijk. Client 5.TC2b op 2023-01-10: geen actie vereist... Client 6.TC3 op 2023-01-05: doe een PCR-test! Client 6.TC3 op 2023-01-10: doe een PCR-test! Client 6.TC3 op 2023-01-15: standaard quarantaine praktijk. Client 6.TC3 op 2023-01-20: geen actie vereist... Klaar met verwerken! Time elapsed: 0:00:01.070156
en in tabel covidtest in de database:
1 2023-01-05 Null 1 1 Null PCR test 1 2023-01-10 38 0 1 1 PCR test 1 2023-01-15 37.2 1 0 0 Standaard quarantaine praktijk 2 2023-01-05 38 0 1 1 PCR test 2 2023-01-10 37.2 1 0 0 Standaard quarantaine praktijk 2 2023-01-15 37 0 0 0 Geen actie vereist 3 2023-01-05 37.2 1 0 1 PCR test 5 2023-01-05 37.1 1 0 0 Standaard quarantaine praktijk 5 2023-01-10 37 0 0 0 Geen actie vereist 6 2023-01-05 Null 1 1 Null PCR test 6 2023-01-10 38 0 1 1 PCR test 6 2023-01-15 37.2 1 0 0 Standaard quarantaine praktijk 6 2023-01-20 37.9 0 0 0 Geen actie vereist
Korte toelichting op het voorbeeldprogramma voorzover nog niet eerder behandeld:
- Het programma wordt gekenmerkt door 2 opeenvolgende doelattributen, die beide herhaald worden:
GoalAttribute: Actie1 Repeat_until: AlleClientenVerwerkt
GoalAttribute: Actie2 Repeat_until: AlleTestenVerwerkt
Zolang voor doelattribuut Actie1 niet AlleClientenVerwerkt wordt bewezen, en dus wel het alternatief ClientGeselecteerd, worden waarden bewezen voor het volgende doelattribuut Actie2: Zolang voor doelattribuut Actie2 niet AlleTestenVerwerkt wordt bewezen, en dus wel één van de 3 alternatieven worden de bijbehorende Cases onder dit doelattribuut uitgevoerd en is een herhaling van doelattribuut Actie2 van toepassing: lees volgend meetmoment en is een herhaling van doelattribuut Actie1 van toepassing: lees volgende client.
Op basis van deze systematiek worden alle meetmomenten per client beoordeeld en verwerkt.