Istituto “Angioy” Informatica BASI DI DATI Prof. Ciaschetti Introduzione e prime definizioni Una Base di dati o Database è un archivio elettronico opportunamente organizzato per reperire in modo efficiente le informazioni ivi memorizzate. Come tutti gli archivi elettronici, un database è realizzato tramite uno o più file, memorizzati in modo permanente. A differenza degli archivi tradizionali su file di testo o file binari (si veda la dispensa su Archivi e File), un database è un file strutturato in modo tale da consentire l‟accesso e la gestione dei dati a un particolare software, il Gestore del database, (Data Base Management System, DBMS). ESEMPI DI DBMS DB2 ORACLE MS ACCESS MS SQL SERVER MySQL dBase SQL Anywhere Base creato da Informix, (poi acquisita da IBM), è uno dei DMBS più diffusi sul mercato. insieme al DB2, è la regina del mercato dei DMBS: si tratta di un prodotto altamente professionale e molto costoso, il migliore in termini di robustezza, sicurezza e affidabilità. è il DBMS di Microsoft Office per utenti domestici; possiede una comoda interfaccia grafica per utilizzarlo. versione professionale di Access. è il più diffuso DBMS open source, per via della sua versatilità, facilità d‟uso ed economicità è il più antico DBMS, poi evoluto in versioni più aggiornate (dBaseII, dBaseIII e dBaseIV) creato da Sybase, una delle maggiori società al mondo produttrici di DBMS. versione open source e gratuita del famoso Access di Office. Si trova nel pacchetto OpenOffice. La prima grande differenza tra la realizzazione di un archivio su file binario in linguaggio C/C++ oppure tramite database sta nel fatto che mentre nel primo caso occorre specificare in un programma cosa cercare e come cercarlo all‟interno del file (ricordate, le istruzioni fread e fwrite, fseek, ecc.), mentre nel secondo caso basta specificare cosa cercare, e non come: il modo in cui avviene la ricerca è compito del DBMS, che farà questo al posto nostro, a patto che progettiamo opportunamente il database in modo da permettergli le ricerche. L‟uso di database risulta di grande utilità nella realizzazione di archivi di grandi dimensioni, come ad esempio un sistema informativo aziendale, in cui molti utenti devono accedere a molti dati collegati tra loro in modo complesso: scrivere del codice (in C++ o qualsiasi altro linguaggio di programmazione) per accedere ogni volta a un archivio di questo tipo può risultare estremamente sconveniente. 1 Progettazione di un database Per progettare opportunamente una base di dati, occorre innanzitutto realizzare un modello concettuale del database, solitamente in UML, che specifica quali entità sono coinvolte e quali relazioni ci sono tra esse (si veda la dispensa sulla programmazione a oggetti), e successivamente derivare da questo il modello logico, ossia lo schema di come è fatto il database. Il database, come abbiamo già sottolineato nel paragrafo introduttivo, va opportunamente progettato in modo da permettere al DBMS un facile e rapido accesso ai dati, e per garantire inoltre: - non ridondanza dei dati: evitare dati ripetuti inutilmente. - inconsistenza dei dati: evitare di avere dati privi di significato o di perdere dati significativi. - sicurezza: permettere l‟accesso ai dati solo alle persone autorizzate. Modello concettuale: schema Entity/Relationship (E/R) Come per la programmazione orientata agli oggetti, in questo modello si specificano quali entità devono essere memorizzate, e come le diverse entità sono in relazione tra loro (da questo, il nome di schema E/R). Si può usare un linguaggio grafico come UML per descrivere questo schema. In questo caso, tuttavia, a differenza della OOP, non ha nessun senso parlare di metodi delle entità: ci interessa solo memorizzare informazioni, e non metodi, cioè non cosa un‟entità sa fare. Per ogni entità, dunque, andremo a definire solo la lista degli attributi che la caratterizzano. Possiamo allora disegnare uno schema E/R usando un linguaggio UML semplificato rispetto a quello utilizzato nella programmazione a oggetti, come nel seguente esempio: Come si può notare dall‟esempio, non occorre più riportare nello schema E/R i metodi dell‟entità, né il tipo dei diversi attributi (che andrà successivamente specificato nel modello logico del database). Inoltre, si indicano con un pallino pieno gli attributi obbligatori, mentre si indicano con un pallino vuoto gli attributi opzionali, quelli ai quali è possibile anche non attribuire un valore. Infine, viene sottolineato un attributo (o un insieme di attributi) che costituisce una chiave primaria, la quale permette di distinguere un elemento dall‟altro in modo univoco. Facciamo un altro esempio: 2 insegna N N L‟entità studente è composta dagli attributi obbligatori matricola, nome, cognome e dall‟attributo opzionale classe. Ciò significa che quando inseriremo i dati di uno studente, dovremo inserire la sua matricola, il suo nome, il suo cognome, e solo se lo vogliamo anche la classe. Inoltre, l‟attributo matricola è chiave primaria: significa che ogni studente è distinto dall‟altro per il fatto che la matricola è diversa. L‟entità docente, invece, è composta dagli attributi obbligatori id, nome, cognome e dall‟attributo opzionale materia. La chiave primaria in questo caso è l‟attributo id (sta per identificativo, che di solito è un codice univoco o un numero progressivo). Tra le due entità c‟è una associazione generica con molteplicità N a N. Perché lo schema concettuale sia valido, occorre che ogni attributo sia un dato semplice (non composto, come gli array o i record), che può essere una stringa, un intero, un reale, ecc. Modello logico: schema del database Una volta disegnato il modello concettuale, si passa allo schema logico del database: si stabilisce cioè come sono organizzate le informazioni dentro l‟archivio. Come abbiamo già detto, questo deve essere fatto in modo tale da permettere al DBMS di recuperare facilmente ed efficientemente i dati. Lo schema logico del database dipende dal tipo di database che si vuole realizzare. Esso può essere di diversi tipi: - database gerarchico - database reticolare - database relazionale - database object oriented I database gerarchici hanno un‟organizzazione ad albero: alcune informazioni dipendono (discendono) da altre informazioni, a formare una sorta di albero genealogico. Per realizzare questo tipo di database occorre memorizzare gli indirizzi delle informazioni “figlie” nelle informazioni “padre” in modo da poterle recuperare: servono, quindi, i puntatori. L‟uso dei puntatori rende piuttosto difficile e macchinosa la gestione di un database di questo tipo. 3 I database reticolari sono organizzati con puntatori come quelli gerarchici, solo che il grafo che rappresenta le dipendenze tra le informazioni può essere qualsiasi, non necessariamente un albero (ricordiamo che un albero è un particolare grafo, connesso e aciclico). I database relazionali sono attualmente i più utilizzati in commercio, per la loro semplicità, rapidità ed efficienza nella gestione dei dati. Tutti i DBMS elencati nel paragrafo introduttivo fanno riferimento a database relazionali (per questo motivo prendono il nome di RDBMS). Essendo i più utilizzati, sono quelli che tratteremo in questa dispensa e ne parleremo più in dettaglio tra poco. I database object oriented sono i più recenti e hanno grande utilità in particolari applicazioni come i database spaziali e in alcune aree finanziarie. Non hanno avuto, però, per la complessità di gestione e per la difficoltà del linguaggio usato per reperire informazioni dal database, un grande successo commerciale. Il modello relazionale Un database relazionale è composto da una o più relazioni o tabelle. Matematicamente, una relazione è un sottoinsieme del prodotto cartesiano di due o più insiemi. Si faccia attenzione a non confondere il concetto di relazione nel modello logico di un database, che corrisponde a una tabella, con quello di relazione (che chiameremo d‟ora in poi associazione, per evitare confusione) nello schema E/R che lega due entità tra loro. ESEMPIO: Siano dati gli insiemi A={1,2,3} e B = {x, y}. Il prodotto cartesiano degli insiemi A e B (si indica AXB) è l‟insieme formato da tutte le possibili coppie ottenute prendendo un elemento di A e un elemento di B. Qundi, abbiamo AXB = {(1,x), (1, y), (2,x), (2, y), (3,x), (3, y)} Essendo una relazione R un sottoinsieme del prodotto cartesiano, essa sarà formata solo da alcune delle coppie possibili, come ad esempio R = {(1, y), (2,x), (2, y)} ESEMPIO: Siano dati gli insiemi U = {Filippo, Marco, Gianni} e D = {Arianna, Sara, Fernanda} dei tronisti e delle troniste della trasmissione Uomini e Donne. Consideriamo la relazione “fidanzarsi con”. Essa è composta da alcune delle coppie possibili del prodotto cartesiano UXD (che ricordiamo, è l‟insieme di tutte le possibili coppie formate da un uomo e una donna). Ad esempio, potremmo avere R = {(Filippo, Sara), (Gianni,Fernanda)} ESEMPIO: Siano dati gli insiemi A = {1, 2, 3}, B = {x, y}, C = {?, !}. Una relazione è un sottoinsieme del prodotto cartesiano AXBXC, cioè formata da alcune delle possibili triple ottenute prendendo un elemento dell‟insieme A, un elemento dell‟insieme B e un elemento dell‟insieme C. Ad esempio, R = {(1, x, ?), (1, y, ?), (3, y, !)} 4 In generale, detti A, B, C,… i domini degli attributi a, b, c,… di un‟entità, cioè gli insiemi dei possibili valori che ogni attributo può assumere (A è l‟insieme dei possibili valori che può assumere l‟attributo a, B è l‟insieme dei possibili valori che può assumere l‟attributo b, ecc.), e supponendo di avere n diversi attributi, una relazione R è un sottoinsieme di tutte le possibili n-ple (si legge ennuple) ottenute prendendo un elemento di A, un elemento di B, un elemento di C, ecc. Appare evidente come una relazione può essere vista come una tabella, in cui ogni riga corrisponde a una n-pla e ogni colonna corrisponde a un diverso attributo. Con riferimento all‟ultimo esempio, possiamo rappresentare la relazione R come a b c 1 x ? 1 y ? 3 y ! Nel linguaggio dei database relazionali, ogni riga si chiama una tupla (per ricordare che si tratta di triple o quadruple o quintuple o, in generale, n-ple) e ogni colonna si chiama campo, anziché attributo. In una tabella, il numero di righe si chiama cardinalità della relazione, mentre il numero di colonne si chiama grado della relazione. Nelle figure seguenti mostriamo un esempio di tabella (o relazione, visto che sono la stessa cosa) creata con il DBMS Base di OpenOffice: nella Figura 1 osserviamo la struttura della tabella, che ne descrive i campi, ognuno con un proprio tipo di dato; nella Figura 2 mostriamo il contenuto della tabella, ossia l‟insieme delle tuple che la compongono. Figura 1 Figura 2 Per sinteticità, per descrivere la struttura di una tabella nel modello relazionale si usa spesso la seguente notazione: con riferimento alla tabella studente della figura precedente, si può scrivere Studente ( matricola, nome, cognome, età, classe ) dove matricola è la chiave primaria. 5 Regole di derivazione del modello logico dal modello concettuale Per creare un database in modo coerente, cioè tale che il DBMS possa reperire le informazioni che ci interessano con facilità ed efficienza, occorre seguire alcune regole. A partire dallo schema E/R, si applicano le seguenti regole: 1. ogni entità diventa una tabella, con tante colonne (campi) quanti sono gli attributi dell‟entità, con un‟eccezione: se c‟è un‟associazione 1 a 1 tra due entità, viene realizzata un‟unica tabella in cui compaiono tutti gli attributi di entrambe le entità. ESEMPIO: diventa ESEMPIO: diventa 2. ogni associazione 1 a 0..1 viene realizzata inserendo una chiave esterna nella tabella dell‟entità 0..1, che fa riferimento alla chiave primaria dell‟entità 1 ESEMPIO: diventa 3. ogni associazione 1 a N viene realizzata inserendo una chiave esterna nella tabella dell‟entità N, che fa riferimento alla chiave primaria dell‟entità 1 6 ESEMPIO: diventa 4. ogni associazione N a N viene realizzata creando una nuova tabella che contiene solo le chiavi primarie delle due entità, più eventuali attributi dell‟associazione. ESEMPIO: diventa Operatori relazionali e SQL Per interrogare il database, ossia per recuperare le informazioni memorizzate al suo interno, si usa un linguaggio specifico, chiamato SQL (Structured Query Language, linguaggio strutturato di interrogazione). Prima di descrivere come funziona, occorre spiegare che ogni interrogazione in SQL è una combinazione di una o più tra tre operazioni relazionali che è possibile fare sul database: 1. Proiezione: si rappresenta con il simbolo e crea una nuova tabella che contiene solo alcune colonne di una tabella esistente (dunque, ne cambia il grado), nel seguente modo: facendo sempre riferimento alla tabella Studente dell‟esempio di pagina 5, supponiamo di voler estrarre solo gli attributi nome e cognome: scriveremo nome, cognome (Studente) ottenendo la tabella seguente: 7 2. Selezione: si rappresenta con il simbolo e crea una nuova tabella che contiene solo alcune righe di una tabella esistente (dunque, ne cambia la cardinalità), nel seguente modo: facendo ancora riferimento alla tabella Studente di pagina 5, supponiamo di voler cercare gli studenti che hanno più di 18 anni: scriveremo età>18 (Studente) ottenendo la tabella seguente: Come si può vedere, l‟operazione di selezione richiede di esprimere una condizione, che può essere una qualsiasi espressione booleana con operatori AND, OR e NOT, e operatori matematici di confronto > , >= , < , <= , = , . 3. Congiunzione (join): si rappresenta con il simbolo e crea una nuova tabella ottenuta congiungendo insieme due tabelle su un attributo comune. Ad esempio, date le due tabelle dove è stata posta una chiave esterna sigla_classe nella tabella Studente che fa riferimento all‟attributo sigla della tabella Classe, per rappresentare l‟associazione 1 a N tra le due entità, se si effettua un join tra le due tabelle sull‟attributo comune, cioè l‟operazione Classe sigla Studente sigla_classe si ottiene la tabella Per essere più chiari, facciamo un altro esempio: siano date le seguenti tabelle R1 e R2, con attributo comune A. 8 Facciamo ora l‟operazione di join tra le due, sull‟attributo A, cioè R1A R2A . Otteniamo la nuova tabella SQL Nel linguaggio SQL, possiamo eseguire le tre operazioni relazionali viste (proiezione, selezione e join) formulando un‟interrogazione (query, in inglese) nel seguente modo: SELECT campi FROM tabelle WHERE condizioni Nella prima riga si realizza l‟operazione di proiezione , cioè si scelgono (SELECT) i campi da visualizzare della tabella. Nella seconda riga si specificano le tabelle dalle quali (FROM) prendere i dati necessari alla nostra l‟interrogazione. Se occorre effettuare uno o più join tra tabelle, si elencano tutte le tabelle separate da virgola. Con la terza riga si realizza l‟operazione di selezione , cioè, si specificano le condizioni (WHERE) di selezione delle righe della tabella, insieme alle condizioni di join (cioè, che il valore dell‟attributo comune sul quale effettuare il join deve essere uguale). Facciamo alcuni esempi: - Con riferimento alla tabella studente di pagina 5, vogliamo visualizzare il nome e il cognome degli studenti della 5°A. Scriveremo SELECT nome, cognome FROM Studente WHERE classe = 5A 9 - Sempre con riferimento alla tabella studente di pagina 5, vogliamo visualizzare le diverse età degli studenti della 4B. In questo caso, aggiungiamo la parola DISTINCT all‟operazione SELECT in modo da non visualizzare valori ripetuti. Scriveremo, perciò, SELECT DISTINCT eta FROM Studente WHERE classe = 4B - Facciamo un join: siano date le tabelle Studente e Classe mostrate nell‟esempio di pagina 8. Vogliamo visualizzare il nome e il cognome degli studenti del secondo piano. Bisogna congiungere insieme le due tabelle, poiché le informazioni nome e cognome di uno studente sono nella tabella Studente, mentre l‟informazione piano è nella tabella Classe. Scriveremo allora SELECT nome, cognome FROM Studente, Classe WHERE piano = 2 AND sigla=sigla_classe La prima delle due condizioni del WHERE realizza la selezione , scegliendo solo le righe relativi a studenti del secondo piano, mentre la seconda è la condizione per fare la congiunzione tra le due tabelle. In molte implementazioni di SQL, per una maggior chiarezza, si richiede che il nome dei campi sia preceduto dal nome della tabella di cui il campo fa parte, separati da un punto. Ad esempio, nell‟ultima interrogazione vista, dovremo scrivere SELECT Studente.nome, Studente.cognome FROM Studente, Classe WHERE Classe.piano = 2 AND Classe.sigla=Studente.sigla_classe Oltre alle operazioni viste, SQL mette a disposizione molti altri strumenti per effettuare conteggi (COUNT), somme (SUM), medie (AVG), ecc, oltre alla possibilità di effettuare interrogazioni più complesse come query di risultati di altre query (query annidate tra loro). Al momento, questo approfondimento non rientra negli scopi di questa dispensa. IL DBMS di OpenOffice: Base Come abbiamo già anticipato, Base è un DBMS gratuito fornito con il pacchetto OpenOffice, e come il più famoso Access di Microsoft Office (che però è a pagamento), ha un‟interfaccia grafica e procedure guidate per la creazione di tabelle, per la realizzazione delle query, per definire delle viste (sono regole di visibilità che definiscono quali utenti possono vedere quali tabelle o porzioni di esse: si pensi a un database aziendale: il reparto produzione non deve necessariamente vedere le tabelle dei dati del reparto amministrazione, e viceversa), preparare formulari e rapporti, e molte altre caratteristiche. 10 All‟avvio, Base presenta la seguente finestra, per scegliere se creare un nuovo database o aprirne uno già esistente: Una volta fatta la scelta, se si tratta di un nuovo database Base ci chiede di registrarlo (serve a poter usufruire di funzioni messe a disposizione da OpenOffice, come la condivisione in rete e il controllo degli accessi) e salvarlo. Si arriva così alla schermata principale: Per creare una nuova tabella, si può usare la procedura guidata o fare click su Crea tabella in vista struttura. Nel secondo caso, si apre la seguente schermata 11 che permette di definire i campi della tabella e i loro tipi, di inserirne una descrizione informale, e di assegnare una chiave primaria (basta fare click destro sul campo che deve diventare chiave) alla tabella. ATTENZIONE: Base richiede che ogni tabella abbia una chiave primaria, che può essere costituita da un solo campo! Una volta definita la struttura di una tabella, la si salva e la si ritrova visualizzata nella lista delle tabelle nella schermata principale. Per vedere il contenuto della tabella, o per inserirvi dati, basta fare doppio click su di essa. Per realizzare una query, basta fare click sulla voce Ricerche nella schermata principale, aprendo la seguente schermata A questo punto è possibile definire un‟interrogazione (o query, o ricerca) in modalità struttura, in modalità SQL, o usando una procedura guidata. ATTENZIONE: l‟SQL di Base richiede che i nomi delle tabelle e i nomi dei campi siano racchiusi tra doppi apici, e che i valori costanti siano racchiusi tra singoli apici! Ad esempio, la query 12 SELECT Studente.nome, Studente.cognome FROM Studente, Classe WHERE Classe.piano = 2 AND Classe.sigla=Studente.sigla_classe si scrive nell‟SQL di Base nel seguente modo: SELECT “Studente”.”nome”, “Studente”.”cognome” FROM “Studente”, “Classe” WHERE “Classe”.”piano” = „2‟ AND “Classe”.”sigla”=”Studente”.”sigla_classe” Se si sceglie di definire la query in modalità struttura, invece, si apre la seguente schermata: Innanzitutto, si scelgono le tabelle che si vogliono utilizzare nella query (si noti che è possibile anche scegliere le tabelle ottenute con delle query già memorizzate). Queste verranno poste in alto e sarà possibile collegarle tra loro per effettuare le congiunzioni (basta trascinare uno sull‟altro l‟attributo comune), come nel seguente esempio: Ora, bisogna impostare le operazioni di selezione e proiezione: si scelgono i campi nella parte inferiore della schermata, impostando l‟opzione visibile se devono essere visualizzati (è la proiezione), e impostando eventuali criteri di selezione delle righe. Mostriamolo con un esempio: 13 con riferimento alle due tabelle Studente e Classe della figura precedente, realizziamo in questa modalità la query SELECT “Studente”.”nome”, “Studente”.”cognome” FROM “Studente”, “Classe” WHERE “Classe”.”piano” = „2‟ AND “Classe”.”sigla”=”Studente”.”sigla_classe” dovremo fare come segue: Per esercizio, si aggiunga una tabella Docente (id, nome, cognome, materia) alle due tabelle del precedente esempio, e una tabella Docente-Classe (id, id_docente, id_classe) per realizzare l‟associazione N a N tra le tabelle Docente e Classe. Dopo aver popolato (inserito dei dati) il database, si esegua la seguente ricerca (o query, o interrogazione): visualizzare il nome e il cognome di tutti gli studenti che seguono Informatica. Si osservi successivamente il codice SQL della ricerca generato dalla modalità struttura di Base (click destro sulla query, poi Modifica in vista SQL). Normalizzazione del database Perché un database sia opportunamente organizzato, esso deve essere progettato in modo da non presentare anomalie, che si verificano spesso quando i dati presenti nel database sono ridondanti (più copie inutili degli stessi dati). Le anomalie che possono verificarsi sono di inserimento, di modifica e di cancellazione. Facciamo un esempio: Supponiamo di avere la seguente tabella, in cui il codice del prodotto è la chiave primaria: 14 appare evidente che la tabella non è ben strutturata, in quanto ci sono parecchi dati ripetuti inutilmente. Possono verificarsi, in questo caso, le seguenti situazioni: - Anomalia di inserimento: se abbiamo un nuovo magazzino che non contiene prodotti, non possiamo aggiungerlo al database. - Anomalia di modifica: se cambia l‟indirizzo di un magazzino, occorre cambiarlo in tutte le tuple dove compare. - Anomalia di cancellazione: se si svuota un magazzino, perdiamo le informazioni sul suo indirizzo. Per risolvere questo problema, si effettua un processo di normalizzazione del database, utilizzando in sequenza (una dopo l‟altra) tre diverse forme normali: Prima forma normale (1FN): Una tabella si dice in prima forma normale quando rispetta i requisiti del modello relazionale, cioè, ogni attributo è formato da un dato elementare, non ci sono elementi uguali tra loro nella relazione (tuple o righe uguali), non ci sono attributi ripetuti. Seconda forma normale (2FN): Una tabella si dice in seconda forma normale se è in 1FN e non ci sono attributi che dipendono parzialmente dalla chiave primaria; è il caso in cui la chiave primaria è formata da più di un attributo, e c‟è un terzo attributo che dipende solo da una parte della chiave. ESEMPIO: Supponiamo che nella tabella della figura precedente la chiave primaria sia composta dalla coppia di attributi prodotto, magazzino, cioè che la nostra tabella sia la seguente Inventario (prodotto, magazzino, quantità, indirizzo) Chiaramente, l‟attributo indirizzo dipende solo dall‟attributo magazzino, che è parte della chiave. Si può risolvere questa situazione realizzando due tabelle nel seguente modo: Inventario (prodotto, quantità, id_magazzino) Magazzino (id, indirizzo) Terza forma normale (2FN): Una tabella si dice in terza forma normale se è in 2FN e non ci sono dipendenze transitive, cioè attributi che dipendono indirettamente dalla chiave, ma da altri attributi non chiave. E‟ l‟esempio della tabella in figura: Inventario (prodotto, magazzino, quantità, indirizzo) L‟attributo non chiave indirizzo (del magazzino) dipende dall‟attributo non chiave magazzino, il quale dipende dall‟attributo prodotto, che è chiave. Per risolvere questa situazione, si può procedere come nel caso della 2FN, creando due tabelle Inventario (prodotto, quantità, id_magazzino) Magazzino (id, indirizzo) 15 ESEMPIO: Facciamo un altro esempio, con la seguente tabella: Studente (matricola, nome, cognome, scuola, telefono_scuola) Si vede chiaramente che anche in questo caso c‟è una dipendenza transitiva: l‟attributo telefono_scuola dipende dall‟attributo scuola, che non è chiave primaria. Si può risolvere la situazione creando le due tabelle seguenti, al posto di quella data: Studente (matricola, nome, cognome, id_scuola) Scuola (nome_scuola, telefono_scuola) E‟ opportuno sottolineare, comunque, che una buona progettazione concettuale del database (lo schema E/R) ci darà tabelle che già rispettano tutte e tre le forme normali, senza bisogno di effettuare un processo di normalizzazione. 16