PDA

View Full Version : [VBA Access] Come fare per visualizzare in casella di testo una query SQL


tesladj
20-05-2008, 13:06
Salve a tutti.

Mi sono imbarcato nell'impresa di creare un database di gestione di una videoteca (non è un esercizio o un compito: è una cosa vera!).

Il cliente m'ha chiesto di creargli, tra le tante opzioni, una maschera per poter lui modificare le note per un cliente (sono note personali es. "deve dare 5€", "contattarlo al num. xxx" ecc.). Io ho fatto così: nella tabella "clienti" ho messo un campo Testo "note", occupando tutti e 255 i caratteri disponibili. Nella maschera ho messo un elenco (casella di riepilogo) che mi visualizzasse certi campi della tabella clienti (non tutti, perchè nella maschera era inutile averli tutti) e poi ho creato una casella di testo che, nella mia idea, doveva funzionare così: cliccando con un pulsante (o direttamente sull'elenco) mi visualizzava la nota relativa al cliente selezionato in elenco nella casella di testo, e tramite la casella stessa io potevo modificare la nota e con un altro pulsante mandarla al record appartenente e sostituirla.

Purtroppo, se faccio:

Testo12.Value = "SELECT clienti.note FROM clienti WHERE clienti.numtessera=[Inserisci numero tessera del cliente:];"

la casella di testo mi visualizza "SELECT clienti.note FROM clienti WHERE clienti.numtessera=[Inserisci numero tessera del cliente:];" invece di svolgermi la query.

Come posso fare? :help:

MarcoGG
20-05-2008, 15:07
Nella maschera ho messo un elenco (casella di riepilogo) che mi visualizzasse certi campi della tabella clienti (non tutti, perchè nella maschera era inutile averli tutti) e poi ho creato una casella di testo che, nella mia idea, doveva funzionare così: cliccando con un pulsante (o direttamente sull'elenco) mi visualizzava la nota relativa al cliente selezionato in elenco nella casella di testo, e tramite la casella stessa io potevo modificare la nota e con un altro pulsante mandarla al record appartenente e sostituirla.


La tua idea può essere implementata in un modo relativamente facile.
Crei una query di selezione parametrica ( SELECT + 1 Parametro - numtessera ), una query di aggiornamento, sempre parametrica ( UPDATE + 2 Parametri numtessera e nuove_note )...

Con un pulsante metti in una textbox le note da visualizzare per quel dato cliente ( numtessera deve essere ovviamente campo univoco nel db ), con un altro pulsante aggiorni le note per quel cliente con eventuali modifiche.

Se ti interessa questa soluzione ti faccio un piccolo esempio in VBA... ;)

tesladj
20-05-2008, 22:58
@Marco: grazie per l'interessamento. :)

Se fosse possibile un esempio scritto te ne sarei grato, perchè non ho capito bene cosa scrivere.

P.S. se per numtessera, univoco intendi che non ce ne sono 2 uguali: sì, lo è, grazie al fatto che è tipo Contatore.

MarcoGG
21-05-2008, 08:52
@Marco: grazie per l'interessamento. :)

Se fosse possibile un esempio scritto te ne sarei grato, perchè non ho capito bene cosa scrivere.

P.S. se per numtessera, univoco intendi che non ce ne sono 2 uguali: sì, lo è, grazie al fatto che è tipo Contatore.


Detto fatto.
Anzitutto un consiglio : numtessera io NON lo farei contatore, casomai faccio un ID chiave primaria e contatore, mentre numtessera campo univoco, ossia "indicizzato : SI (duplicati non ammessi)".

Creo una query di selezione che chiamo "Query_Select" parametrica :
SELECT T_Clienti.numtessera, T_Clienti.note
FROM T_Clienti
WHERE (((T_Clienti.numtessera)=[Inserire Numero Tessera]));

Creo una query di aggiornamento "Query_Update" parametrica :
UPDATE T_Clienti SET T_Clienti.[note] = [Inserire Note]
WHERE T_Clienti.numtessera=[Inserire Numero Tessera];

Intanto arriva fin qui... ;)

tesladj
21-05-2008, 15:34
Le sto creando adesso. :)

Ma come mai non mettere numtessera come contatore? Non ho bisogno di modificarla o metterla personalizzata. Mi deve soltanto conteggiare i clienti, anche nel caso in cui qualcuno volesse disiscriversi.

tesladj
21-05-2008, 16:02
Piccolo OT: nella stessa maschera di modifica delle note, ho messo una casella di riepilogo ad una riga per visualizzare le stesse (senza modificarle). Non riesco, però, a creare la barra di scorrimento nel caso di note troppo lunghe! Così mi si visualizzano tagliate. Ho provato creando dello spazio, modificando la larghezza delle colonne, ma niente... Dove sbaglio?

MarcoGG
22-05-2008, 08:29
Allora :

1. Non è mai consigliabile lasciare gestire con un banale contatore un DATO. Prendila come regola generale per DB più complessi di questo. Spesso i codici delle tessere sono fatti da un numero fisso di caratteri alfanumerici, perciò ti consigliavo di creare una PK "ID" contatore o addirittura avere numtessera come PK... Ma se va bene a te, e per un DB così semplice, nessun problema.

2. Le barre di scorrimento ( ACCESS 2003 ) su un controllo txt le attivi da
- proprietà / Formato / Barre Scorrimento > Verticale, e poi
- Allineam. barra di scorrimento > Da destra ( o sinistra ).

3. Il tuo DB adesso contiene le due query che ti ho postato, perciò crea una maschera come questa ( poi adatterai il mio esempio alle tue necessità... ) :

- ogni controllo deve avere il nome che gli ho dato io, sennò il codice VBA non funzionerà !
- una textbox "txtNum" non associata.
- una textbox "txtNote" non associata.
- un pulsante "cmdSelect".
- un pulsante "cmdUpdate".

4. Codice per Click su cmdSelect :

Private Sub cmdSelect_Click()

Dim numTessera As String
txtNum.SetFocus
numTessera = txtNum.Text

Dim QD As QueryDef
Set QD = CurrentDb.QueryDefs("Query_Select")
QD.Parameters("Inserire Numero Tessera") = numTessera

Dim RS As Recordset
Set RS = QD.OpenRecordset

MsgBox RS.RecordCount
txtNote.SetFocus
txtNote.Text = RS("note").Value

RS.Close
QD.Close
Set RS = Nothing
Set QD = Nothing

End Sub

5. Codice per Click su cmdUpdate :

Private Sub cmdUpdate_Click()

Dim numTessera As String
txtNum.SetFocus
numTessera = txtNum.Text
Dim nuoveNote As String
txtNote.SetFocus
nuoveNote = txtNote.Text

Dim QD As QueryDef
Set QD = CurrentDb.QueryDefs("Query_Update")
QD.Parameters("Inserire Numero Tessera") = numTessera
QD.Parameters("Inserire Note") = nuoveNote

QD.Execute

QD.Close
Set QD = Nothing

End Sub

L'esempio funziona così :
- Scrivi un codice numtessera nella txtNum.
- Premi il pulsante cmdSelect e nella txtNote ti trovi le note di quel cliente.
- Modifica qualcosa nelle note > Premi cmdUpdate e applichi le modifiche.

6. Pagare birra... :D

tesladj
22-05-2008, 10:31
Grazie mille, ma ho dei problemi:

1. La soluzione delle barre di scorrimento non va, perchè non c'è l'opzione Barre di scorrimento (e quindi poi la selezione Verticale). Sarà perchè è Access 2002 (ovvero XP)?

2. Nei codici dei pulsanti non mi riconosce la dichiarazione "QueryDef": ho cercato nella lista, e in effetti non c'è! Ho provato a togliere "Option Explicit", così da poter provare il codice cancellando la dichiarazione, ma sulla riga "Set RS = QD.OpenRecordset" mi dà errore di runtime 13, ovvero "Tipo non corrispondente". :muro:

E' perchè devo modificare qualche campo, nel caso tu l'avessi scritto diverso da quello che ho io in tabella?

P.S. mi spieghi, se possibile, brevemente, cosa hai scritto? Ci sono comandi che non conosco... :p

MarcoGG
22-05-2008, 10:57
1. La soluzione delle barre di scorrimento non va, perchè non c'è l'opzione Barre di scorrimento (e quindi poi la selezione Verticale). Sarà perchè è Access 2002 (ovvero XP)?

2. Nei codici dei pulsanti non mi riconosce la dichiarazione "QueryDef": ho cercato nella lista, e in effetti non c'è! Ho provato a togliere "Option Explicit", così da poter provare il codice cancellando la dichiarazione, ma sulla riga "Set RS = QD.OpenRecordset" mi dà errore di runtime 13, ovvero "Tipo non corrispondente". :muro:

E' perchè devo modificare qualche campo, nel caso tu l'avessi scritto diverso da quello che ho io in tabella?


Devi prima cercare di replicare il mio esempio, adattandoti ad usare i nomi che uso io sennò non ne esci più. Poi lo adatterai...

1. Purtroppo Office XP è quello che conosco meno in assoluto. Sono passato direttamente dal 2000 al 2003 ( e francamente l'esistenza della versione XP non me la spiego proprio... ). Se non ci sono le barre, non ci sono e basta. Mi sa che c'è poco da fare. Direi che a 2008 inoltrato è legittimo pretendere che il cliente sia aggiornato almeno alla v.2003 ( la migliore per gli sviluppatori, 2007 a parte ).

2. Per il problema su RS, QueryDef ecc... entra nell'editor VBA della maschera :
>> Menu / Strumenti / Riferimenti >>
controlla che sia attivo "Microsoft Activex data objects 2.* library"...

tesladj
22-05-2008, 16:24
Per le barre: WOW!

Per il fatto che ho la versione XP, l'ho lasciata perchè non m'ha mai dato problemi. Per la 2003, sapevo fosse più pesante, per questo non l'ho messa. Il fatto di dover gestire e creare DB m'è venuta solo da poco.

Comunque: i riferimenti non funzionano, ho provato le librerie dalla 2.0 alla 2.8. Nulla. Vedo se ho qualcos'altro disattivato.

tesladj
22-05-2008, 16:28
Ho risolto il fatto dell'errore!

Dovevo attivare la libreria "Microsoft DAO 3.6 Object Library" e metterla la prima di tutti come priorità! (senza quest'ultima opzione, non funzionava! :eek: )

MarcoGG
22-05-2008, 17:47
Ho risolto il fatto dell'errore!

Dovevo attivare la libreria "Microsoft DAO 3.6 Object Library" e metterla la prima di tutti come priorità! (senza quest'ultima opzione, non funzionava! :eek: )


Perchè, quella non l'avevi già attiva ? Io con Access 2003 solo ad installarlo ho già tutti i riferimenti di base impostati !
Se puoi, passa a Office 2003. Non so chi ti abbia detto che è più pesante di XP. Per me è velocissimo.

Quindi tutto ok con la mia soluzione ?

tesladj
23-05-2008, 10:59
Non so perchè la libreria non fosse attiva. :confused:

Devo dirti GRAZIE perchè mi hai risolto un problemone! :p

Ho adattato il codice a quello che mi serviva, ho aggiunto qualcosa e adesso è perfetto. ;)

Adesso non mi resta che sbattere su un'altra maschera... Ho un pulsante che non mi funziona e non capisco il perchè. Guarda il codice:

Dim db As ADODB.Connection
Set db = CurrentProject.Connection()

Dim tabdvd As ADODB.Recordset
Set tabdvd = New ADODB.Recordset
tabdvd.LockType = adLockOptimistic
tabdvd.Open "dvd", db

Dim response1 As String

If Testo1.Value = "" Or Testo14.Value = "" Then
MsgBox "Non hai inserito il titolo del DVD!", vbExclamation, "Attenzione!"
Else
If Testo3.Value = "" Or Testo5.Value = "" Then
response1 = MsgBox("Non hai inserito il nome del regista o quello degli attori: continuare comunque?", vbYesNo, "Attenzione!")
If response1 = vbYes Then
tabdvd.AddNew
tabdvd!titolo = UCase(Testo1.Value)
tabdvd!genere = CasellaCombinata1.Value
tabdvd!supporto = CasellaCombinata2.Value
tabdvd!regista = Testo3.Value
tabdvd!attore = Testo5.Value
tabdvd!prezzo = Testo12.Value
tabdvd!numcopie = Testo14.Value
tabdvd.Update
tabdvd.Close

MsgBox "Perfetto, hai aggiunto il DVD con successo!", vbInformation, "Operazione completata"

End If
End If
End If


Perchè non mi entra in nessun IF?

MarcoGG
25-05-2008, 09:08
Dim db As ADODB.Connection
Set db = CurrentProject.Connection()

Dim tabdvd As ADODB.Recordset
Set tabdvd = New ADODB.Recordset
tabdvd.LockType = adLockOptimistic
tabdvd.Open "dvd", db

Dim response1 As String

If Testo1.Value = "" Or Testo14.Value = "" Then
MsgBox "Non hai inserito il titolo del DVD!", vbExclamation, "Attenzione!"
Else
If Testo3.Value = "" Or Testo5.Value = "" Then
response1 = MsgBox("Non hai inserito il nome del regista o quello degli attori: continuare comunque?", vbYesNo, "Attenzione!")
If response1 = vbYes Then
tabdvd.AddNew
tabdvd!titolo = UCase(Testo1.Value)
tabdvd!genere = CasellaCombinata1.Value
tabdvd!supporto = CasellaCombinata2.Value
tabdvd!regista = Testo3.Value
tabdvd!attore = Testo5.Value
tabdvd!prezzo = Testo12.Value
tabdvd!numcopie = Testo14.Value
tabdvd.Update
tabdvd.Close

MsgBox "Perfetto, hai aggiunto il DVD con successo!", vbInformation, "Operazione completata"

End If
End If
End If


Intanto vedo parecchie cose che non mi piacciono, in particolare :

1. Il modo corretto per verificare che una textbox non contenga una stringa vuota ( che comunque è una stringa ) è il confronto con la sua proprietà .Text. Tu invece usi .Value dappertutto...

2. il result di una msgbox ( vbYes, vbNo, ecc... ) va registrato come Variant, non come String.

tesladj
25-05-2008, 18:13
Intanto vedo parecchie cose che non mi piacciono, in particolare :

1. Il modo corretto per verificare che una textbox non contenga una stringa vuota ( che comunque è una stringa ) è il confronto con la sua proprietà .Text. Tu invece usi .Value dappertutto...

2. il result di una msgbox ( vbYes, vbNo, ecc... ) va registrato come Variant, non come String.

Eh... In base a quello che mi hanno insegnato! :rolleyes:

Vedo di modificare il tutto... ;)

tesladj
10-06-2008, 18:42
Scusa se ritorno dopo tanto tempo.

Allora: ho lasciato ".value" perchè con il ".text" aveva problemi. E funziona bene comunque.

Adesso ho una domanda: il cliente m'ha chiesto che, quando aggiunge un nuovo DVD alla tabella tramite apposita maschera, venga visualizzato il codice che il DVD assume dopo essere stato inserito nella tabella, che sarebbe il campo "numprog", che è Contatore.

Quando clicco sul pulsante "Aggiungi DVD", quale codice devo mettere per vedere che numprog prende? Devo spostarmi sull'ultimo record e prendere il contenuto di quel campo? Se sì, come si fa? :p

MarcoGG
11-06-2008, 07:42
Adesso ho una domanda: il cliente m'ha chiesto che, quando aggiunge un nuovo DVD alla tabella tramite apposita maschera, venga visualizzato il codice che il DVD assume dopo essere stato inserito nella tabella, che sarebbe il campo "numprog", che è Contatore.

Quando clicco sul pulsante "Aggiungi DVD", quale codice devo mettere per vedere che numprog prende? Devo spostarmi sull'ultimo record e prendere il contenuto di quel campo? Se sì, come si fa? :p


Elementare Watson, appena dopo il codice che esegue l'inserimento fai partire una SELECT sul massimo valore attuale del contatore "numprog" ( il RecordSet in questione avrà sempre e solo 1 valore... ) :

SELECT MAX(T_DVD.numprog)
FROM T_DVD;

ammettendo che la tabella si chiami, appunto "T_DVD"... ;)

tesladj
12-06-2008, 11:04
Grazie mille!

Il codice è esatto, ho creato la query "max_numprog" ma non so come farla partire! :p

Io faccio:

Dim w As Integer, z As String

z = "SELECT * FROM max_numprog;"
w = Val(z)

E mi dà sempre 0, cioè come se non ci fossero numeri nella stringa.

Dove sbaglio?

MarcoGG
12-06-2008, 12:45
Non funzionerà mai così, e poi che senso ha fare una Select su una Query già creata ?
Se usi una Stored Query "max_numprog" :

SELECT MAX(T_DVD.numprog) AS [max]
FROM T_DVD;

E poi il valore che ritorna lo mettiamo in una variabile Long :

Dim max As Long
max = 0
Dim QDmax As QueryDef
Set QDmax = CurrentDb.QueryDefs("max_numprog")
Dim RSmax As Recordset
Set RSmax = QDmax.OpenRecordset
max = CLng(RSmax("max").Value)
RSmax.Close
QDmax.Close
Set RSmax = Nothing
Set QDmax = Nothing

Pensavo fosse chiaro, dai post precedenti... :D ;) .

tesladj
12-06-2008, 14:54
Erano, ma non per me. Ma chi me l'ha fatto fare di imbarcarmi in quest'impresa... :doh:

Grazie mille ancora una volta. Adesso è tutto perfetto. :)

MarcoGG
12-06-2008, 22:23
Ma chi me l'ha fatto fare di imbarcarmi in quest'impresa... :doh:


E perchè mai ? Il miglior modo per iniziare è porsi un problema reale, per quanto circoscritto, e tentare di risolverlo... :)