Normalizzazione tabelle
Gli argomenti di questa pagina
|
In tutte le nostre prove abbiamo bisogno di questo file che mettiamo nella cartella res e che contiene tutte le credenziali per connetterci al nostro DB.
1
|
<?php
|
Normalizzazione delle tabelle
Il problema di questo esempio è l'opposto del precedente.
In questo esempio vorrei partire da una tabella dove ho memorizzato una semplice rubrica, esportando i dati in due altre tabelle correlate fra loro.
Immaginiamo di avere questa tabella chiamata sql_rubrica.
id, codice, cognome, nome, indirizzo, cap, citta, prov, data_nascita, telefono
Da una rapida occhiata all'elenco dei campi è possibile notare che possiamo tirar fuori dalla tabella i campi cap, citta, prov e metterli in altra tabella: sql_citta.
Per non correre il rischio di derdere i dati con qualche operazione errata viene creata una nuova tabella chiamata sql_agenda copiandovi i campi della tabella aql_rubrica e, al posto dei campi cap, citta, prov, mettiamo un un campo id_citta che faccia riferimento al campo ID della tabella sql_citta come è visibile qui in basso.
Questo fatto porterà ad alcuni vantaggi:
In fase di registrazione o di modifica della tabella sql_agenda basterà indicare il solo id relativo a cap, citta, prov della tabella sql_citta (id_citta).
Se durante una registrazione o modifica sbagliamo l'associazione o l'ortografia di cap, citta, prov, basterà modificarli nella sola tabella sql_citta evitando di trovare eventuali errori in tutta la tabella.
Viene evitato che a più contatti della stessa città vengano attribuiti cap o provincia errati.
Nella normalizzazione delle tabelle potremmo scendere anche più a fondo, andando magari a valutare la estrapolazione dei telefoni, ma per il momento possiamo anche fermarci a questo punto.
id, cap, citta, prov
I campi della tabella: sql_agenda
id, cognome, nome, indirizzo, id_citta, data_nascita, telefono
Struttura delle tabelle normalizzate
Vediamo ora la struttura che potrebbero avere le tabella da creare.
In queste due tabelle, oltre agli ID presenti in entrambe, ed ai campi specifici di ciascuna tabella, c'è da notare il campo "id_citta" della tabella "sql_agenda". Questo campo serve da collegamento tra la tabella "sql_agenda" e la tabella "sql_citta"e vi sarà inserito l'ID della tabella "sql_citta".
Quando si inserisce un nuovo utente nella tabella "sql_agenda", invece di mettere cap, citta e prov è sufficiente mettere il solo ID relativo al record di questi tre campi.
I campi della tabella sql_citta
|
I campi della tabella sql_agenda
|
I files .sql che si useranno per la creazione delle tabelle
La creazione delle nuove tabelle non possiamo farlo col metodo visto nella pagina "Duplicare tabella e dati", Ma dovremmo servirci di una Query o dei files .sql.
Queste mostrate qui sotto potrebbero essere i due files .sql necessari alla creazione delle due tabelle.
Per far questo occorre che ci procuriamo due files con estensione .sql adatte a creare le due tabelle che ci occorrono.
1
|
-- phpMyAdmin SQL Dump
|
1
|
-- phpMyAdmin SQL Dump
|
Metodi per creazione delle tabelle
Per creare le nuove tabelle di cui necessitiamo possiamo seguire diverse strare di cui queste potrebbero esserne alcune:
- creazione delle nuove tabelle attraverso il pannello di controllo di phpmyadmin usando i files .sql
- creazione delle tabelle unsando i files .sql ed un breve script PHP
- Creazione delle tabelle attraverso delle Query "CREATE TABLE" create ad hoc
Caso 1: creare le tabelle da pannello di controllo di phpmyadmin
Una volta in possesso dei due files .sql possiamo recarci al pannello di controllo di phpmyadmin ed importiamo i due files come indicato in questa immagine.
Caso 2: creare le tabelle con script PHP
Per creare le due tabelle tramite script PHP possiamo usare il codice visibile qui in basso, nel riquadro sottostante.
Questo script inizia, come il solito, con l'inclusione del file db_login.php.
Dal nome della tabella individua il file .sql.
Una volta eseguita la connessione al DB, legge il contenuto el file .sql mettendo tutte le righe del file nella matrice $file_content (riga 13)
Nelle righe seguenti scorre le righe della matrice e, se la riga è valida, ci crea la Query che poi userà alla riga 21
Questo script va usato una volta per ogni tabella si intende creare, quindi, in questo caso, va usato due volte o, quanto meno, andrebbero duplicate le righe che vanno dalla 13 alla 29, cambiando ogni volta il nome della tabella.
Per risparmiare codice e per lasciare lo script così come si trova possiamo agire in questo modo:
Lo script va salvato in un file chiamato "create_table_to_file.php" o con altro nome: in questo caso dobbiamo cambiare anche gli include che si vedono nel riquadro di destra.
Nella pagina che useremo per creare le due tabelle scriveremo le poche righe che si trovano nel riquadro di destra. In questo frammento di codice definiamo le due tabelle e, per ciascuna di esse, eseguiamo un include della pagina che crea la tabella.
1
|
<?php
|
Nella pagina che dovrà creare le tabelle
1
|
<?php
|
Caso 3: uso di Query CREATE TABLE per creare le tabelle
Le Query visibili qui sotto hanno bisogno di questi elementi:
- l'istruzione CREATE TABLE
- l'indicazione di tutti gli elementi (campi) da inserire nella tabella a cui dobbiamo assegnare:
- un nome
- due proprietà:
- il tipo di dato che dovrà ospitare
- il valore Null o Not Null
- per il campo ID abbiamo altre due proprità aggiuntive
- auto_increment
- la qualifica di PRIMARY KEY
- il tipo di ENGINE impostato a MyISAM
- infine viene indicato il CHARSET e da quale numero inizia l'AUTO_INCREMENT
Detto questo possiamo creare le nostre Query per creare le due tabelle necessarie.
1
|
<?php
|
1
|
<?php
|
Per eseguire queste due query è sufficiente usare queste poche righe di codice:
1
|
<?php
|
Importazione dei dati: INSERT e subquery
Dopo aver creato le strutture delle due tabelle con uno dei metodi appena visti possiamo pensare di trasferire i dati dalla tabella originale alle due nuove tabelle. Possiamo pensare di farlo manualmente oppure creare due Query speciali che provvedono a trasferire in maniera automatica i dati prelevandoli dalla tabella originale.
La sintassi per eseguire questa operazione si usa questa sintassi:
(SELECT elenco campi from tab_origine)
dove elenco campi indicato nella clausola INSERT è facoltativo se tutti i campi della tab_destinazione coincidono con tutti i campi della tab_origine. Ma se vengono indicati i campi nella clausola INSERT gli stessi campi debbono essere mensionati anche nella clausola SELECT
Questi tipi di Query sono molto delicate ed il buon esito della loro esecuzione dipende da come viene istruita la subquery SELECT. E' per questo motivo che prima di eseguire una Query INSERT è buona norma creare e testare la subquery SELECT.
INSERT e subquery per la tabella sql_citta.
In questa Query:
Si inizia nel modo classico:
INSERT INTO sql_citta (cap, citta, prov)
Nella seconda parte della Query iniziamo a costruire la subquery SELECT
Nella subquery SELECT vengono indicati i campi nello stesso ordine usato nella istruzione INSERT INTO. Viene usata la clausola DISTINCT per selezionare uno solo degli eventuali record duplicati che verrebbero restituini nel recordset ed alla fine viene usata anche la clausola ORDER BY (anche se in questo caso è ininfluente) per ottenere un recordset ordinato da memorizzare nella tabella.
1
|
<?php
|
Importazione dei dati nella tabella sql_agenda: INSERT e subquery
Ora si può passare alla tabella sql_agenda.
Questa seconda Query è più complessa di quella appena vista. Vediamo ora se riusciamo a spiegarne il senso.
Si inizia la Query alla solita maniera:
INSERT INTO sql_agenda (cognome, nome, indirizzo,........., id_citta)
A questo punto, per prelevare anche l'ID della città da memorizzare nel campo id_citta, dobbiamo creare una SELECT che restituisca nei record del recordset tutti i campi descritti nella istruzione SELECT prelevandoli dalla tabella di origine sql_rubrica e l'ID dalla tabella sql_citta tramite una JOIN tra le due tabelle. Quindi:
Nella istruzione SELECT specifichiamo tutti i campi necessari qualificandoli (un campo qualificato si ha quando davanti al suo nome è presente anche il nome della tabella seguito da un punto).
Per semplificare la scrittura delle istruzioni nella clausola FROM viene dato un alias al nome della tabella sql_rubrica.
Subito dopo la clausola FROM viene impostata la INNER JOIN per creare il collegamento con la seconda tabella. Dopo la JOIN viene specificata la clausola ON per definire la condizione di JOIN.
In questa ultima clausola vengono definite tre condizioni:
dalla tabella sql_citta viene prelevato l'ID solo se c'è corrispondenza tra il cap, la citta e la provincia della tabella sql_citta e della tabella sql_rubrica.
1
|
<?php
|
Gli effetti delle operazioni compiute
Qui sotto vengono mostrati i contenuti delle tre tabelle su cui abbiamo lavorato.
Questa è la tabella sql_rubrica che abbiamo usato per generare le altre due tabelle. Per comodità, delle tabelle più grandi, mostriamo solo alcuni dei campi ed i primi record e non tutti i campi perchè ovvi.
trovati 101 record
15 record visualizzati
id | codice | cognome | nome | indirizzo | cap | citta | prov | data_nascita | telefono |
---|---|---|---|---|---|---|---|---|---|
1 | 201_parente_000 | Migliavacca | Luigi | VIA P. FIMIANI TRIVIO | 35031 | Varena | AE | 2004-01-22 | 084 41655 |
2 | 002_fam_010 | Rizzi | Carlo | VIA SABIN, 34/2 | 35031 | Varena | AE | 2007-11-22 | 07 9940508 |
3 | 002_fam_020 | Liberali | Franca | VIA DEL TUSCOLANO, 1 | 67030 | Abbadia Lariana | AB | 2004-02-20 | 036 348719 |
4 | 003_fam_001 | Di Maggio | Mario | TERMINAL CONTENITORI MOLO VII | 51021 | Ville di Fano | RF | 2009-05-21 | 051 18752 |
5 | 003_fam_002 | Scicchitano | Andrea | VIA SABIN, 34/2 | 51021 | Ville di Fano | RF | 1997-01-12 | 07 74891 |
6 | 003_fam_010 | Edelvisi | Maurizio | VIA MATTEO RICCI, 12 | 51021 | Ville di Fano | RF | 1987-07-02 | 079 89428 |
7 | 003_fam_020 | Gerardini | Silvano | Z.I SAMBUCETO | 51021 | Ville di Fano | RF | 2009-08-12 | 012 164848 |
8 | 500_conosc_000 | Pasotti | Alessio | VIA SABIN, 34/2 | 22050 | Correzzana | FS | 1987-11-14 | 05 9552713 |
9 | 004_fam_001 | Calvi | Giovanni | VIA SABIN, 34/2 | 53021 | Marsiliana | AB | 1987-07-26 | 044 5602773 |
10 | 004_fam_002 | Poggi | Giuseppe | VIA SABIN, 34/2 | 67030 | Abbadia Lariana | AB | 1987-01-25 | 08 0640120 |
11 | 004_fam_010 | Curti | Oreste | STRADA MARCHESANE, 43_4 | 51021 | Ville di Fano | RF | 1988-06-26 | 027 42781 |
12 | 004_fam_021 | Borsotti | Mirella | VIA DEL TUSCOLANO, 1 | 51021 | Ville di Fano | RF | 1987-07-19 | 09 379786 |
13 | 004_fam_020 | Franchinotti | Anna | VIA BREDINA, 6 | 67030 | Abbadia Lariana | AB | 2009-05-10 | 062 8880 |
14 | 500_conosc_000 | Pischedda | Giovanni | VIA MATTEO RICCI, 12 | 22059 | Falconara Alta | FS | 1999-08-08 | 07 628585 |
15 | 004_fam_030 | Maini | Marilena | MACRON TICHON STREET, 27 | 57020 | Borgo S. Dalmazzo | BO | 2002-03-20 | 02 6638 |
Le due tabelle qui sotto sono state valorizzate coi dati prelevati dalla tabella sorgente dei dati. Si può notare che mentre la tabella sql_citta ha i campi cap, citta, prov già presenti nella tabella sorgente, la tabella sql_agenda ha molti dei campi della tabella sorgente ma, invece dei campi cap, citta, prov ha solo un id_citta. Questo campo serve per collegarla alla tabella sql_citta tramite il suo ID.
La tabella sql_citta trovati 38 record 15 record visualizzati
|
La tabella sql_agenda trovati 103 record 15 record visualizzati
|
La tabella qui sotto mostra come impiegare le due tabelle appena create per ottenere le informazioni come dalla tabella originale.
Tramite una JOIN preleva i dati da entrambe le tabelle basandosi sui campi id_citta della tabella sql_agenda e id della tabella sql_citta. Sulle JOIN parleremo in sede a parte nel settore delle SELECT. In questa sede la usiamo solo per mostrare quel che possiamo ottenere unendo due tabelle relazionate.
La colonna id_citta che si vede nella tabella, normalmente, negli usi comuni, non viene mostrata. Qui invece ho preferito mostrarla per poter effettuare le comparazioni visive tra le varie tabelle.
Questa tecnica della JOIN verrà mostrata in una delle pagine seguenti, ma qui ne facciamo una anticipazione con questo frammento di codice dove viene usata la Query che esegue la JOIN tra le due tabelle sql_agenda e sql_citta.
Qui di seguito un esempio di Query che usa la tecnica della JOIN tra le due tabelle
1
|
<?php
|
Lo script usato è quello che viene usato per una qualsiasi Query SELECT
1
|
<?php
|
Il codice appena visto produce una cosa del genere (ovviamente la tabella è ridotta per motivi di spazio).
trovati 103 record
15 record visualizzati
cognome | nome | indirizzo | id_citta | cap | citta | prov | nato | telefono |
---|---|---|---|---|---|---|---|---|
Migliavacca | Luigi | VIA P. FIMIANI TRIVIO | 21 | 38030 | Varena | TN | 22-01-2004 | 084 41655 |
Rizzi | Carlo | VIA SABIN, 34/2 | 21 | 38030 | Varena | TN | 22-11-2007 | 07 9940508 |
Liberali | Franca | VIA DEL TUSCOLANO, 1 | 2 | 23821 | Abbadia Lariana | LC | 20-08-2004 | 036 348719 |
Di Maggio | Mario | TERMINAL CONTENITORI MOLO VII | 22 | 67010 | Ville di Fano | AQ | 21-05-2009 | 051 18752 |
Scicchitano | Andrea | VIA SABIN, 34/2 | 22 | 67010 | Ville di Fano | AQ | 12-01-1997 | 07 74891 |
Edelvisi | Maurizio | VIA MATTEO RICCI, 12 | 22 | 67010 | Ville di Fano | AQ | 02-07-1987 | 079 89428 |
Gerardini | Silvano | Z.I SAMBUCETO | 22 | 67010 | Ville di Fano | AQ | 12-08-2009 | 012 164848 |
Pasotti | Alessio | VIA SABIN, 34/2 | 13 | 20050 | Correzzana | MB | 14-11-1987 | 05 9552713 |
Calvi | Giovanni | VIA SABIN, 34/2 | 18 | 58010 | Marsiliana | GR | 26-07-1987 | 044 5602773 |
Poggi | Giuseppe | VIA SABIN, 34/2 | 2 | 23821 | Abbadia Lariana | LC | 25-01-1987 | 08 0640120 |
Curti | Oreste | STRADA MARCHESANE, 43_4 | 22 | 67010 | Ville di Fano | AQ | 26-06-1988 | 027 42781 |
Borsotti | Mirella | VIA DEL TUSCOLANO, 1 | 22 | 67010 | Ville di Fano | AQ | 19-07-1987 | 09 379786 |
Franchinotti | Anna | VIA BREDINA, 6 | 2 | 23821 | Abbadia Lariana | LC | 10-05-2009 | 062 8880 |
Pischedda | Giovanni | VIA MATTEO RICCI, 12 | 14 | 60015 | Falconara Alta | AN | 08-08-1999 | 07 628585 |
Maini | Marilena | MACRON TICHON STREET, 27 | 6 | 12011 | Borgo S. Dalmazzo | CN | 20-03-2002 | 02 6638 |