In Database esistono due metodi degni di nota: Execute ed ExecuteSQL, entrambi eseguono query SQL, ma solo query che non ritornano record, ad esempio DELETE o UPDATE
Un esempio di Excute e di ExecuteSQL è questo
MyDb.Execute "UPDATE Impiegati SET Stipendio=4000000 WHERE Anni>=20 AND Contributi>=58000000"
Dim Lines As Long
Lines=MyDb.ExecuteSQL("DELETE FROM Impiegati WHERE Anni=36")
Le due query hanno ovviamente un significato diverso, ma sono anche eseguite da metodi diversi
Iniziamo comunque a dire che la prima query assegna il valore 4.000.000 al campo Stipendio della tabella Impiegati se gli Anni sono 20 o più e i contributi sono maggiori o uguali a 58.000.000
La seconda invece elimina dalla stessa tabella tutti i record dove Anni vale 36
La cosa che però ci interessa maggiormente notare è che Execute() non ritorna nulla, mentre ExecuteSQL() ritorna un Long che indica il numero di Record influenzati dalla Query, cioè nel nostro caso il numero di record cancellati
Interessante, no?
Ma come ogni cosa ci sono i pro e i contro, perchè usare questi metodi richiede la conoscenza di SQL che è comunque trattato nella Guida in Linea di VB
A questo punto però ci possiamo chiedere come creare query che ritornino valori come SELECT?
La risposta è in un figlio di Database, RecordSet
SELECT * FROM Editori WHERE ScriveLibri='1'
Ottenere risposta da questa query è molto facile, basta usare un metodo di Database e l'oggetto Recordset
Dim MyRecordSet As RecordSet
Set MyRecordSet=MyDb.OpenRecordSet("SELECT * FROM Editori WHERE ScriveLibri=1")
Questo codice non fa altro che creare un Recordset che contiene tutti i record di Editori dove ScriveLibri è uguale ad 1
Facile, vero?
Ricordate però una cosa, questo RecordSet non è fisicamente presente nel Database, cioè una volta scritta questa linea di codice
Set MyRecordSet=Nothing
la tabella non esiste più, ma anche a questo problema c'è una soluzione, nel caso ci interessi la Tabella possiamo fare 2 cose
il metodo più ovvio è un QueryDef che si aggiorna anche nel caso la tabella Editori cambi, ma siccome in questa puntata voglio trattare i TableDef opteremo per la seconda soluzione
Iniziamo con il decidere la struttura di Editori
Nome=Text
AnnoNascita=DateTime
LibriPubblicati=Memo
FatturatoUltimoAnno=Currency
ScriveLibri=Intero
Adesso ci serve una tabella chiamati QueryEditori che creeremo con le seguenti istruzioni
Dim Table As TableDef
Set Table=MyDb.CreateTableDef("QueryEditori")
...'Codice per creare i campi
MyDb.TableDefs.Append Table
Questo codice è tutto quello che serve per creare un TableDef cioè un modello di Tabella e aggiungerlo al Database
Ma tra questo e la tabella QueryEditori finale c'è ancora molto lavoro da fare, cioè aggiungere i record
Dim MyField As Field
...'Impostazione del campo
Table.Fields.Append MyField
Come al solito il meccanismo degli insiemi ci ha ridotto di molto il lavoro, ma qualcosa da fare c'è ancora, MyField è ancora un oggetto vuoto, bisogna dargli un nome e un tipo di dati, dovete però sapere che la creazione dei record è un compito così ripetitivo e noioso che ci conviene creare una routine AggiungiCampo() che faccia il lavoro al posto nostro
Public Sub AggiungiCampo(Tabella As TableDef, Campo As Field, Nome _
As String, TipoDati As Integer)
Dim MyField As Field
'Impostazione del campo
Tabella.Fields.Append MyField
End Sub
Adesso passiamo al codice mancante, Impostazione del campo
Public Sub AggiungiCampo(Tabella As TableDef, Nome _
As String, TipoDati As Integer, Optional Dimensione)
Dim MyField As Field
If IsMissing(Dimensione) Then
Set MyField=Tabella.CreateField(Nome, TipoDati)
Else
Set MyField=Tabella.CreateField(Nome, TipoDati, Dimensione)
End If
Tabella.Fields.Append MyField
End Sub
Se il fatto che Dimensione sia Optional vi stupisce sappiate che è giusto che sia così, poichè alcuni campi ignorano l'argomento durante la creazione e pertanto inserirlo sarebbe solo uno spreco di Byte nello Stack
Adesso che abbiamo la nostra brava AggiungiCampo() possiamo anche usufruirne
AggiungiCampo(Table, "Nome", dbText)
AggiungiCampo(Table, "AnnoNascita", dbDate)
AggiungiCampo(Table, "LibriPubblicati", dbMemo)
AggiungiCampo(Table, "FatturatoUltimoAnno", dbCurrency)
AggiungiCampo(Table, "ScriveLibri", dbInteger)
MyDb.TableDefs.Append Table
Adesso posso anche dirvi che abbiamo sprecato 1 byte creando la tabella perchè l'ultimo campo poteva essere dbBoolean invece di dbInteger, c'è un modo di modificarlo, sì, ma richiede di eliminare e ricreare la tabella, pertanto ecco come eliminare la tabella
MyDb.TableDefs.Delete("QueryEditori")
il quale metodo elimina l'oggetto "QueryEditori" dell'insieme TableDefs del Database
Però questo comporta anche la creazione di una nuova "Editori" con questo campo corretto, pertanto lasciamo ScriveLibri ad Integer e da questo traiamo una regola, quando si crea un Database bisogna sedersi a tavolino e pensare alla struttura del Database ore ed ore prima di scrivere anche e solo una linea di codice
Adesso abbiamo tutte e due le tabelle e possiamo aprirle
Dim QueryEditori As RecordSet
Dim Editori As RecordSet
Set QueryEditori=MyDb.OpenRecordSet("QueryEditori")
Set Editori=MyDb.OpenRecordSet("Editori")
Da questo codice otteniamo le due tabelle aperte e pronte per le operazioni
A questo punto siamo pronti per iniziare
BeginTrans
Do Until Editori.Eof
QueryEditori.AddNew
QueryEditori("Nome")=Editori("Nome")
QueryEditori("AnnoNascita")=Editori("AnnoNascita")
QueryEditori("LibriPubblicati")=Editori("LibriPubblicati")
QueryEditori("FatturatoUltimoAnno")=Editori("FatturatoUltimoAnno")
QueryEditori("ScriveLibri")=Editori("ScriveLibri")
QueryEditori.Update
Loop
CommitTrans
Cosa significa tutto questo?
Semplice, che finchè Editori non arriva all'ultimo record ogni suo campo deve essere trasferito a QueryEditori, BeginTrans e CommitTrans indicano una transazione ed è buona norma inserirle prima di ogni modifica al DB, BeginTrans prima e CommitTrans dopo
Questo sembra proprio ciò che ci serve, ma in effetti non lo è perchè noi volevamo copiare i risultati della Query, pertanto dobbiamo cambiare il codice che apre Editori in:
Set MyRecordSet=MyDb.OpenRecordSet("SELECT * FROM Editori WHERE ScriveLibri=1")
Adesso tutto funzionerà alla perfezione tranne che ad ogni cambiamento di Editori dovremo ricordarci di eseguire questo codice, esiste poi un metodo più generico per copiare due tabelle con record uguali
BeginTrans
Do Until Editori.Eof
QueryEditori.AddNew
Dim FieldCounter As Integer
For FieldCounter=0 To Editori.Fields.Count-1
QueryEditori(FieldCounter)=Editori(FieldCounter)
QueryEditori(FieldCounter)=Editori(FieldCounter)
QueryEditori(FieldCounter)=Editori(FieldCounter)
QueryEditori(FieldCounter)=Editori(FieldCounter)
QueryEditori(FieldCounter)=Editori(FieldCounter)
QueryEditori.Update
Next FieldCounter
Loop
CommitTrans
Questo codice si basa sul meccansimo degli insiemi e degli insiemi predefinti, in quanto QueryEditori(FieldCounter) è uguale a QueryEditori.Fields(FieldsCounter) che a sua volta è uguale a QueryEditori.Fields.Item(FieldCounter) poichè ogni insieme dispone di un metodo Item che ritorna un elemento in base ad un indice, ciò per mezzo di una enumerazione, ma questo non ci riguarda direttamente, ci basti sapere che Editori.Fields.Count è conseguenza diretta dell'esistenza dell'enumerazione
Questo codice che può servire anche in lezioni successive ci conviene salvarlo in una routine di nome CopiaTabelle() così definita
Public Sub CopiaTabelle(QueryEditori As RecordSet, Editori As RecordSet)
'Codice già scritto
QueryEditori.Close
Editori.Close
End Sub
Le ultime due linee di codice aggiunte prima di End Sub chiudono la tabella QueryEditori e quella Editori, ma volendo potrebbero anche usare il metodo MoveFirst per riposizionare il Jet sul primo record
QueryEditori.MoveFirst
Editori.MoveFirst
Tra i due metodi esiste una grande differenza, cioè che il primo chiude le tabelle, il secondo permette invece di ricominciare subito a leggervi e scrivervi