Il database e, in particolare, il database basato sul modello relazionale, è una delle strutture dati più utilizzate per conservare e recuperare informazioni.
Esistono tante implementazioni di questo modello relazionale, tra queste c’è la libreria software SQLite, scritta in linguaggio C ed integrata nella distribuzione standard del linguaggio Tcl.
L’ideatore e l’autore originario della libreria SQLite è Dwayne Richard Hipp che ha fatto parte anche del Tcl Core Team.
Tcl ha una interfaccia unica (TDBC: Tcl Database Connectivity) che gli permette di interfacciarsi anche con altri sistemi di database SQL.
Procedura
Per lavorare con un database si procede per passi.
Step #1 – connessione al database
Come prima cosa dobbiamo caricare la libreria sqlite3 e connetterci al database con il comando omonimo sqlite3.
# esempio
package require sqlite3
sqlite3 db ./monitoring.sqlite
Il comando sqlite3 fa parte della libreria (package) sqlite3 e serve per aprire un database esistente o per crearne uno nuovo.
Il comando sqlite3 crea il nuovo comando db che utilizzeremo per interagire con il database il cui nome e posizione vengono definiti nel secondo argomento ./monitoring.sqlite.
Se si vuole memorizzare i dati in memoria invece che in un file sul disco, occorre specificare come identificativo del database l’etichetta
memory.
Step #2: creazione della Tabella
Il database inizialmente è vuoto, quindi come prima cosa dobbiamo creare una Tabella.
Per creare una Tabella dobbiamo utilizzare il sottocomando eval che informa l’interprete Tcl di valutare un successivo comando: nel nostro caso sarà un comando SQL.
db eval {CREATE TABLE mondata( station text, date int, salinity real, temperature real )}
In SQLite l’informazione relativa alla data è un valore intero: in pratica è il valore in secondi restituito dal comando
clock scan(vedi l’articolo Ora e Data).
Step #3a: inserimento di un record
Ora possiamo inserire nel nostro database appena creato un record di dati.
db eval {INSERT INTO mondata VALUES($station,$seconds,$salinity,$temperature)}
L’utilizzo della notazione $nomeVariabile mostra la perfetta integrazione tra SQLite e il linguaggio Tcl.
Step #3b: inserimento di più records
Se si devono inserire pochi records possiamo procedere come fatto nell’esempio più sopra, ma se abbiamo la necessità di inserire molti records è meglio sfruttare la funzione SQLite BEGIN TRANSACTION:
db eval {BEGIN TRANSACTION}
... insert records in a loop
db eval {COMMIT TRANSACTION}
Questa modalità riduce la quantità di carico elaborativo dovuta al controllo dell’integrità dei dati.
Step #4 – chiusura del database
Una volta finito di lavorare con il nostro database lo potremo chiudere con il comando close.
# chiusura del database
db close
Oltre alla chiusura del database, viene cancellato il comando db.
Esempio completo
Creazione e popolamento dei dati
Uniamo ora le varie parti che abbiamo visto in un esempio dove andremo a creare una Tabella (ovvero il database), leggere un file di testo nel formato CSV ed inserire i vari records nella Tabella.
# caricamento della libreria sqlite3
package require sqlite3
# crea il comando db che farà riferimento al database ./monitoring.sqlite
sqlite3 db ./monitoring.sqlite
# crea la Tabella con tre colonne
db eval {CREATE TABLE mondata( station text, date int, salinity real, temperature real )}
# legge il file CSV contenente i dati
set infile [open "monitoring.csv"]
# salta la prima riga contenente i titoli delle colonne
gets $infile line
# inizia la procedura di lettura dei dati e loro inserimento nel database
db eval {BEGIN TRANSACTION}
while { [gets $infile line] >= 0 } {
lassign [split $line ,] station date salinity temperature
set seconds [clock scan $date]
db eval {INSERT INTO mondata VALUES($station,$seconds,$salinity,$temperature)}
}
db eval {COMMIT TRANSACTION}
Produzione di un report
Ora non resta che lavorare con i dati memorizzati nel database.
SQLite ha diverse funzioni interne che possiamo utilizzare direttamente: per esempio la funzione per ottenere la media tra più valori avg() e quella per ottenere il valore massimo max().
db eval {SELECT station, avg(salinity), avg(temperature) FROM mondata GROUP BY station} {
puts "[format "%20s %6.2f %6.2f" $station $avg(salinity) $avg(temperature)]"
}
Questa porzione di codice scorre l’intero database, applicando le due funzioni che abbiamo visto, ed infine stampa il report.
Da notare che i nomi delle colonne presenti nella istruzione
SELECTsono implicitamente convertiti in variabili Tcl.
Dai prossimi articoli cominceremo a trattare il tema della introspezione. Cominceremo vedendo come verificare l’esistenza di procedure, comandi, funzioni matematiche e variabili.