Articolo pubblicato sul n. 35 di MCmicrocomputer (Edizioni Technimedia Srl - Roma) nel novembre 1984

MCmicrocomputer


Data Base Management Systems:
Il modello semantico dei dati

di Andrea de Prisco

   Terza puntata sui Data Base. Parleremo questo mese del modello semantico dei dati: un particolare modo di descrivere la conoscenza, senza allontanarsi troppo dalla realta'. Come dicevamo nella prima puntata, un Utente e' un utente, una persona, e come tale va trattata. Avra' un nome, un recapito, un numero di telefono, un'eta'. Quando dovremo ritrovarne uno nella base di dati, bastera' chiedere al sistema: dammi l'utente di nome tizio o col telefono 345678. Nient'altro. Nulla del tipo: Utente A4Z23...Copertina del numero di MCmicrocomputer contenente l'articolo

Costruiamo una classe

   Anche se con un mese di ritardo rispetto alla tabella di marcia annunciata sul n. 33 (vi avevamo detto che avremmo affrontato l'argomento sul numero scorso) e' giunta l'ora di mostrare come si costruisce una classe dati in Basic-micatanto e come e' possibile operare su essa per individuare insiemi di oggetti o apportare modifiche. Per chi non avesse sottomano il n. 33, diamo nuovamente la definizione di due tipi di dato che useremo molto spesso nel seguito.

   L'ennupla e' un insieme finito di coppie (identificatore,valore) sul quale possibile tramite opportuni operatori selezionare i singoli campi. Un esempio di ennupla e':

   Persona = (Nome="Mario",Cognome="Alpini",Eta'=45)

   per selezionare i vari campi si usa l'operatore "of":

   PRINT Nome of Persona

   Restituira' "Mario"

   La sequenza e' un multinsieme finito di valori dello stesso tipo. E' assimilabile, come struttura, ad un array monodimensionale Basic. Le uniche differenze sono che non e' necessario alcun dimensionamento (puo' variare dinamicamente il numero dei suoi elementi) e che ogni elemento puo' non essere un tipo semplice (intero, stringa, reale), ma anche un'ennupla complicata quanto si vuole.

   Per selezionare un elemento di una sequenza si opera come sugli array: se Lista e' una sequenza, il quinto elemento sara' Lista(5). Per costruire una sequenza, si usano gli operatori "[" e "]".

   Lista = [4,3,6,18,27,3,41]

   se si vuol unire due sequenze, si usa l'operatore "+". Ad esempio:

   AltraLista = Lista + [45,7,12]

   NuovaLista = AltraLista + [11]

   si noti (secondo caso mostrato) che per aggiungere anche un solo elemento ad una sequenza, e' necessario racchiuderlo tra parentesi quadre. Nell'esempio visto, si e' aggiunto alla sequenza di partenza, una sequenza formata da un solo elemento: 11. Questo perche' l'operatore "+" agisce tra sequenze e non tra una sequenza e un elemento.

   Per sapere se un elemento e' contenuto in uno di questi nostri multinsiemi, e' disponibile l'operatore "isin":

   IF 7 isin AltraLista THEN <Qualcosa>

   (e' eseguito il <Qualcosa> se 7 e' contenuto in AltraLista; nel nostro caso si').

   Per visitare tutti gli elementi di una sequenza, in Basic-micatanto, e' disponibile una versione speciale del comando FOR. La sua sintassi e':

   FOR <variabile> in <sequenza>

   .

   .

   .

   .

   NEXT <variabile>

   e non fa altro che scorrere i vari elementi, assegnandoli uno per volta alla <variabile>. Ad esempio:

   10 FOR X in AltraLista

   20 Somma = Somma + X

   30 NEXT X

   calcola la somma degli elementi di AltraLista.

   Per conoscere il numero di elementi di una sequenza, si usa la funzione:

   Count(<sequenza>)

   molto utile anche perche' il sistema genera automaticamente un fallimento se si tenta di selezionare un elemento non contenuto nella sequenza, ossia con un indice piu' grande del numero di elementi.

   Un altro tipo di dato molto usato in linguaggi di programmazione un tantino piu' evoluti del Basic, e' il tipo Booleano. Una variabile booleana puo' assumere solo i valori logici true (vero) o false (falso). Leggere una variabile booleana e' valutare una espressione logica.

   Le classi sono "quasi" delle sequenze: l'accesso agli oggetti (gli elementi) di una classe avviene tramite opportuni operatori e non indicando tra parentesi, accanto al nome della classe, il numero d'ordine.

   Per usare una classe, e' necessario definire la sua struttura, come e' fatto ogni suo elemento, specificando il nome e il tipo di ogni attributo. Esempio: definiamo la classe Amici, nella quale inseriremo indirizzo e telefono di un po' di gente.

   class Amici <->

   (Nome:string,

    Cognome:string,

    Indirizzo:string,

    Citta':string,

    Telefono:int)

   Abbiamo cosi' definito una classe denominata Amici, in cui ogni elemento e' un'ennupla formata dai campi Nome, Cognome, Indirizzo, Citta' di tipo stringa e Telefono di tipo intero.

   Per inserire oggetti in classe, si usa il costruttore Make, seguito dal nome della classe e dall'elemento.

   Make Amici (Nome="Maria Rosaria", Cognome="D'Alessandro", Indirizzo="via Cisanello", Citta'="Pisa", Telefono=474747)

   inserira' il primo oggetto. Continuiamo:

   Make Amici (Nome="Virginia", Cognome="Ravenna", Indirizzo="via Vesalio", Citta'="Pisa", Telefono=484848)

   Make Amici (Nome="Paolo", Cognome="Zunino", Indirizzo="via Rossi", Citta'="Cosenza", Telefono=494949)

   Abbiamo inserito 3 elementi. Vediamo gli operatori per "ripescarli": Si distinguono 2 casi:

  • recuperare un elemento

  • recuperare un insieme di elementi

   esistono per la fattispecie 2 operatori: "get" e "all", il primo da non confondere col GET del basic standard. La sintassi e' comune:

   <comando> <classe> with <condizione>

   <comando> e' get o all, a seconda dei due casi.

   <classe> indica il nome della classe in cui effettuare la ricerca.

   <condizione> e' il parametro di selezione col quale, specificando opportuni valori di attributi, indichiamo a quali elementi siamo interessati.

   In 2 casi il sistema genera fallimento:

   - non esistono oggetti che soddisfano la condizione

   - si e' usato il get (volevamo un elemento) ed esistono piu' oggetti che soddisfano la condizione specificata. Il sistema non sa quale restituire ... e non e' giusto che restituisca il primo che gli capita. Facciamo qualche esempio:

   UnaPersona = get Amici with Nome="Maria Rosaria"

   dopo questa linea, UnaPersona e' l'ennupla inserita che ha campo Nome = "Maria Rosaria".

   Se avessimo scritto:

   UnaPersona = get Amici with Citta'="Pisa"

   si sarabbe generato fallimento, dato che si e' inseriti 2 oggetti "pisani".

   Il comando all, restituisce una sequenza:

   ListaPersone = all Amici with Citta'="Pisa"

   raggiungeremo i singoli elementi con ListaPersone(1) e ListaPersone(2). Inutile dire che all va bene anche se l'elemento che soddisfa la condizione e' unico. Senza dimenticare pero' che sara' restituita in ogni caso una sequenza, anche se formata da un solo elemento. Esempio:

   UnAltraPersona = all Amici with Nome="Paolo"

   e' una sequenza, il cui unico elemento e' UnAltraPersona(1).

   Per cancellare un elemento si usa il comando:

   remove <elemento>

   dove <elemento> e' un'ennupla contenuta nella classe.

   Concludendo, mostriamo come accedere ai vari campi:

   PRINT Telefono of UnaPersona

   restituira'

   474747

   PRINT Indirizzo of ListaPersone(2)

   restuituira'

   via Vesalio

   PRINT Citta' of UnAltraPersona(1)

    restituira'

   Cosenza

 

Il Modello Semantico dei Dati

   Cio' che ci interessa maggiormente e' la conoscenza: non vogliamo fare filosofia, questa e' informatica. Analizzeremo tre aspetti:

  • La Conoscenza Concreta.

  • La Conoscenza Astratta.

  • La Conoscenza Procedurale.

   dando per ognuno di questi i relativi meccanismi di astrazione atti a modellarli.

   La conoscenza concreta riguarda cio' che si vuole rappresentare, che appartiene cioe' al mondo osservato. Penseremo ai seguenti fatti:

  • Le Entita': le cose che ci interessano, ad esempio l'amico Paolo, il libro Knuth, l'utente Rossi.

  • Le Associazioni tra dati: le abbiamo viste sul numero scorso, cio' che stabilisce un legame logico tra entita'.

  • Le Proprieta': cio' che descrive le entita'. Una proprieta' dell'amico Paolo e' che abita a Cosenza, ad esempio.

   La Classificazione e' il meccanismo di astrazione mediante il quale entita' diverse vengono considerate omogenee, da inserire in una stessa classe. Nell'esempio visto in precedenza, entita' diverse (almeno si spera€£!) come Paolo e Virginia sono considerati appartenenti alla classe Amici (identica e' la loro struttura).

   L'Aggregazione e' il meccanismo di astrazione atto a definire la struttura degli oggetti di una classe e quindi le associazioni tra entita' diverse. La struttura di un elemento si descrive dichiarando un insieme finito di proprieta' (Nome, Cognome, Citta', Eta', Professione, ecc.).

   Una proprieta' e' detta Chiave, se un determinato suo valore e' presente al piu' in un elemento della classe. Per intenderci: la proprieta' matricola degli elementi appartenenti alla classe Studenti, puo' essere considerata una chiave, non potendo esistere due studenti con uguale matricola.

   Una proprieta' e' detta Costante se il suo valore e' invariante nel tempo, altrimenti e' detta Modificabile. Ad esempio, il nome di una persona e' costante, il suo recapito no: nella definizione di una classe, e' possibile fare questo tipo di distinzione.

   Una proprieta' e' detta Derivata se il suo valore puo' essere ricavato da altre proprieta' con determinate regole. Esempio:

   Eta' = derived AnnoDomini - AnnoDiNascita

   consentiteci di affermare sinceramente che ormai e' opinione diffusa che l'eta' di un individuo si "ricava" dalla sottrazione tra l'anno in cui ci poniamo il problema e l'anno in cui e' nato.

   Una proprieta' e' detta associazione se ha per valore elementi di altre classi. Descrive cioe' correlazioni tra entita'. Una delle salienti caratteristiche del modello semantico dei dati e' di modellare le associazioni tra dati come se fossero caratteristiche delle entita'. Facciamo un esempio di sapore vagamente universitario. Si vuole descrivere l'associazione mostrata in figura 1: due classi: Studenti e Esami, una l'associazione tra le classi (con diretta e inversa multipla):

  •    Ogni studente ha superato un certo numero di esami.

  •    Ogni esame e' stato superato da un certo insieme di studenti.

   Basta. Di fatto non e' necessario aggiungere altro. Definiremo le due classi cosi':

   class Studenti <->

   (NomeCognome:string,

    Matricola:int,

    Recapito:string,

    HaSuperato:seq Esami)

 

   class Esami <->

   (NomeEsame:string,

    Docente:string,

    CodiceEsame:int,

    SuperatoDa:seq Studenti)

 

   Con i meccanismi visti finora, e' anche possibile automatizzare l'associazioni tra dati. Sfrutteremo la possibilita' di definire proprieta' derivate. Facciamo un esempio, sempre a carattere universitario. Potremmo definire il campo HaSuperato degli Studenti, invece che come seq Esami visto sopra, con l'espressione:

   HaSuperato = all Esami with this isin SuperatoDa

  a parole vuol dire proprio cio' che vogliamo descrivere: HaSuperato sono tutti gli esami della classe Esami che hanno lo studente in questione ("this") tra gli studenti elencati nella proprieta' SuperatoDa. In questo modo, quando uno studente supera un nuovo esame, e' sufficiente aggiornare solo la classe esami (l'esame Blablabla e' stato superato anche da Caio) perche'  sia aggiornata anche la classe Studenti.

   Il meccanismo delle sottoclassi

   La Generalizzazione e' il meccanismo di astrazione della conoscenza concreta mediante il quale e' possibile organizzare insiemi di classi in una gerarchia definita da una relazione di ordinamento parziale. E' il discorso delle sottoclassi, lievemente anticipato due numeri fa.

   Col meccanismo delle sottoclassi, si migliora notevolmente la visione utente di una base di dati, senza appesantire l'organizzazione interna: le sottoclassi sono solo un modo diverso di vedere le stesse cose. Per intenderci: se abbiamo la classe Italiani e la sottoclasse Toscani (e perche' no, la sottosottoclasse Livornesi), il fatto che un abitante Livornese si ritrovi in tre classi in gerarchia, non vuol dire che e' rappresentato tre volte nella base di dati. L'abitante e' sempre lo stesso. Prova ne e' il fatto che cancellandolo dalla classe Italiani, sparira' definitivamente anche dai Toscani e dai Livornesi.

   Distinguiamo tre specie di sottoclasse:

  • Sottoclasse Sottoinsieme: un esempio e' la classe Studenti, vista come sottoinsieme di una classe piu' ampia denominata Persone. E' ovvio che uno studente e' una Persona, ma non e' sempre vero il viceversa. Cio' significa che non potremo avere un elemento in Studenti senza averlo anche in Persone. Avere nel senso logico: ripetiamo, l'oggetto rappresentato e' lo stesso, tutt'al piu' aumentato di qualche campo quando e' visto come Studente. Cio' perche', nella definizione di sottoclasse, e' possibile aggiungere campi alle ennuple della classe da cui si parte. Ad esempio, uno studente e' una persona con in piu' un numero di matricola. Se cercheremo Caio tra le Persone, conosceremo il suo indirizzo, il suo telefono ed altro. Se cercheremo Caio tra gli studenti, otterremo oltre alle proprieta'delle Persone, anche la sua matricola.

  • Sottoclasse Partizione: si costruiscono a partire da una classe eseguendo una partizione (immaginate di tagliare una torta...). Per fare un esempio, potremmo partizionare la classe Persone in maschi e femmine. In generale, l'unione delle delle sottoclassi della stessa partizione, e' un sottoinsieme della classe di partenza.

  • Sottoclasse Restrizione: contengono tutti e soli gli elementi che soddisfano una determinata condizione su uno o piu' attibuti costanti.

Esempio:

   Francesi <-> restriction of Europei class with Nazione = "France"

   costruisce automaticamente la sottoclasse Francesi, aggiornadola ad ogni inserimento in Europei di un elemento con campo Nazione = "France".

   Conoscenza astratta e conoscenza procedurale

   Per modellare la conoscenza astratta si impongono determinati vincoli di integrita'. I vincoli di integrita' servono per limitare l'evolvere della conoscenza concreta, descrivendo fatti generali non direttamente riconducibili ai vincoli impliciti del modello semantico dei dati. Un esempio di vincolo e' che le matricole degli studenti di una universita' sono tutte diverse, che uno studente non puo' superare due volte lo stesso esame, che abbia almeno 17 anni. Insomma, i vincoli dovrebbero impedire o almeno limitare la possibilita' di raccontare frottole alla base di dati. Il tutto per migliorare le prestazioni, sfruttando al massimo questa benedetta informazione di cui si dispone.

   Vincoli piu' interessanti sono quelli che riguardano insiemi diversi. A livello di biblioteca, ad esempio, far controllare al sistema che se un Utente ha in prestito un certo libro, nella classe materiali prestati nel campo PrestatoA, del libro di cui sopra, ci sia appunto l'utente da cui siamo partiti. O piu' semplicemente: se Ermenegildo e' sposato con Ermengalda, deve essere anche che Ermengalda e' sposata con Ermenegildo, altrimenti "qualcosa" non torna.

   I vincoli di integrita' si definiscono al momento di creare una classe, di seguito alla descrizione dell'ennupla. Ad esempio, imponiamo la restizione che l'eta' di una persona deve essere maggiore di zero:

   class Persone <->

   (NomeCognome:string,

    Recapito:string,

    Telefono:int,

    Eta':int)

   assert Eta' > 0

   se si costruira' un elemento Persona con eta' = -12 il sistema generera' fallimento, non consentendo di sporcare la base di dati con dati (almeno in questo senso) inconsistenti.

   La conoscenza procedurale si modella col meccanismo delle funzioni. Nel Basic-micatanto con porzioni di programma etichettate in cima con un nome simbolico.

   Si sta parlando delle linee di programma che si stendono dopo aver definito una base di dati, per l'automazione di determinate procedure. Nell'esempio di organizzazione di una biblioteca mostrato in queste pagine si e' "procedurizzato" le funzioni di prestito materiale, riconsegna, inserzione di un utente, ed altro.

   Scrivendo le opportune procedure si semplifica notevolmente la gestione della base di dati. Per esempio, se un utente vuole in prestito un libro, l'addetto ai prestiti basta che digiti sulla tastiera "Presta Libro" e risponda alle domande poste dal sistema (autore e titolo del libro, nome e cognome dell'utente). Se qualcosa non quadra, saranno segnalati automaticamente messaggi sul video, altrimenti sara' concesso il prestito, aggiornando opportunemente l'informazione mantenuta dalla Base di Dati. Tutto qui.

La nostra amata Biblioteca

   Vedremo ora come e' possibile organizzare in Basic-micatanto una base di dati per biblioteca, secondo il modello semantico dei dati. Sul numero scorso e' stata data la specifica comportamentale: quali saranno le funzioni svolte dal sistema, a istallazione completata. Per ragioni di spazio non commenteremo tutto il listato, ma ci soffermeremo principalmente sui punti piu' interessanti.

   Immaginiamo che il sistema abbia incorporato un calendario interno che si aggiorna automaticamente ogni mattina. L'ennupla Oggi, contiene giorno, mese e anno corrente. Per intenderci, per sapere che giorno e' oggi e' sufficiente digitare:

   PRINT Giorno of Oggi

   analogamente per il mese e l'anno.

   Sempre facente parte del sistema, la funzione:

   GiorniTrascorsi(Giorno,Mese,Anno)

   che restituisce il numero di giorni che intercorrono tra la data di Oggi e la data passata come parametro.

   Il programma Biblioteca e' diviso in due parti: la parte dichiarativa (linee 10-40) dove sono definite le varie classi usate, e la parte procedurale, dove sono specificate le procedure usabili.

   Per chiamare una procedura e' sufficiente digitare il suo nome

   Le prime quattro linee contengono la definizione delle quattro classe adoperate: Materiali, Prenotazioni, Utenti e MaterialiPrestati. Fra parentesi la descrizione delle ennuple contenute nelle classi. A partire dalla linea 50 fino alla linea 100, e' listata la prima delle procedure: "Inserisci Utente". Si invoca quando un Utente accede per la prima volta alla biblioteca. Le linee 60,70 e 80 caricano tramite comunissimi INPUT, Nome e Cognome, Recapito e Documento di identita' nelle variabili A$, B$ e C$. La linea 90 inserisce l'oggetto (...pardon, l'Utente...) in classe. Si noti il campo Ritardatario posto a false e i due campi sequenza  posti a "[]", ossia a "sequenza vuota". Questo perche' un utente, appena accede alla bibioteca, certamente non e' ritardatario (ancora ha la coscienza pulita) e non ha ne' prenotazioni ne' libri in prestito.

   Diamo ora uno sguardo alla procedura "Presta Libro" (linee 450 e segg.).

   Dopo aver chiesto autore e titolo del libro che si chiede in prestito e nome e cognome dell'utente richiedente, il sistema controlla che il testo non sia gia' in prestito a qualcuno. Cio' avviene con le linee 480 e 490. Si cerca il testo tra i MaterialiPrestati e solo se non c'e' si continua la procedura, altrimenti si stampa il messaggio "Libro non disponibile". Il "solo se non c'e'" si implementa col costrutto IF fail THEN, (se c'e' un errore allora...) che funziona in virtu' del fatto che si genera fallimento se si cerca un oggetto in una classe e non lo si trova.

   Le linee 510-520 assegnano alle variabili Libro e Utente il testo desiderato e l'utente gia' memorizzato. Cio' per controllare (linee 530-560) che il testo sia prestabile, che l'utente non sia ritardatario o che non abbia gia' due libri in prestito. Di seguito (linee 570-610) con un trucchetto simile a quello usato per sapere se il materiale era gia in prestito a qualch'altro utente, si controlla che il testo non sia citato in una prenotazione e che tale prenotazione (se esiste) non sia scaduta, non sia passato piu' di un giorno.

   Le linee 620-660 modificano la base di dati secondo il nuovo stato: il libro e' tra i materiali prestati, l'utente ha in prestito il libro di cui sopra, il materiale concesso in prestito e' stato prestato nuovamente a qualcuno. Per la modifica, si inseriscono i nuovi dati aggiornati e si canceallano i vecchi, non piu' significativi.


Impaginato originale...


  Clicca per ingrandire...
Clicca per ingrandire... Clicca per ingrandire...
Clicca per ingrandire...  

Articolo pubblicato su www.digiTANTO.it - per ulteriori informazioni clicca qui