Mastodon

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 SELECT sono 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.