A. Veneziani - Soluzione (parte di Informatica) della simulazione

Pagina creata da Gabriele Di Mauro
 
CONTINUA A LEGGERE
A. Veneziani – Soluzione (parte di Informatica) della simulazione
              di seconda prova Aprile 2019
Analisi del problema
La traccia si suddivide in problematiche relative a sistemi ed altre relative ad informatica, coinvolgendo
quest’anno tutt’e due le materie.
Il testo:
 http://www.veneziani.altervista.org/ITIS_Luino_2018-
2019/Informatica/5A/dispense/DB/simulazione_2019_apr/Testo_Simulazione%20di%20seconda%20prova_2_Aprile_2019.pdf
 prospetta problematiche relative alla gestione di alcuni aspetti di una compagnia ferroviaria passeggeri,
presumibilmente di linee ad alta velocità.
I punti chiave messi in evidenza dal testo relativi alla materia di Informatica (di alcuni dei quali comunque
non è richiesto lo sviluppo) sono:
    a) Registrazione di un utente sul sistema Web della compagnia EasyTrain
    b) Possibilità di effettuare prenotazioni, quindi selezione del giorno del viaggio, della tratta, della
         carrozza e del posto (semprechè liberi).
    c) Effettuare il pagamento relativo al punto (b)
    d) Permettere ai viaggiatori di scegliere in un catalogo di film, riportandone i dati salienti
    e) Registrare quali di essi sono stati visti da chi e in quale occasione
In realtà in sostanza la traccia richiede esplicitamente di esaudire solo le richieste al punto (d) ed (e) della
precedente lista. Per completezza il DB proposto come soluzione tiene conto anche degli aspetti relativi alla
registrazione e al relativo accesso alla piattaforma di acquisto viaggi, e registra tutte le prenotazioni
effettuate dei viaggi stessi.

Punto 2 della traccia

Costruzione del diagramma E/R del DB
Per prima cosa consideriamo che il testo parla, come ovvio, di un accesso al sito di prenotazione, che
comporta una identificazione dell’utente. Ciò ovviamente perchè sia il biglietto che la stessa operazione di
prenotazione è personale. Questo è direttamente in relazione con le operazioni di registrazione e successivo
accesso con identificazione.
Prevederemo quindi una entità Utenti che raggruppi i dati delle persone che si registrano al sito di EasyTrain,
con alcune informazioni utili, quali la loro mail ed ovviamente login e password.
Tali utenti secondo quanto detto dal testo effettueranno delle prenotazioni relative a dei viaggi.
Prevederemo quindi una entità Viaggi, che raggruppi le varie tratte tra le quali un utente possa scegliere ed
effettuare quindi la prenotazione voluta. Ad ogni tratta sarà associato un prezzo specifico, eventualmente
modificabile a seconda dei periodi e del rapporto domanda / offerta di posti.
Sarà prevista anche una entità che registri quali utenti hanno effettuato quale viaggio (tratta), che
chiameremo Prenotazioni. La registrazione del dato tratta / utente, assieme ad altri necessari, quali la data
della prenotazione, il posto (carrozza + n° posto) prenotato sul treno ecc. prevede già il pagamento anticipato
del costo del biglietto.
In realtà quindi si suppone che Prenotazioni sia una entità che registri le prenotazioni degli Utenti e come
tale sia in relazione 1 a n con essa (n lato Prenotazioni), in quanto un utente potrà effettuare più prenotazioni,
ed una prenotazione riguarda ed è effettuata da un solo utente.
Nello stesso modo Prenotazioni è correlata logicamente e quindi in associazione con Viaggi, in quanto una
prenotazione riguarda inevitabilmente un viaggio (tratta). Mentre un viaggio può essere oggetto di molte
prenotazioni. Quindi esiste una associazione tra Prenotazioni e Viaggi, con molteplicità 1 -> N da Viaggi verso
Prenotazioni.
A questa parte del diagramma, riguardante l’accesso e le prenotazioni, potremo combinare la parte relativa
alla fruizione dei films durante il viaggio, oggetto di buona parte delle richieste della traccia.
I films saranno catalogati grazie ad una apposita entità Films.             Prevederemo un apposito attributo
(In_Catalogo) per indicare se il film fa parte attualmente del catalogo corrente dei film proposti oppure no.

                                                    Pagina 1
In caso negativo (valore 0), esso comunque indica che il film è stato in un qualche altro periodo in catalogo.
La presenza di questo flag permette di evitare di dover cancellare dal DB tutti i film non in catalogo,
permettendo quindi di mantenere i dati raccolti (n° visioni, ecc.) riguardo ad essi.
Ovviamente prevederemo per questa entità tutti gli attributi indicati dalla traccia. La traccia mette in
evidenza in particolare due dati la cui gestione pone delle particolarità.
Films è in associazione con Prenotazioni, in quanto per visionare effettivamente qualcuno dei films, bisogna
aver acquistato un biglietto e quindi aver effettuato una prenotazione, oltre ad essere effettivamente in
viaggio. In questo caso si può dire che ad ogni prenotazione (con presenza), corrisponde la possibile visione
di più films, e viceversa ad ogni film considerato corrisponde la visione da parte di più persone che hanno
effettuato più prenotazioni. Si tratta quindi di una associazione N a M tra le due entità indicate. In linea di
massima l’associazione da prenotazioni a films è parziale, perché non è detto che solo per aver prenotato e
viaggiato l’utente veda per forza dei films, mentre l’associazione considerata dall’altro verso si può
considerare totale, ipotizzando che nessun film abbia totalizzato in assoluto 0 visualizzazioni.
Dovendo memorizzare i vari attori che hanno lavorato in un film è ovvio che non è opportuno semplicemente
prevedere n attributi dello stesso tipo. Anche qui l’associazione Films  Attori, è totale in entrambi i sensi,
in quanto un film deve pur avere qualche attore che vi recita, e si può ipotizzare che un attore sia tale perche’
ha partecipato ad almeno un film.
Si conformerà quindi una entità ulteriore Attori in associazione con Films con molteplicità N a M con essa.
Questo in quanto: in un film potremo avere più attori che lo interpretano, ma viceversa anche un attore potrà
senza dubbio interpretare più film.
Tutto questo porta a concludere quanto già detto sopra riguardo all’associazione tra queste due entità e alla
sua molteplicità.
Per quanto riguarda l’attributo genere del film, può essere vantaggioso scorporare tale attributo facendolo
divenire una entità autonoma, di modo da catalogare i vari generi in essa e fare quindi riferimento ad ognuno
di essi quando necessario, dall’entità Films. In sintesi, come al solito, una operazione di questo tipo porta a
una relazione 1 a N, in questo specifico caso tra l’entità Films (N) e l’entità Generi (1), in quanto dopo questa
modifica del diagramma, ad un film corrisponde un solo genere, mentre ad un genere possono corrispondere
più films. Anche questa associazione può ragionevolmente essere pensata come totale in tutte e due i sensi,
in quanto ad un genere apparterrà almeno qualche film (anche per accontentare nel modo più ampio la
clientela), e nel contempo ad un film non può non appartenere ad un genere.

Entità e relativi attibuti
Possiamo quindi alla fine di questa analisi fare un riepilogo delle entità e degli attributi considerati o di quello
che vanno comunque aggiunti allo schema descritto prima:

        Entità Utenti
        CF               codice fiscale dell’utente – chiave primaria
        Nome             nome dell’utente
        Cognome          cognome dell’utente
        Mail             mail dell’utente
        Login            username dell’utente (potrebbe essere generato automaticamente)
        Passwd           password di accesso da abbinare al Login

        Entità Prenotazioni
        PU             codice unico prenotazione – chiave primaria
        Carrozza       numero della carrozza del treno
        Posto          numero del posto nella carrozza indicata
        DataPreno      data in cui avviene la prenotazione
        DataViaggio    data di effettivo svolgimento del viaggio
        PrezzoBigl     prezzo a cui è stato pagato il biglietto
        Presente       indicatore booleano che indica se il passeggero era presente

                                                    Pagina 2
Entità Viaggi
       Cod_Viaggio     codice univoco relativo al viaggio – chiave primaria
       LuogoPart       Luogo di partenza del viaggio
       LuogoArr        Luogo di arrivo del viaggio
       PrezzoAtt       prezzo a cui attualmente viene venduta la tratta

       Entità Films
       Cod_Film        codice univoco relativo al singolo film – chiave primaria
       Titolo          titolo del film
       Durata          durata del film
       Anno            anno in cui è stato prodotto il film
       Trama           testo descrittivo della trama del film
       In_Catalogo     indica se il film è attualmente in catalogo (cioè tra quelli visionabili)

       Entità Generi
       Cod_Genere codice univoco relativo ad un genere – chiave primaria
       Genere        descrizione del genere

       Entità Attori
       Cod_Attore    codice univoco relativo ad un attore – chiave primaria
       Nome          nome dell’attore
       Cognome       cognome dell’attore

Relazioni - Modello logico
Le entità ed il diagramma E/R ipotizzate sopra portano al seguente modello logico schematizzato dalle
seguenti relazioni:

       Utenti(CF, Nome, Cognome, Mail, Login, Passwd)
       Viaggi(Cod_Viaggio, LuogoPart, LuogoArr, PrezzoAtt)
       Prenotazioni(PU, Carrozza, Posto, DataPreno, DataViaggio, PrezzoBigl, Presente, CF, Cod_Viaggio)
       Films(Cod_Film, Titolo, Durata, Anno, Trama, In_Catalogo, Cod_Genere)
       Visioni(PU, Cod_Film)
       Attori(Cod_Attore, Nome, Cognome)
       Attori_Films(Cod_Films, Cod_Attore)
       Generi(Cod_Genere, Genere)

Forma tabellare delle relazioni

 Relazione             Utenti
 Nome campo            Tipo                  Ampiezza               NULL                    Chiavi
 CF                    CHAR(16)              16                     No                      Primaria
 Nome                  VARCHAR(40)           40                     No
 Cognome               VARCHAR(40)           40                     No
 Mail                  VARCHAR(70)           70                     No
 Login                 VARCHAR(20)           20                     No
 Passwd                VARCHAR(20)           20                     No

 Relazione             Viaggi
 Nome campo            Tipo                  Ampiezza               NULL                    Chiavi
 Cod_Viaggio           INT UNSIGNED                                 No                      Primaria
                                                  Pagina 3
LuogoPart     VARCHAR(30)    30               No
LuogoArr      VARCHAR(30)    30               No
PrezzoAtt     DECIMAL(5,2)   5                No

Relazione     Prenotazioni
Nome campo    Tipo           Ampiezza         NULL   Chiavi
Cod_Film      INT UNSIGNED                    No     Primaria
Carrozza      TINYINT                         No
Posto         TINYINT                         No
DataPreno     DATE                            No
DataViaggio   DATE                            No
PrezzoBigl    DECIMAL(5,2)   5                No
Presente      BIT(1)                          Si
CF            CHARF(16)      16               No     Esterna
Cod_Viaggio   INT UNSIGNED                    No     Esterna

Relazione     Films
Nome campo    Tipo           Ampiezza         NULL   Chiavi
PU            INT UNSIGNED                    No     Primaria
Titolo        VARCHAR(100)   100              No
Durata        TIME                            No
Anno          YEAR                            No
Trama         TEXT                            No
In_Catalogo   BIT            1                No
Cod_Genere    INT UNSIGNED                    No     Esterna

Relazione     Visioni
Nome campo    Tipo           Ampiezza         NULL   Chiavi
PU            INT UNSIGNED                    No
                                                     Primaria
Cod_Film      INT UNSIGNED                    No

Relazione     Attori
Nome campo    Tipo           Ampiezza         NULL   Chiavi
Cod_Attore    INT UNSIGNED                    No     Primaria
Nome          VARCHAR(40)    40               No
Cognome       VARCHAR(40)    40               No

Relazione     Attori_Films
Nome campo    Tipo           Ampiezza         NULL   Chiavi
Cod_Attore    INT UNSIGNED                    No
                                                     Primaria
Cod_Film      INT UNSIGNED                    No

Relazione     Generi
Nome campo    Tipo           Ampiezza         NULL   Chiavi
Cod_Genere    INT UNSIGNED                    No     Primaria
Genere        VARCHAR(50)    50               No

                                   Pagina 4
Script SQL di generazione del DB
Lo script che permette di generare il DB con la struttura precedentemente descritta, completo di vincoli di
integrità referenziale, risulta. L’ordine della creazione delle tabelle è vincolato, per alcune di esse, dalla
presenza dei vincoli di integrità referenziale:

        CREATE TABLE   Attori (
        Cod_Attore     INT UNSIGNED PRIMARY KEY,
        Nome           VARCHAR(40) NOT NULL,
        Cognome        VARCHAR(40) NOT NULL );

        CREATE TABLE Generi (
        Cod_Genere    INT UNSIGNED PRIMARY KEY,
        Genere       VARCHAR(50) NOT NULL );

        CREATE TABLE   Utenti (
        CF             CHAR(16) PRIMARY KEY,
        Nome           VARCHAR(40) NOT NULL,
        Cognome        VARCHAR(40) NOT NULL,
        Email          VARCHAR(70) NOT NULL,
        CartaCredito   CHAR(16) NOT NULL,
        TipoCarta      ENUM('Visa', 'MasterCard', 'American Express', 'Postepay') NOT NULL,
        Login          VARCHAR(20) NOT NULL,
        Passwd         VARCHAR(20) NOT NULL );

        CREATE TABLE   Viaggi (
        Cod_Viaggio    INT UNSIGNED PRIMARY KEY,
        LuogoPart      VARCHAR(30) NOT NULL,
        LuogoArr       VARCHAR(30) NOT NULL,
        PrezzoAtt      DECIMAL(5,2) );

        CREATE TABLE Films (
        Cod_Film     INT UNSIGNED PRIMARY KEY,
        Titolo       VARCHAR(100) NOT NULL,
        Durata       TIME NOT NULL,
        Anno         YEAR NOT NULL,
        Trama        TEXT NOT NULL,
        In_Catalogo  BIT NOT NULL,
        Cod_Genere INT UNSIGNED NOT NULL,
        FOREIGN KEY(Cod_Genere) REFERENCES Generi(Cod_Genere) );

        CREATE TABLE Attori_Films (
        Cod_Attore    INT UNSIGNED NOT NULL,
        Cod_Film      INT UNSIGNED NOT NULL,
        PRIMARY KEY(Cod_Attore, Cod_Film),
        FOREIGN KEY(Cod_Attore) REFERENCES Attori(Cod_Attore),
        FOREIGN KEY(Cod_Film) REFERENCES Films(Cod_Film) );

        CREATE TABLE Prenotazioni (
        PU            INT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
        Carrozza      TINYINT NOT NULL,

                                                  Pagina 5
Posto         TINYINT NOT NULL,
      DataPreno     DATE NOT NULL,
      DataViaggio   DATE NOT NULL,
      PrezzoBigl    DECIMAL(5,2) NOT NULL,
      Presente      BIT,
      CF            CHAR(16) NOT NULL,
      Cod_Viaggio I NT UNSIGNED NOT NULL,
      FOREIGN KEY(CF) REFERENCES Utenti(CF),
      FOREIGN KEY(Cod_Viaggio) REFERENCES Viaggi(Cod_Viaggio) );

      CREATE TABLE Visioni (
      PU           INT UNSIGNED NOT NULL,
      Cod_Film     INT UNSIGNED NOT NULL,
      PRIMARY KEY(PU, Cod_Film),
      FOREIGN KEY(PU) REFERENCES Prenotazioni(PU),
      FOREIGN KEY(Cod_Film) REFERENCES Films(Cod_Film) );

Diagramma UML del DB

                                           Pagina 6
Punto 3 della traccia – svolgimento query
Svolgiamo qui le query richieste in questo punto sul DB appena creato.

Query a) Elenco dei film in catalogo ordinati per genere ed anno di produzione

        #
        # elenco dei films in catalogo ordinati per genere e anno di produzione
        #
        SELECT Titolo, genere, anno
        FROM films, generi
        WHERE films.Cod_Genere = generi.Cod_Genere AND
        films.In_Catalogo = 1
        ORDER BY genere, anno;

si tratta di effettuare un join tra le tabelle films e generi (per poter accedere anche alle denominazioni dei
generi, ovviamente in relazione ad ogni film considerato). Su tale join si effettua un ordinamento su un
doppio criterio (genere ed anno). Dall’elenco sono esclusi, come richiesto dal testo i film ormai non più in
catalogo, ossia quelli che non sono nella lista dei visionabili (catalogo corrente).

Query b) Elenco in ordine alfabetico degli utenti che non hanno mai visualizzato alcun film

Per risolvere il problema posto si può iniziare a considerare una query che estragga gli utenti che hanno
visualizzato films (in particolare il dato che gli identifica univocamente e senza ambiguità, ossia in questo caso
la loro chiave primaria codice fiscale).

        # codice fiscale di utenti che hanno visualizzato films
        SELECT utenti.CF
        FROM utenti, prenotazioni, visioni, films
        WHERE
        utenti.CF = prenotazioni.CF AND
        prenotazioni.PU = visioni.PU AND
        visioni.Cod_Film = films.Cod_Film;

Tale query produce quindi un insieme di codici fiscali, probabilmente sottinsieme di tutti i codici fiscali
presenti in utenti.
Per trovare gli utenti che non hanno visualizzato alcun film, basta poi effettuare una query su utenti che
abbia come condizione quella di avere la chiave primaria non presente come risultato della query indicata
sopra (qui facente la funzione di una subquery)

        #
        # elenco in ordine alfabetico degli utenti che non hanno mai visualizzato alcun film
        #
        SELECT Cognome, Nome
        FROM utenti
        WHERE CF NOT IN
        (SELECT utenti.CF
        FROM utenti, prenotazioni, visioni, films
        WHERE
        utenti.CF = prenotazioni.CF AND
        prenotazioni.PU = visioni.PU AND
        visioni.Cod_Film = films.Cod_Film)

                                                   Pagina 7
ORDER BY Cognome;

Infine si deve aggiungere un ordinamento per cognome al tutto, in quanto richiesto dal testo del punto (b)
Si tratta in definitiva di una operazione di sottrazione sullo stesso insieme di un suo sottinsieme.
L’insieme di tutti gli utenti – l’insieme degli utenti che hanno visto film = insieme degli utenti che non hanno
visto alcun film.

Query c) Dato un intervallo di tempo tra due date, produrre il titolo che ha registrato il maggior numero di
visualizzazioni.

Considero e creo la view che calcola quante volte è stato visto ognuno dei film, nel periodo prefissato

         #
         # Appoggiandosi ad una View
         #

         CREATE OR REPLACE VIEW ContaVisioni AS
         SELECT Titolo, COUNT(*) AS 'NumeroVisioni'
         FROM prenotazioni, visioni, films
         WHERE
         prenotazioni.PU = visioni.PU AND
         visioni.Cod_Film = films.Cod_Film AND
         DataViaggio > '2019-03-01' AND DataViaggio < '2019-03-15'
         GROUP BY films.Cod_Film;

La subquery1:

         (SELECT MAX(NumeroVisioni)
         FROM ContaVisioni);

utilizzante la view appena definita, calcola il numero massimo di tali visualizzazioni (per uno o piu’ film, quelli
più visti).
Una view in sostanza si comporta come una nuova tabella in realtà generata però da operazioni di selezione
su quelle già preesistenti nel DB.
Deduco infine, con la query sottostante, quale è il film più visto (in quanto dalla tabella che elenca il numero
di visualizzazioni per ogni film, scelgo solo quelli con il numero di visualizzazioni che risulta il massimo,
ovviamente sempre nel periodo di interesse):

         #
         # e quindi la query
         # "dato un intervallo di tempo produrre il titolo che ha registrato
         # il maggior numero di visualizzazioni"
         # diviene:

         SELECT Titolo, NumeroVisioni
         FROM ContaVisioni
         WHERE NumeroVisioni =
         (SELECT MAX(NumeroVisioni)
         FROM ContaVisioni);

1
  Una subquery è una query, inserita a sua volta in una query di livello superiore, atta a permettere a quest’ultima di ottenere i
risultati voluti.
                                                             Pagina 8
ovviamente con l’uso della view considerata

Altrimenti potrei procedere in questo modo:
Inizio a ricavare il numero di visioni di un certo film in un certo periodo di tempo (analogamente alla query
fatta sopra, inserita nella view).
Per realizzare questa query ho bisogno di Films, perché considero i film e ho bisogno del loro titolo, della
tabella Visioni, perché indica le visioni dei film stessi ed infine della tabella Prenotazioni perché in tale entità
c’è la data effettiva di esecuzione del viaggio, nella quale, eventualmente, saranno visionati i film:

        # numero di visioni per ogni film in un certo periodo
        SELECT Titolo, COUNT(*) NumeroVisioni
        FROM prenotazioni, visioni, films
        WHERE
        prenotazioni.PU = visioni.PU AND
        visioni.Cod_Film = films.Cod_Film AND
        prenotazioni.DataViaggio > '2019-03-01' AND
        prenotazioni.DataViaggio < '2019-03-15'
        GROUP BY films.Cod_Film;

per effettuare questo conteggio per ogni film, devo raggruppare per film.
A questo punto si pone comunque il problema di trovare il massimo nella tabella appena considerata.
E’ possibile, a tal proposito, in SQL, utilizzare i risultati di una query come se fossero a loro volta una tabella,
anche in modo diretto (non solo generando una view come prima).
Utilizzando quindi la query precedente come una tabella, ossia inserendo la stessa come subquery nella parte
FROM di un comando SELECT di livello più alto che utilizzi questa query appunto per individuare il valore
massimo di visualizzazioni, dato il report di numero di visualizzazioni che la stessa contiene:

        # massimo numero (assoluto) di visualizzazioni di un film
        SELECT MAX(NumeroVisioni)
        FROM
        (SELECT COUNT(*) NumeroVisioni
        FROM prenotazioni, visioni, films
        WHERE
        prenotazioni.PU = visioni.PU AND
        visioni.Cod_Film = films.Cod_Film AND
        prenotazioni.DataViaggio > '2019-03-01' AND
        prenotazioni.DataViaggio < '2019-03-15'
        GROUP BY films.Cod_Film) AS T1;

Si noti che alla subquery si è dovuto per forza dare un alias (ossia un nome). In tal caso si parla di alias di
tabella, ossia è stato necessario dare un nome alla tabella appena utilizzata (che non può rimanere anonima).
Determinato il massimo di visualizzazioni in questo modo è possibile utilizzare una variante della clausola
GROUP BY per determinare quali conteggi su ogni film siano pari al valore massimo:
In pratica posso immaginare di riscrivere la query che effettua i conteggi delle visualizzazioni per ognuno dei
film:

        # titolo di film che ha registrato il massimo numero di visualizzazioni
        # in un certo intervallo di tempo
        SELECT Titolo, COUNT(*)
        FROM prenotazioni, visioni, films
        WHERE
        prenotazioni.PU = visioni.PU AND

                                                    Pagina 9
visioni.Cod_Film = films.Cod_Film AND
        prenotazioni.DataViaggio > '2019-03-01' AND
        prenotazioni.DataViaggio < '2019-03-15'
        GROUP BY films.Cod_Film
        HAVING COUNT(*) =
        (SELECT MAX(NumeroVisioni)
        FROM
        (SELECT COUNT(*) NumeroVisioni
        FROM prenotazioni, visioni, films
        WHERE
        prenotazioni.PU = visioni.PU AND
        visioni.Cod_Film = films.Cod_Film AND
        prenotazioni.DataViaggio > '2019-03-01' AND
        prenotazioni.DataViaggio < '2019-03-15'
        GROUP BY films.Cod_Film) AS T1);

La clausola HAVING permette di aggiungere una condizione sui risultati calcolati dalla funzione di
aggregazione. In questo caso abbiamo richiesto che il conteggio delle visualizzazioni dei films, accaduto in
un certo lasso di tempo, sia pari al massimo precedentemente determinato con la subquery considerata
prima.

Parte IIa

Punto I
Per realizzare la pagina si è scelto di implementare il problema della query (b). In questo caso la realizzazione
è immediata; una volta scritta la query basta inserirla in una pagina avente il codice PHP necessario per
interfacciare i risultati a PHP stesso, in questo modo:

        Implementazione pagina punto I seconda parte 
        
        Utenti che non hanno visualizzato alcun film (nei vari viaggi):
$riga = mysqli_fetch_array($rs);
                    while ($riga)
                    {
                      echo $riga['Cognome'] . " " . $riga['Nome'] . "";
                       $riga = mysqli_fetch_array($rs);
                    }
            ?>

Punto III
Il punto richiede di effettuare alcune operazioni sullo schema di relazioni:
        FARMACO (COD_F,NOME_F,DATA_PREPARAZIONE,DATA_SCADENZA,PREZZO)
        COMPONENTE (COD_C,NOME_C,DESCRIZIONE)
        CONTIENE (ID_FARMACO,ID_COMPONENTE,QUANTITA_C)

a) disegnare il diagramma del modello concettuale corrispondente;

Il diagramma E/R relativo alle relazioni indicate risulta il seguente2:

                                       N                                                      M
             Farmaco                                         contiene                              Componente

b) definire in linguaggio SQL il modello fisico corrispondente tenendo conto dei vincoli di integrità referenziali
e/o vincoli di dominio;

            CREATE TABLE Farmaco (
                  COD_F             INT UNSIGNED PRIMARY KEY,
                  NOME_F            VARCHAR(40) NOT NULL,
                  DATA_PREPARAZIONE DATE NOT NULL,
                  DATA_SCADENZA     DATE NOT NULL,
                  PREZZO            DECIMAL(5,2),
                  CHECK(DATA_PREPARAZIONE < DATA_SCADENZA) );

            CREATE TABLE Componente (
                  COD_C               INT UNSIGNED PRIMARY KEY,
                  NOME_C              VARCHAR(40) NOT NULL,
                  DESCRIZIONE         TEXT NOT NULL);

            CREATE TABLE Contiene (
                  COD_F                             INT UNSIGNED NOT NULL,
                  COD_C                             INT UNSIGNED NOT NULL,

2   Non si indicano qui gli attributi perché l’operazione risulta graficamente lunga da svolgere
                                                               Pagina 11
PRIMARY KEY(COD_F, COD_C),
                   QUANTITA_C          SMALLINT UNSIGNED NOT NULL,
                   FOREIGN KEY(COD_F) REFERENCES Farmaco(COD_F) );
                   FOREIGN KEY(COD_C) REFERENCES Componente(COD_C) );

c) esporre il significato delle varie tipologie di vincoli che si possono riscontrare nella progettazione delle basi
di dati e dei riflessi che essi hanno sulle operazioni di inserimento, aggiornamento e cancellazione.

Nella realizzazione della precedente base di dati elementare abbiamo utilizzato vincoli di tre tipologie:
     vincoli di chiave primaria
     vincoli di integrità
     vincoli di integrità referenziale
Nello schema per quanto riguarda i vincoli di chiave primaria abbiamo due campi chiave primaria semplici
(COD_F e COD_C) ed un campo chiave primaria composito (COD_F e COD_C) su Contiene.
Nel campo chiave primaria composito il DBMS controlla che non ci siano delle ripetizioni delle coppie di valori
(COD_F, COD_C)3.

Un vincolo di integrità è stato utilizzato per garantire che non ci siano sovrapposizioni di data tra la data di
preparazione e quella di scadenza del farmaco. Sicuramente infatti per quanto riguarda queste date deve
essere DataPreparazione < DataScadenza. Questo è imposto tramite l’istruzione CHECK(….)4.

Per quanto riguarda i vincoli di integrità referenziale, essi effettuano dei controlli tra i valori delle chiavi
primarie e chiavi esterne, coinvolte nelle associazioni.
In questo caso la coppia di chiavi primarie ed esterne coinvolta data la relazione n a m “contiene” è:
              1) COD_F su Farmaco (Primaria)  COD_F su Contiene (Esterna)
              2) COD_C su Componente (Primaria)  COD_C su Contiene (Esterna)
I valori di questi due vincoli non devono mai presentare incoerenze, se sono stati posti come controllo dei
vincoli di integrità referenziali. Ad esempio:
          In Contiene non posso avere l’indicazione di un farmaco che non sia presente anche in Farmaco.
              Un riferimento di un codice di farmaco deve sempre avere corrispondenza nella tabella Farmaco.
          Idem per la tabella Componente. In Contiene non è possibile avere riferimenti a componenti il
              cui codice non esiste nella tabella Componenti.
          E’ possibile viceversa sempre avere codici di Farmaci e Componenti che non abbiano riferimenti
              in Contiene.
          Non è possibile cancellare Farmaci che abbiano associate delle tuple in Contiene5
          Non è possibile cancellare Componenti che abbiano delle tuple associate in Contiene
          Non è possibile modificare il codice di un farmaco che abbia associazioni in Contiene
          Non è possibile modificare il codice di un componente che abbia associazioni in Contiene
          Non è possibile inserire in Contiene elementi che associno farmaci o componenti che non
              esistono

3 In quanto non ha senso che un componente sia citato più volte nella formulazione di un medicinale.
4 Si ricorda che l’istruzione CHECK è stata implementata ed è quindi disponibile solo nelle ultimissime versioni di MySQL e MariaDB.
Nelle precedenti versioni essa non ha effetto pratico.
5
  Questo con la sintassi ed il tipo di vincolo indicato; ulteriori cossiderazioni possono essere fatte nel caso di presenza delle
clausole ON UPDATE…. ed ON DELETE….
                                                           Pagina 12
Puoi anche leggere