3. TabQuery

Tabelle e Query

3.1   Riallegare tabelle 3.11 Numero/somma incrementale nelle query
3.2   Reinizializzare campi contatori 3.12 Creare una lista di compleanni
3.3   Funzioni come valori predefiniti 3.13 Non funzionano i criteri di data
3.4   Controllare se esiste una tabella 3.14 Criterio che restituirà tutti i record
3.5   Cambiare il tipo dati di un campo via codice 3.15 Come usare le variabili nelle query
3.6   Record troppo grande 3.16 Record di A non presenti in B
  3.17 Realizzare un ordine casuale di record
  3.18 Parametri nelle query a campi incrociati
  3.19 Distinguere tra maiuscole e minuscole
   
3.1 Riallegare tabelle
http://www.donkarl.com/it?FAQ3.1 aggiornato 2014-01-04

Problema

Un MDB ha tabelle collegate. Se la directory del database con le tabelle originali cambia, si perde la connessione.

Soluzione

Il metodo più semplice è, chiaramente, quello di cancellare i collegamenti delle tabelle e riallegarle dalla voce di menu File/Carica dati esterni/Collega tabelle.

Un altro modo è quello di usare il Gestore tabelle collegate che puoi trovare in menu Strumenti/Utilità database.

Se vuoi riallegare le tabelle in maniera dinamica con VBA, puoi usare un file dialogo ed il codice, come viene mostrato in
http://www.mvps.org/access/tables/tbl0009.htm

Una soluzione completa con un file dialogo ed anche per backend multipli offre il JStreet Access Relinker: http://www.jstreettech.com/downloads.aspx

Se sei sicuro, che entrambi i database sono sempre nella stessa directory, puoi completamente automatizzare il ricollegamento via VBA. Richiama, nella macro autoexec o nell'evento Su apertura della tua maschera d'avvio, un codice come segue:

'******* INIZIO CODICE *******
On Error GoTo MyError

Dim db As DAO.Database
Dim strDaten As String
Dim i as Integer

Set db = CurrentDB()

strDaten = Left(db.Name, Len(db.Name) - Len(Dir(db.Name))) & "TuoDato.mdb"

For i = 0 To db.TableDefs.Count - 1
  If db.TableDefs(i).Connect <> "" Then
    If Mid(db.TableDefs(i).Connect, 11) <> strDaten Then
      db.TableDefs(i).Connect = ";database=" & strDaten
      db.TableDefs(i).RefreshLink
    End If
  End If
Next i

MyExit:
  Exit Sub

MyError:
  MsgBox "Un problema è accaduto durante l'installazione. ", 16, "Eccezione"
  Resume MyExit

'******* FINE CODICE *******

in alto

3.2 Reinizializzare campi contatori
http://www.donkarl.com/it?FAQ3.2 aggiornato 2008-12-17

Problema

In una tabella, vuoi reinizializzare un campo contatore a 1 o al numero libero successivo, dopo che dei record sono stati inseriti e cancellati.

Soluzione

Compattare il database: menu Strumenti/Utilità database/Compatta e ripristina database
Questo, usualmente, reimposta il contatore di tutte le tabelle al numero libero successivo.

Però nelle versioni di Access>=00, spesso ciò non funziona più. Vedi: http://support.microsoft.com/?kbid=287756
Le soluzioni di questo articolo però sono inutilmente complicate, perché da JET4, cioè da A00, si può impostare le proprietà Seed ed Increment di un campo contatore con SQL:

ALTER TABLE NomeTabella ALTER COLUMN NomeCampo COUNTER(1,1)

Il primo numero imposta il valore iniziale a 1, il secondo numero imposta la sequenza a 1 (si può anche ometterlo incl. la virgola)

In genere, i campi Contatore sono destinati per l'uso interno, p. e., essi servono come campi chiave e di relazione, non per ottenere dei bei numeri. Quest'ultimi dovrebbero essere creati via programmazione, quali valori predefiniti o manualmente.

in alto

3.3 Funzioni come valori predefiniti
http://www.donkarl.com/it?FAQ3.3

Problema

Nella proprietà Valore predefinito di un campo in una tabella, vuoi utilizzare una funzione come, p. e., CurrentUser(), o una funzione VBA autodefinita, o un riferimento ad un controllo in una maschera ecc.
Però o la funzione è modificata in testo (Access inserisce " " attorno), o ricevi un messaggio di errore che ti dice che la funzione o il riferimento è sconosciuto o non potrebbe essere riconosciuto, o qualcosa di simile.

Causa

In una tabella il valore predefinito di un campo non può contenere funzioni definite dall'utente, funzioni di aggregazione (DlookUp ecc.) o qualche funzione particolare, come CurrentUser od Eval. La stessa cosa è valida per i riferimenti agli oggetti di Access.

Soluzione

Devi utilizzare le maschere. Solo i controlli nelle maschere permettono di usare le sopracitate funzioni e i riferimenti nella loro proprietà Valore predefinito .

in alto

3.4 Controllare se esiste una tabella
http://www.donkarl.com/it?FAQ3.4

Problema

Vuoi controllare "automaticamente", se in un DB esiste, oppure non esiste, una particolare tabella.

Soluzione

Vi sono vari metodi. P. e., puoi intercettare l'errore che avviene quando richiami una tabella che non esiste. Un metodo più preciso è controllare l'insieme TableDefs. Per fare ciò, puoi copiare il seguente codice in un modulo standard:

Function fctTableExists(strTableName As String) As Boolean

  Dim db As DAO.Database
  Dim tdf As DAO.TableDef
  Set db = CurrentDb
  For Each tdf In db.TableDefs
    If tdf.Name = strTableName Then fctTableExists = True: Exit For
  Next

End Function


Un altro metodo è usare la tabella di sistema MSysObjects:

Function fctTableExists(strTableName As String) As Boolean

  If DCount("*", "MSysObjects", "Name='" & strTableName & "'") Then fctTableExists = True
    
End Function


In ogni caso puoi richiamare la funzione dovunque nel tuo database, in questo modo:
fctTableExists("NomeTuaTabella")

in alto

3.5 Cambiare il tipo dati di un campo via codice
http://www.donkarl.com/it?FAQ3.5

Problema

Vuoi modificare, da programma, il tipo dati o la dimensione di un campo.

Soluzione

Nelle versioni antecedenti A00 questo è solo possibile con codice verboso. Qui vi è un esempio che mostra un tale modo complicato, per modificare il tipo dati di un campo in testo, o modificare la dimensione (del campo) di un campo testo.

'************ INIZIO CODICE ************
Dim db As DAO.Database
'se la tabella è nel database corrente
Set db = CurrentDb
'se la tabella è in un diverso database, p. e., in una situazione Frontend/Backend
'Set db = DBEngine.Workspaces(0).OpenDatabase("c:\Percorso\Diverso.mdb")

'rinominare il campo originale
db.TableDefs("MiaTabella").Fields("MioCampo").Name = "VecchioCampo"

'creare un nuovo campo con le impostazioni desiderate
db.Execute "ALTER TABLE MiaTabella ADD COLUMN MioCampo VARCHAR(100)"

'prendere i vecchi dati
db.Execute "UPDATE MiaTabella SET MioCampo = VecchioCampo"

'cancellare il vecchio campo
db.Execute "ALTER TABLE MiaTabella DROP COLUMN VecchioCampo"

'************ FINE CODICE ************

Con il Jet 4, cioè con le versioni >=A00, questa procedura complicata non è più necessaria. Il comando ALTER TABLE di JET SQL è stato ampliato da ALTER COLUMN (vedi <F1> Help). Così hai soltanto bisogno di una singola linea di codice per portare a termine il compito (utilizzando la variabile db sopra indicata):

db.Execute "ALTER TABLE MiaTabella ALTER COLUMN MioCampo VARCHAR(100)"

in alto

3.6 Record troppo grande
http://www.donkarl.com/it?FAQ3.6

Problema

Quando tenti di salvare un record ricevi l'errore 3047 "Record troppo grande".

Causa

Un record , in una tabella di Access (più di preciso JET), ha un limite di circa 2000 caratteri. Nelle versioni >=A00 questo limite è incrementato fino a circa 4000 caratteri, se la proprietà Compressione Unicode dei campi testo è impostata a . In questo contesto la proprietà Dimensione campo non importa per nulla, ma solo il dato che effettivamente è presente nel record.

Soluzione

I campi Memo non sono inclusi in questo limite, poiché essi sono gestiti in modo diverso. Pertanto, potresti aggirare la limitazione modificando in memo alcuni dei campi testo (quelli con molti dati).

A parte questo, puoi dividere la tabella in diverse tabelle simili, messe in relazione 1:1.

in alto

3.11 Numero/somma incrementale nelle query
http://www.donkarl.com/it?FAQ3.11 aggiornato 2016-09-06

Problema

In una query, vuoi un campo con un numero o una somma incrementale.

Soluzione

Numero Incrementale

Puoi utilizzare una subquery all'interno della tua query per creare un campo contatore. Per far questo, inserisci una stringa SQL, come la seguente, in una nuova colonna della query:

NumIncr: (Select Count (*) FROM [Prodotti] as Temp WHERE [Temp].[Id] < [Prodotti].[Id])+1

L'esempio mostra come creare il campo contatore "NumIncr" in una tabella "Prodotti" con un campo chiave primaria "Id". Se la tua query ha criteri di filtro, o se vuoi ordinare dopo altri campi, la stringa SQL diviene più complessa. In questo caso dai uno sguardo agli esempi nella KB:
articolo KB tedesco

Un'alternativa alla soluzione con la subquery è quella di creare il numero incrementale con DCount:
NumIncr: DCount("Id";"Prodotti";"Id<" & [Id])+1

Le subquery con JET non sono sostanzialmente veloci, e, nonostante le funzioni di aggregazione su dominio, frequentemente proscritte, questo metodo potrebbe risultare più rapido con grandi volumi di dati. Pertanto, è meglio testarlo.

Somma Incrementale

Puoi usare, p. e., la funzione DSum:
Somma incrementale nelle query
Somma incrementale raggruppata nelle query

in alto

3.12 Creare una lista di compleanni
http://www.donkarl.com/it?FAQ3.12

Problema

Vuoi creare una query che, sulla base di un campo data-di-nascita, trovi nella tua tabella quali delle persone, p.e., compirà gli anni tra 10 giorni.

Soluzione

Puoi creare una nuova colonna nella query e trasferire la data di nascita all'anno corrente.
DatNQuestAnno:DateAdd("aaaa";nz(DateDiff("aaaa";[CampoTuaDatN];Date()));[CampoTuaDatN])

Come criterio utilizzi:
Between Date() and Date()+10

Certamente questo metodo mette solo in evidenza i compleanni dell'anno corrente. Se dovrà funzionare anche per il cambio d'anno, puoi creare un secondo campo:
DatNProsAnno: DateAdd("aaaa";nz(DateDiff("aaaa";[CampoTuaDatN];Date()))+1;[CampoTuaDatN])

Il criterio è lo stesso di prima, ma questa volta lo devi mettere una riga più in basso rispetto al criterio precedente, p. e., nella riga "Oppure"

vedi anche *calcolare l'età* e nella KB * *
v.a. Calcolare l'età e l'articolo KB tedesco con DB d'esempio

in alto

3.13 Non funzionano i criteri di data
http://www.donkarl.com/it?FAQ3.13

Problema

Nei criteri di una query, utilizzi una espressione come =Date(), ma la query non restituisce alcun record che, ovviamente, dovrebbe soddisfare i criteri.

Causa

Il più delle volte, l'errore accade poiché nel campo della tabella vi è anche salvato un orario > 00:00. In questo caso, non è importante come sia impostata la proprietà della formattazione del campo. L'ora è sempre riportata assieme. Il problema spesso si crea, se il campo, in qualche parte, è stato caricato con Now(). Se poi questo campo viene confrontato a Date(), esso effettivamente è confrontato all'ora 00:00 del giorno corrente.

Soluzione

Utilizza la funzione Date invece di Now, se vuoi caricare un campo data senza un esplicito valore orario (risp. 00.00)
oppure
Nella query che restituirà tutti i record del giorno corrente, senza considerare un eventuale valore orario corrente, utilizza come criteri:
>= Date() And < Date()+1
oppure
Utilizza come campo nella query: Format([MioCampodata];"ggmmaaaa")
ed i corrispondenti criteri: Format(Date();"ggmmaaaa")

in alto

3.14 Criterio che restituirà tutti i record
http://www.donkarl.com/it?FAQ3.14

Problema

Vuoi utilizzare un criterio per un campo di una query, p. e., un riferimento ad un controllo di una maschera o ad un parametro. Normalmente, i record saranno filtrati secondo questo valore. Comunque, se il criterio è vuoto, o ha un particolare valore (p. e., "*" oppure "Tutti"), allora vuoi che la query restituisca tutti i record.

Soluzione

I seguenti esempi mostrano cosa puoi usare come criterio:

per un controllo di una maschera
[Forms]![MiaMaschera]![MioControllo] Or [Forms]![MiaMaschera]![MioControllo] Is Null

per un parametro vuoto
[MyParameter] Or [MyParameter] Is Null

per l' * (asterisco) in un controllo di una maschera
[Forms]![MiaMaschera]![MioControllo] Or [Forms]![MiaMaschera![MioControllo] = "*"

per un parametro che potrebbe contenere "Tutto"
[MioParametro] Or [MioParametro] = "Tutto"

etc.

Se la parte "Or" del criterio esempio è Vera, allora vengono restituiti tutti i record della query. Altrimenti i record sono filtrati, come al solito, dal valore inserito nella prima parte dell'espressione del criterio.

In una query, questo metodo funziona solo per poche colonne. Se tu hai parecchi criteri, allora Access/Jet potrebbe avere dei problemi ad eseguire la query. In questo caso è meglio creare una stringa SQL via codice, che include il criterio solo se ha un valore. Questo inoltre migliora la dichiarazione SQL e l'esecuzione.

articolo KB tedesco con DB d'esempio

in alto

3.15 Come usare le variabili nelle query
http://www.donkarl.com/it?FAQ3.15

Problema

Vuoi utilizzare una variabile globale in una query, p. e., come criterio o come parte di un campo calcolato. Se tenti, però, di fare ciò, la variabile non è riconosciuta, ma è considerata come stringa o parametro.

Soluzione

Non puoi utilizzare direttamente una variabile in una query. Devi, invece, creare una funzione in un modulo standard, che non fa altro che restituire il valore della variabile. P. e.,

Public Function fctSendVar() 'qui potresti anche specificare il tipo

  fctSendVar = MiaVariabileGlobale

End Function


Nella query, poi, invece della variabile, scrivi il nome della funzione con le parentesi().

A tale proposito, in questo modo puoi anche utilizzare il valore di una variabile come origine controllo di una maschera o report.

in alto

3.16 Record di A non presenti in B
http://www.donkarl.com/it?FAQ3.16

Problema

Hai 2 tabelle "A" e "B", e vuoi trovare quali record sono presenti in A ma non in B.

Soluzione

In modalità Struttura di una query, con le due tabelle collegate su campi opportuni (chiave primaria ed esterna o come tali), fai doppio-click sulla linea di collegamento. Nella finestra di dialogo scegli la seconda opzione, che dice: " Includi tutti i record di A e solo i record di B in cui i campi collegati sono uguali". Trascina l'asterisco * della tabella A alla griglia della query ed anche il campo chiave primaria della tabella B. Non è necessario visualizzare questo campo, ma nei criteri utilizza: Is Null

L'istruzione SQL risultante, assomiglia a questa:

SELECT A.*
FROM A LEFT JOIN B ON A.Id = B.Id
WHERE B.Id Is Null

in alto

3.17 Realizzare un ordine casuale di record
http://www.donkarl.com/it?FAQ3.17

Problema

Ogni volta che apri una query, vuoi che i record appaiano in ordine differente e casuale.

Soluzione

VBA offre la funzione Rnd() per creare numeri casuali. Per realizzare un ordine casuale, puoi creare un nuovo campo, e a quel punto usare un campo contatore che si spera sia presente nella sottostante tabella (in mancanza, allora crealo).
L'espressione per il nuovo campo è: Rnd(MioCampoContatore)
Ordina la query tramite questo campo.

in alto

3.18 Parametri nelle query a campi incrociati
http://www.donkarl.com/it?FAQ3.18

Problema

In una query a campi incrociati, utilizzi come criterio, un parametro che digiti nella finestra di dialogo del parametro o , p. e., un riferimento ad una maschera, che in altri tipi di query funziona bene. Tuttavia, nella query a campi incrociati ricevi il messaggio di errore:
"Il modulo di gestione di database Microsoft Jet non riconosce '|' come nome di campo o espressione valida. (errore 3070)"

Causa

In una query a campi incrociati i nomi di colonna sono generati dinamicamente. Così inizialmente Access non rileva se qualcosa sia un parametro o un riferimento ad un campo. Soltanto dopo, quando JET tenta di collegare le colonne ad un campo di una tabella, accade l'errore.

Soluzione

Aggiungere il parametro, il riferimento della maschera etc. e il suo tipo alla lista parametri della query a campi incrociati. Nella modalità struttura scegli la voce di menu Query/Parametri. Dopo che Access conosce il nome ed il tipo di parametro, può gestirlo in maniera corretta dall'inizio.

in alto

3.19 Distinguere tra maiuscole e minuscole
http://www.donkarl.com/it?FAQ3.19

Problema

In un criterio o in un collegamento vuoi distinguere le lettere tra maiuscole e minuscole. Access, però, non se ne prende cura.

Causa

JET, il modulo di gestione database standard di Access, strutturalmente non distingue le maiuscole dalle minuscole, cioè, non è "case-sensitive".

Soluzione

Puoi usare la funzione StrComp() di VBA per distinguere le maiuscole dalle minuscole.
Supponiamo che vuoi confrontare il CampoX con un criterio "abc". Nel set dei risultati vuoi soltanto i record con questo testo in minuscolo, non "ABC","aBc","Abc" etc. Per realizzare ciò, crea un nuovo campo di una query con la seguente espressione:

StrComp([CampoX];"abc";0)

Lo 0 (zero) alla fine (parametro [,compare]), fornisce il confronto binario necessario. Solo se lo "spelling" dei valori confrontati è esattamente identico, StrComp() restituisce uno 0. (vedi <F1> Help per "StrComp"). In questa maniera puoi filtrare le risposte, utilizzando come criterio del campo: 0
Vedi: http://support.microsoft.com/?kbid=209674

Con una tecnica simile puoi anche distinguere le maiuscole dalle minuscole in campi collegati di un collegamento (una relazione). Devi solo utilizzare un campo addizionale assieme al confronto binario della funzione StrComp per i campi collegati. In SQL ciò assomiglia a:

SELECT *
FROM Tabella1 INNER JOIN Tabella2 ON Tabella1.CampoX = Tabella2.CampoX
WHERE StrComp(Tabella1.CampoX, Tabella2.CampoX, 0) = 0


Vedi: http://support.microsoft.com/?kbid=244693

in alto