05 PHP e MySQL XP
14-12-2004
5
0:05
Pagina 75
Progettazione
di database relazionali
Sin dal Capitolo 2, Primi passi con MySQL, abbiamo lavorato con un database molto semplice che era composto da una singola tabella chiamata “joke”. Anche se questo database ci è servito come introduzione ai database MySQL c’è molto di più di quanto possa insegnare questo piccolo esempio, per quanto riguarda i database relazionali. In questo capitolo approfondiremo e impareremo nuove caratteristiche di MySQL, per cercare di capire e sfruttare tutto
quello che i database relazionali hanno da offrire.
Tenete presente, però, che molti argomenti verranno trattati in modo informale e non rigoroso. Come alcuni esperti di Scienza del Computer potranno confermarvi, la progettazione di
database è un’importante area di ricerca con principi testati e provati matematicamente e che,
anche se utili, sono aldilà degli obiettivi di questo testo. Se volete maggiori informazioni consultate il sito www.datamodel.org per un elenco di ottimi libri e per avere altre risorse utili. In
particolare potreste dare un’occhiata alle Rules of Data Normalization nella sezione “Data
Modeling” del sito.
Dare a Cesare quel che è di Cesare
Per iniziare, ricordiamoci com’era la struttura della nostra tabella di barzellette contenente tre
colonne: id, joketext e jokedate. Insieme, queste colonne ci permettono di identificare le barzellette (id), di mantenere una traccia del loro testo (joketext) e della data in cui sono state
inserite (jokedate). Il codice SQL che crea questa tabella e che inserisce un paio di record è nell’archivio del codice con il nome di jokes1.sql.
Diciamo ora di voler indicare altre informazioni sulle nostre barzellette: il nome delle persone che le hanno inserite. Sembrerebbe naturale voler aggiungere una nuova colonna alla
nostra tabella per fare ciò. Il comando SQL ALTER TABLE (che prima non abbiamo visto) ci permette di fare esattamente ciò. Connettetevi al vostro server MySQL usando la riga di comando mysql proprio come nel Capitolo 2, Primi passi con MySQL, selezionate il vostro database
(ijdb, se avete usato il nome suggerito in quel capitolo) e quindi digitate questo comando:
05 PHP e MySQL XP
14-12-2004
0:05
Pagina 76
Creare siti Web con PHP e MySQL
mysql>ALTER TABLE joke ADD COLUMN
->authorname VARCHAR(255);
Questo codice aggiunge una colonna chiamata authorname alla vostra tabella. Il tipo dichiarato è una stringa a lunghezza variabile fino a 255 caratteri – un sacco di spazio, adatto a nomi
anche molto esotici. Aggiungiamo una colonna per gli indirizzi e-mail degli autori:
mysql>ALTER TABLE joke ADD COLUMN
->authoremail VARCHAR(255);
Per maggiori informazioni sul comando ALTER TABLE andate all’Appendice A, Sintassi MySQL.
Per essere sicuri che le due colonne siano state aggiunte in modo corretto dovremmo chiedere a MySQL di descriverci la tabella:
mysql>DESCRIBE joke;
+-------------+--------------+------+-----+-------------+
| Field
| Type
| Null | Key | Default
|
+-------------+--------------+------+-----+-------------+
| id
| int(11)
|
| PRI | NULL
|
| joketext
| text
| YES |
| NULL
|
| jokedate
| date
|
|
| 0000-00-00 |
| authorname | varchar(255) | YES |
| NULL
|
| authoremail | varchar(255) | YES |
| NULL
|
+-------------+--------------+------ +-----+-------------+
5 rows in set (0.01 sec)
Sembra a posto, no? Ovviamente dovremmo fare dei cambiamenti al codice HTML e PHP dei
form che abbiamo creato nel Capitolo 4, Pubblicare i dati MySQL sul Web, quelli che ci permettevano di aggiungere nuove barzellette al database. Usando la query UPDATE potremmo
aggiungere i dettagli degli autori per tutte le barzellette nella tabella. Ma, prima di essere travolti da questi cambiamenti, dobbiamo fermarci e considerare se questo nuova struttura di
database è la scelta giusta in questo caso. Pare proprio di no.
Mantenere le cose separate
All’ingrandirsi dei siti Web basati su database potreste decidere che un elenco personale di
barzellette non è abbastanza. Infatti potreste volere ricevere più barzellette inviate che quelle
che immettete voi. Diciamo che decidete di pubblicare un sito dove le persone, da tutte le parti
del mondo, possono condividere barzellette fra loro. Avete mai sentito parlare dell’Internet
Movie Database (IMDB)? Voi decidete di aprire l’Internet Joke Database (IJDB)! Aggiungere
il nome dell’autore e il suo indirizzo e-mail sicuramente ha senso, ma il metodo che abbiamo
usato sopra porta potenzialmente a diversi problemi:
•
76
Cosa succedere se un’affezionata contribuente del vostro sito, che si chiama Joan Smith,
cambia il suo indirizzo e-mail? Potrebbe iniziare a inserire nuove barzellette usando il
nuovo indirizzo, ma quello vecchio rimarrebbe associato alle barzellette inviate nel passato. Guardando il vostro database potreste semplicemente pensare che esistono due perso-
05 PHP e MySQL XP
14-12-2004
0:05
Pagina 77
Capitolo 5: Progettazione di database relazionali
•
ne che si chiamano Joan Smith che inviano delle barzellette. Se lei fosse particolarmente
coscienziosa potrebbe informarvi del cambiamento di indirizzo e voi potreste cercare di
aggiornare tutte le vecchie barzellette con il nuovo indirizzo; se solo ne saltaste una, però,
il database conterrebbe delle informazioni non corrette. Gli esperti di progettazione del
database si riferiscono a questo genere di problema come un’anomalia di aggiornamento.
Sarebbe naturale per voi fare affidamento sul vostro database per fornire un elenco di persone che non hanno mai mandato barzellette al vostro sito. Ed effettivamente potreste
ottenere facilmente un elenco usando la seguente query:
mysql>SELECT DISTINCT authorname, authoremail
->FROM joke;
•
La parola DISTINCT in questa query dice a MySQL di non duplicare i risultati delle righe
nell’output. Per esempio, se Joan Smith ha inviato 20 barzellette sul vostro sito, il suo
nome dovrebbe apparire 20 volte nell’elenco, anziché solo una, se non provvedeste a usare
l’opzione DISTINCT.
Se, per qualche ragione, decidete di rimuovere tutte le barzellette che una certa persona
vi ha inviato, rimuovereste con esse tutti i record di questa persona dal database nel processo e non sareste più in grado di inviargli informazioni sul vostro sito. Poiché la mailing list potrebbe essere una fonte di entrate primaria per il vostro sito non penso siate
dell’idea di gettare un indirizzo e-mail solo perché non vi piacciono le barzellette che questa persona vi ha inviato. Gli esperti di progettazione la chiamano anomalia di cancellazione.
Non avete garanzie che Joan Smith non inserisca il suo nome come “Joan Smith” un giorno, “J. Smith” un altro e come “Smith, Joan” ancora in un’altra occasione. Questo renderebbe sempre più difficile mantenere la traccia di un autore specialmente se Joan Smith
avesse diversi indirizzi e-mail.
Questi problemi – e altri – possono essere risolti velocemente con delle query. Anziché immagazzinare le informazione degli autori nella tabella delle barzellette, però, possiamo creare una
nuova tabella dedicata completamente al nostro elenco di autori. Poiché abbiamo usato una
colonna chiamata id nella tabella delle barzellette, per identificare ogni barzelletta con un
numero univoco, useremo una colonna chiamata allo stesso modo per identificare gli autori.
Possiamo allora usare gli id degli autori nella nostra tabella delle barzellette per associare gli
autori alle loro barzellette. Il layout completo del database è mostrato nella figura 5.1.
Quello che mostrano le due tabelle sono tre barzellette e due autori. La colonna authorid della
tabella joke fornisce una relazione tra le due tabelle, indicando che Kevin Yank ha inviato le
barzellette 1 e 2 e Joan Smith invece la numero 3. Da notare che, poiché ogni autore appare
solo una volta nel database e appare indipendentemente dalle barzellette che ha inviato, abbiamo evitato i problemi delineati in precedenza.
La caratteristica più importante della progettazione di questo database, comunque, è che poiché stiamo immagazzinando informazioni su due tipi di “oggetti” (barzellette e autori) è più
appropriato avere due tabelle. Questa è una regola che dovreste sempre tenere a mente quan77
05 PHP e MySQL XP
14-12-2004
0:05
Pagina 78
Creare siti Web con PHP e MySQL
Figure 5.1. Il campo authorid associa ogni riga in “joke” con una riga in “author”.
do progettate un database: ogni tipo di entità (o “oggetto”) di cui volete immagazzinare informazioni dovrebbe avere la sua tabella separata.
Preservare il database di cui sopra sin dall’inizio è abbastanza semplice (e coinvolge solo due
query del tipo CREATE TABLE ), ma, poiché ci piacerebbe fare questi cambiamenti in un modo
non-distruttivo (per esempio senza perdere nessuna preziosa barzelletta), useremo di nuovo
il comando ALTER. Prima di tutto dobbiamo sbarazzarci delle colonne relazionate all’autore
nella tabella delle barzellette :
mysql>ALTER TABLE joke DROP COLUMN authorname;
Query OK, 0 rows affected (0.00 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql>ALTER TABLE joke DROP COLUMN authoremail;
Query OK, 0 rows affected (0.00 sec)
Records: 0 Duplicates: 0 Warnings: 0
Adesso creiamo la nostra nuova tabella:
mysql>CREATE TABLE author (
-> id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
-> name VARCHAR(255),
-> email VARCHAR(255)
->);
Per finire, aggiungiamo la colonna authorid alla nostra tabella delle barzellette:
mysql>ALTER TABLE joke ADD COLUMN authorid INT;
78
05 PHP e MySQL XP
14-12-2004
0:05
Pagina 79
Capitolo 5: Progettazione di database relazionali
Se preferite i comandi CREATE TABLE per creare le due tabelle, sin dal principio sono forniti nell’archivio del codice 2tables.sql.
Quello che ci rimane da fare è aggiungere alcuni autori alla nuova tabella e assegnare gli autori a tutte le barzellette esistenti nel database, completando la colonna authorid[1]. Proseguite
in questo lavoro, se vi piace – dovrebbe farvi fare pratica con le query INSERT e UPDATE.
Gestire tabelle multiple
Con i dati in due tabelle potrebbe sembrare che state complicando il processo per il loro recupero. Considerate, per esempio, il nostro scopo originale: mostrare un elenco di barzellette
con il nome e l’indirizzo e-mail dell’autore a fianco di ogni barzelletta. Nella soluzione con
una singola tabella potreste avere tutte le informazioni di cui avete bisogno per far un tale
elenco, utilizzando una sola dichiarazione SELECT nel vostro codice PHP:
$jokelist = mysql_query(
“SELECT joketext, authorname, authoremail FROM jokes”);
while ($joke = mysql_fetch_array($jokelist)) {
$joketext = $joke[‘joketext’];
$name = $joke[‘authorname’];
$email = $joke[‘authoremail’];
// Mostra la barzelletta con l’informazione sull’autore
echo “<p>$joketext<br />” .
“(by <a href=’mailto:$email’>$name</a>)</p>”;
}
Con il primo sistema, a prima vista, non sembra possibile. Poiché i dettagli di ogni barzelletta non sono conservati nella tabella delle barzellette, potreste pensare che occorra recuperare
questi dati separatamente per ogni barzelletta che volete mostrare. Il codice per fare quest’azione sarebbe il seguente:
// Recupera l’elenco delle barzellette
$jokelist = mysql_query(“SELECT joketext, authorid FROM joke”);
while ($joke = mysql_fetch_array($jokelist)) {
// Recupera il testo e l’authorid per la barzelletta
$joketext = $joke[‘joketext’];
$authorid = $joke[‘authorid’];
// Recupera i dettagli dell’autore per la barzelletta
$authordetails = mysql_query(
“SELECT name, email FROM author WHERE id=$authorid”);
$author = mysql_fetch_array($authordetails);
[1]
Per adesso dovrete fare ciò manualmente. Ma non preoccupatevi, nel Capitolo 6, Un Content Management
System vedremo come PHP possa automaticamente inserire record con gli id corretti, riportando la relazione che
c’è fra loro.
79
05 PHP e MySQL XP
14-12-2004
0:05
Pagina 80
Creare siti Web con PHP e MySQL
$name = $author[‘name’];
$email = $author[‘email’];
// Mostra la barzelletta con l’informazione sull’autore
echo “<p>$joketext<br />” .
“(by <a href=’mailto:$email’>$name</a>)</p>”;
}
È piuttosto confuso e comporta una query al database per ogni singola barzelletta che viene
mostrata, cosa che potrebbe rallentare considerevolmente il caricamento della vostra pagina.
Considerato tutto ciò sembrerebbe che il vecchio metodo sia la soluzione migliore, nonostante la sua debolezza. Fortunatamente i database relazionali come MySQL sono progettati per
semplificare il lavoro con i dati salvati in tabelle multiple! Usando una nuova formulazione
della dichiarazione SELECT chiamata unione (join), potete avere il meglio di entrambi i mondi.
Il join vi permette di trattare i dati relazionati in tabelle multiple come se fossero immagazzinati in una tabella unica. Questa è la sintassi in un caso semplice:
mysql>SELECT columns FROM tables
->WHERE condition(s) for data to be related;
Nel vostro caso le colonne alle quali siete interessati sono joketext nella tabella delle barzellette e nome ed email nella tabella dell’autore. La condizione necessaria a un record nella tabella delle barzellette, affinché sia collegato a un record nella tabella degli autori, è che il valore
nella colonna authorid nella tabella delle barzellette sia uguale al valore a quello della colonna id nella tabella degli autori. Ecco un esempio di un join (le prime due query mostrano semplicemente cosa è contenuto nelle due tabelle – non sono necessarie):
mysql>SELECT LEFT(joketext, 20), authorid FROM joke;
+---------------------- +-----------+
| LEFT(joketext, 20)
| authorid |
+---------------------- +-----------+
| Why did the chicken |
1 |
| Knock knock. Who’s t |
1 |
| A man walks into a b |
2 |
+-----------------------+----------+
3 rows in set (0.00 sec)
mysql>SELECT * FROM author;
+---- +------------ +---------------------+
| id | name
| email
|
+---- +------------ +---------------------+
| 1 | Kevin Yank | [email protected] |
| 2 | Joan Smith | [email protected]
|
+---- +------------ +---------------------+
2 rows in set (0.00 sec)
80
05 PHP e MySQL XP
14-12-2004
0:05
Pagina 81
Capitolo 5: Progettazione di database relazionali
mysql>SELECT LEFT(joketext, 20), name, email
->FROM joke, author WHERE authorid = author.id;
+-----------------------+------------ +---------------------+
| LEFT(joketext, 20)
| name
| email
|
+-----------------------+------------ +---------------------+
| Why did the chicken
| Kevin Yank | [email protected] |
| Knock-knock! Who’s t | Kevin Yank | [email protected] |
| A man walks into a b | Joan Smith | [email protected]
|
+-----------------------+------------ +---------------------+
3 rows in set (0.00 sec)
Vedete? Il risultato del terzo SELECT, che è un join, raggruppa i valori immagazzinati nelle due
tabelle in una unica tabella di risultati, che ha relazionato correttamente i dati che appaiono
insieme. Anche se i dati sono immagazzinati in due tabelle, potete sempre ottenere le informazioni di cui avete bisogno per emettere un elenco di barzellette sulla vostra pagina Web con
una singola query. Da notare, nella query, che, poiché ci sono colonne chiamate id in entrambe le tabelle, si è dovuto specificare il nome della tabella per riferirsi alla colonna id della tabella degli autori (author.id). Se non specificate il nome della tabella, allora MySQL non saprà a
quale id si sta riferendo e incapperete nel seguente errore:
mysql>SELECT LEFT(joketext, 20), name, email
->FROM joke, author WHERE authorid = id;
ERROR 1052: Column: ‘id’ in where clause is ambiguous
Ora che sapete come accedere in modo efficiente ai dati salvati nelle vostre due tabelle, potete riscrivere il codice per il vostro elenco di barzellette sfruttando le unioni:
Esempio 5.1. jokelist2.php (esercitazione)
$jokelist = @mysql_query(
‘SELECT joketext, name, email
FROM joke, author WHERE authorid=author.id’);
if (!$jokelist) {
exit(‘<p>Error performing query: ‘ . mysql_error() . ‘</p>’);
}
while ($joke = mysql_fetch_array($jokelist)) {
$joketext = $joke[‘joketext’];
$name = $joke[‘name’];
$email = $joke[‘email’];
// Mostra la barzelletta con l’informazione dell’autore
echo “<p>$joketext<br />” .
“(by <a href=’mailto:$email’>$name</a>)</p>”;
}
Il risultato è mostrato nella figura 5.2.
Più lavorate con i database, più comprenderete quanto sia potente poter combinare dei dati
contenuti in tabelle separate in un’unica tabella. Considerate, per esempio, la seguente query
che mostra un elenco di tutte le barzellette scritte da Joan Smith:
81
05 PHP e MySQL XP
14-12-2004
0:05
Pagina 82
Creare siti Web con PHP e MySQL
Figura 5.2. Le migliori le ho scritte tutte io!
mysql>SELECT joketext FROM joke, author WHERE
->name=”Joan Smith” AND authorid=author.id;
+----------------------------------+
| joketext
|
+----------------------------------+
| A man walks into a bar. “Ouch.” |
+----------------------------------+
1 row in set (0.02 sec)
I risultati della precedente query provengono solo dalla tabella delle barzellette, ma la query
usa un join per cercare barzellette secondo un valore immagazzinato nella tabella degli autori. Ci saranno molte altri esempi intelligenti di query come queste per tutto il libro, ma questo esempio, da solo, illustra che le applicazioni pratiche dei join sono molte e che, quasi sempre, possono evitarvi un sacco di lavoro!
Relazioni semplici
La progettazione migliore per un database è dettata di solito dal tipo di relazione che intercorre tra i dati. In questo esempio esamineremo i più frequenti tipi di relazioni e spiegheremo come meglio rappresentarli in un database relazionale.
Nel caso di una semplice relazione uno-a-uno tutto quello di cui avrete bisogno sarà una singola tabella. Un esempio di relazione uno a uno che avete visto finora è il database con l’indirizzo e-mail di ogni autore, nel nostro database delle barzellette. Poiché ci sarà un indirizzo email per ogni autore e un autore per ogni indirizzo e-mail, non c’è ragione per dividere gli
indirizzi in tabelle separate.
82
05 PHP e MySQL XP
14-12-2004
0:05
Pagina 83
Capitolo 5: Progettazione di database relazionali
Una relazione molti-a-uno è un po’ più complicata, ma ne avete vista una anche di questo tipo.
Ogni barzelletta nel nostro database è associata con un solo autore, anche se molte sono state
scritte dallo stesso autore. Questa relazione barzelletta-autore è del tipo molti-a-uno. Abbiamo
già trattato i problemi che ci sono nel conservare le informazioni associate all’autore della barzelletta nella stessa tabella della barzelletta. In breve, possono risultare molte copie dello stesso dato che sono poi difficili da mantenere sincronizzate, sprecando spazio. Se dividiamo i
dati in due tabelle e utilizziamo una colonna id per collegarle insieme, il che è reso possibile
dai join come mostrato prima, tutti questi problemi scompariranno.
Una relazione uno-a-molti è semplicemente una relazione molti-a-uno vista dalla direzione
opposta. Fintanto che la relazione barzelletta-autore è molti-a-uno, la relazione autore-barzelletta è uno-a-molti (c’è un autore potenzialmente per molte barzellette). Questo è facile da
vedere in teoria, ma quando vi incappate non è poi così ovvio. Nel caso di barzellette e autori, abbiamo iniziato con un elenco di barzellette (i molti) e quindi abbiamo voluto assegnare
un autore a ognuno di loro (l’uno). Adesso guardiamo a un ipotetico problema di progettazione se iniziamo dall’uno e vogliamo aggiungere i molti.
Diciamo che vogliamo permettere a ognuno degli autori nel nostro database (l’uno) di avere
indirizzi e-mail multipli (i molti). Quando qualcuno senza esperienza nella progettazione di
database si avvicina a una relazione uno-a-molti come questa, il suo primo pensiero è spesso
quello di cercare di immagazzinare valori multipli in un singolo campo di database, come
mostrato nella figura 5.3.
Figura 5.3. Mai sovraccaricare il campo di una tabella per immagazzinare valori multipli, come
viene fatto qui.
Mentre questo potrebbe funzionare per recuperare un singolo indirizzo e-mail da un database, in questo caso avremmo bisogno di spezzare la stringa nel cercare le virgole (o qualsiasi
altro carattere speciale abbiate scelto come separatore) – un’operazione non tanto semplice e
potenzialmente molto onerosa in termini di tempo. Provate a immaginare un codice PHP
necessario per rimuovere uno specifico indirizzo e-mail da un autore in particolare! In più
dovrete permettere valori molto più lunghi nella colonna e-mail, il che causerebbe uno spreco di spazio sul disco perché la maggior parte degli autori avrebbe comunque un solo indirizzo e-mail.
83
05 PHP e MySQL XP
14-12-2004
0:05
Pagina 84
Creare siti Web con PHP e MySQL
Fate un passo indietro per rendervi conto che questa relazione uno-a-molti è la stessa relazione molti-a-uno che abbiamo visto tra barzellette e autori. La soluzione, quindi, è la medesima:
dividete gli “oggetti” (in questo caso, indirizzi e-mail) nelle loro tabelle. La struttura di database risultante è mostrata nella figura 5.4.
Figura 5.4. Il campo authorid associa ogni riga di email con una riga degli autori.
Usando un join con questa struttura possiamo facilmente avere un elenco degli indirizzi email associati con un particolare autore:
mysql>SELECT email FROM author, email WHERE
->name=”Kevin Yank” AND authorid=author.id;
+-----------------------+
| email
|
+-----------------------+
| [email protected]
|
| [email protected] |
+-----------------------+
2 rows in set (0.00 sec)
Relazioni molti-a-molti
Ora avete pubblicato sul vostro sito Web un database di barzellette che cresce vigorosamente.
Sta crescendo così velocemente, infatti, che il numero di barzellette non è più gestibile. Le persone che visitano il sito hanno a che fare con una pagina gigantesca che contiene centinaia di
barzellette senza alcun tipo di struttura. Qualcosa deve cambiare.
84
05 PHP e MySQL XP
14-12-2004
0:05
Pagina 85
Capitolo 5: Progettazione di database relazionali
Decidete di divider le vostre barzellette in categorie come “Knock-knock” , “Cross the road”,
“Lawyers” e “Political”. Ricordandoci la nostra regola di base citata precedentemente, dovete
identificare le categorie di barzellette come un differente tipo di “oggetto” e creare una nuova
tabella per esso:
mysql>CREATE TABLE category (
-> id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
-> name VARCHAR(255)
->);
Query OK, 0 rows affected (0.00 sec)
Siete arrivati al compito ingrato di assegnare categorie alle vostre barzellette. Capita che una
barzelletta “politica” possa essere anche una barzelletta sull’“attraversamento di strada” e una
barzelletta sul “knock-knock” possa anche riguardare gli avvocati. Una singola barzelletta
potrebbe appartenere a più categorie e ogni categoria conterrà molte barzellette. Questa è una
relazione molti-a-molti.
Molti sviluppatori inesperti, di nuovo, cominceranno a pensare a dei modi per immagazzinare diversi valori in una singola colonna, perché la soluzione ovvia è quella di aggiungere una
colonna di categoria alla tabella delle barzellette e usarla per fare un elenco degli id di quelle
categorie alle quali ogni barzelletta appartiene. Una seconda regola di base potrebbe essere
utile: se avete bisogno di immagazzinare valori multipli in un singolo campo, la vostra progettazione è probabilmente difettosa.
Il modo corretto di rappresentare una relazione molti-a-molti è quello di usare una tabella di
lookup. Questa è una tabella che non contiene alcun dato reale, ma che fa un elenco delle coppie che sono relazionate. La figura 5.5 mostra come dovrebbe apparire la progettazione di
database per le nostre categorie di barzellette.
Figura 5.5. La tabella jokecategory associa coppie di righe dalle tabelle joke e category.
85
05 PHP e MySQL XP
14-12-2004
0:05
Pagina 86
Creare siti Web con PHP e MySQL
La tabella jokecategory associa gli id delle barzellette (jokeid) con gli id delle categorie (categoryid). In questo esempio possiamo vedere che la barzelletta che inizia con “How many
lawyers…” appartiene sia alla categoria “Lawyers” sia a quella “Light bulb”.
Una tabella lookup è creata allo stesso modo in cui è creata ogni altra tabella. La differenza sta
nella scelta della chiave primaria (primary key). Ogni tabella che abbiamo creato fino a qui ha
avuto una colonna chiamata id, che era progettata per essere PRIMARY KEY. Progettare una
colonna come chiave primaria dice a MySQL di non permettere a due record, in quella colonna, di avere lo stesso valore e velocizza anche le operazioni di unione basate su quella colonna.
Nel caso di una tabella di lookup non c’è una singola colonna che vogliamo forzare ad avere
valori univoci. Ogni id di barzelletta appare più di una volta, poiché ogni barzelletta può
appartenere a più di una categoria e ogni id di categoria può apparire più di una volta, in
quanto ogni categoria può contenere molte barzellette. Quello che non vogliamo è che la stessa coppia di valori appaia nella tabella due volte. E, visto che l’unico motivo di questa tabella
è quello di facilitare i join, il beneficio di velocità offerto da una chiave primaria sarebbe molto
utile. Per questa ragione di solito si creano tabelle lookup con chiave primarie a più colonne,
come la seguente:
mysql>CREATE TABLE jokecategory (
-> jokeid INT NOT NULL,
-> categoryid INT NOT NULL,
-> PRIMARY KEY(jokeid, categoryid)
->);
Questo codice crea una tabella in cui le colonne jokeid e categoryid insieme formano la chiave primaria. Ciò rafforza l’univocità che è appropriata per un tabella lookup, prevenendo che
una stessa barzelletta sia assegnata a una categoria particolare più di una volta e velocizzando
i join che fanno uso di questa tabella.
Ora che la vostra tabella lookup è al suo posto e contiene gli assegnamenti della categoria,
potete usare un join per creare diverse query. La query seguente farà un elenco di tutte le barzellette nella categoria “Knock-knock”:
mysql>SELECT joketext
->FROM joke, category, jokecategory
->WHERE name=”Knock-knock” AND
->categoryid=category.id AND jokeid=joke.id;
La query seguente mostra un elenco delle categorie che contengono barzellette che iniziano
per “How many lawyers…”:
mysql>SELECT name
->FROM joke, category, jokecategory
->WHERE joketext LIKE “How many lawyers%”
->AND categoryid=category.id AND jokeid=joke.id;
86
05 PHP e MySQL XP
14-12-2004
0:05
Pagina 87
Capitolo 5: Progettazione di database relazionali
E questa query, che fa anche uso della nostra tabella degli autori per fare un’unione di quattro tabelle, fa un elenco dei nomi di tutti gli autori che hanno scritto barzellette della categoria “Knock-knock”:
mysql>SELECT author.name
->FROM joke, author, category, jokelookup
->WHERE category.name=”Knock-knock”
->AND categoryid=category.id AND jokeid=joke.id
->AND authorid=author.id;
Riepilogo
In questo capitolo abbiamo spiegato i fondamentali di una buona progettazione di database e
abbiamo imparato come MySQL e, per quello che ci interessava, tutti i sistemi di gestione dei
database relazionali forniscono supporto per la rappresentazione di differenti tipi di relazioni tra entità. Dall’iniziale comprensione delle relazioni uno-a-uno abbiamo espanso la nostra
conoscenza fino a includere relazioni molti-a-uno, uno-a-molti e molti-a-molti.
Durante ciò avete appreso nuove caratteristiche di comandi SQL. In particolare avete imparato a usare la query SELECT per fare un’unione di dati sparsi in tabelle multiple in una singola serie di risultati. Nel Capitolo 6, Un Content Management System, imparerete a utilizzare
tutto quello che avete imparato, insieme a nuovi trucchi, per costruire un content management system in PHP. Lo scopo di un sistema del genere è quello di fornire un’interfaccia personalizzata e basata sul Web, che gestisca i contenuti del database, anziché obbligarvi a digitare manualmente tutte le cose dalla riga di comando MySQL.
87
05 PHP e MySQL XP
14-12-2004
0:05
Pagina 88