OutputSu (OutputTo)

di il
11 risposte

OutputSu (OutputTo)

Ricollegandomi a questo thread
https://www.iprogrammatori.it/forum-programmazione/access/followhyperlink-t16875.html
ho utilizzato una macro con l'azione OutputSu (equivalente a OutputTo in VBA) per esportare in html molte tabelle e query in una determinata directory. Anche in questo caso, se, alla proprietà "File output", scrivo un path assoluto, funziona correttamente. Se il mio database si trova nella directory X e voglio esportare "relativamente" in X\Y\NomeFile.html non riesco a scrivere un path coerente e quando eseguo la macro mi appare il messaggio "Impossibile salvare i dati di output nel file selezionato". Accetto un suggerimento anche in VBA.

11 Risposte

  • Re: OutputSu (OutputTo)

    In VBA vale sempre quello che ti ho suggerito nell'altro 3D... stessa identica cosa.

    Con le macro non puoi relativizzare il Path.
  • Re: OutputSu (OutputTo)

    Private Sub HTML_Click()
    Dim H As String
    H = CurrentProject.Path & "\HTML\DDiffDanza.html"
    DoCmd.OutputTo acOutputQuery, "DDiffDanza", HTML, H
    H = CurrentProject.Path & "\HTML\DFama.html"
    DoCmd.OutputTo acOutputQuery, "DFama", HTML, H
    End Sub
    Mi sono inventato questo codice. Non sapendo se creare una Public Sub o come inventare un Evento, ho costruito una maschera fittizia con un pulsante. Ho cancellato la scritta (Cancel As Integer) che non ho capito. In questo codice ho ipotizzato di esportare 2 query. Potrei ripetere le due righe 12 volte, oppure giocare su una For...Next sfruttando la numerazione di tutte e 12 le query (ma qua andiamo su un livello superiore...se ti va di raccontarmelo, tanto di guadagnato, altrimenti va bene pure alla poverella...).
    Ho provato, ma non funziona. Non so usare il Debug quando viene evidenziato in giallo...ecc...
  • Re: OutputSu (OutputTo)

    Risolto sia con macro, questa la sintassi da includere in File output:
    =[application].[currentproject].[path] & "\HTML\DDiffDanza.html"
    oppure
    =[currentproject].[path] & "\HTML\DDiffDanza.html"

    Risolto anche in VBA, questo il codice precedente, ma corretto:
    Private Sub HTML_Click()
    Dim H As String
    H = CurrentProject.Path & "\HTML\DDiffDanza.html"
    DoCmd.OutputTo acOutputQuery, "DDiffDanza", acFormatHTML, H
    H = CurrentProject.Path & "\HTML\DFama.html"
    DoCmd.OutputTo acOutputQuery, "DFama", acFormatHTML, H
    End Sub
    Osservazioni:
    Con la macro, ogni volta che eseguo l'eportazione, mi appare una finestra dove chiede qualcosa come "Il file esiste già. Occorre sovrascriverlo?"
    Con il codice VBA questo non accade: sovrascrive senza chiedere.

    Mi rimangono appesi ancora i seguenti dubbi:
    1. In realtà ho 12 query da esportare. So che in VBA è possibile numerarle da 0 a 11 e magari creare un ciclo For...Next sfruttando la ripetitività delle due linee di codice. Come?
    2. Per far funzionare il codice, ho trovato più familiare il clic di un pulsante su una maschera inventata per l'occasione. In realtà tale esportazione è una operazione da farsi ogni qualvolta vado ad aggiornare dati nel database. Cosa mi conviene fare? Creare un modulo con una Public Sub? E poi cosa ci scrivo accanto?
    3. In un precedente suggerimento di @Alex ho trovato scritto accanto a una Public Sub (Cancel As Integer). Aveva un significato rilevante? Aveva un senso solo limitatamente al discorso del precedente link?
    4. Nel costruire il codice ed eseguirlo, quando non funzionava, appariva evidenziata in giallo la seguente riga:
    DoCmd.OutputTo acOutputQuery, "DDiffDanza", HTML, H
    Come avviene il debug? Quali strumenti avrei dovuto mettere in atto per scovare l'errore?
  • Re: OutputSu (OutputTo)

    Ciao Osvaldo.

    Allora, partiamo dal primo:
    1)Le queries sono contenute in una Collection chiamata QueryDefs(con la s finale), questa collection è ENUMERABILE, quindi ciclabile gli oggetti contenuti nella collection sono degli Oggetti chiamati QueryDef(senza s)...
    
    Dim qdf as DAO.Querydef
    Dim strPath as String
    For each qdf in DbEngine(0)(0).Querydefs
        strPath=CurrentProject.Path & "\HTML\" & qdf.name & ".html"
        DoCmd.OutputTo acOutputQuery, qdf.name, acFormatHTML, strPath
    Next
    2) Per fare una funzione o Sub, serve capire se il codice può essere riciclabile... in quel caso la distinzione Sub/Function devi definirla se vuoi o meno un valore restituito...(allora usi una Function) e normalmente si sfruttano Parametri per rendere la Sub/Function flessibile, nel tuo caso potrebbe essere il ROOT:
    
    Public Sub ExportQry(strPath As String)
    Dim qdf as DAO.Querydef
    For each qdf in DbEngine(0)(0).Querydefs
        DoCmd.OutputTo acOutputQuery, qdf.name, acFormatHTML, strPath  & "\HTML\" & qdf.name & ".html"
    Next
    End Sub
    Ovviamente essendo unb Parametro il Path, devi passarlo alla chiamata
    
    Call ExportQry(CurrentProject.Path)
    
    3) Il parametro CANCEL è presente in modo NATIVO nelle SUB mai nelle Function, che poi sono EVENTI specifici di Oggetto, come il BeforeUpdate ad esempio.
    Quel Cancel consente di ANNULLARE l'evento, di conseguenza annullare l'UPDATE...
    L'annullamento si ottiene Forzando il Valore CANCEL=TRUE
    
    4)Per il DEBUG, leggi questo TUTORIAL:
    [url]http://forum.masterdrive.it/access-79/access-debug-44533/[/url]
  • Re: OutputSu (OutputTo)

    1) Vorrei sapere: Leggo da un libro che si può fare riferimento a un oggetto (in questo caso query) anche con la sintassi NomeInsieme(NumeroRelativoOggetto). Io pensavo che le mie 12 query fossero così considerate:
    DAreaGeo = QueryDefs(0)
    DDiffDanza = QueryDefs(1)
    DFama = QueryDefs(2)
    ...
    TTitolo = QueryDefs(11)
    So anche che QueryDefs.Count conta tutte le query, quindi potrei anche generalizzare il discorso sfruttando la proprietà Count. Se quello che ho scritto equivale al concetto espresso dal mio libro, io pensavo più a un ciclo con una variabile contatore K (Dim K As Integer) e poi un tradizionale For K = 0 To 11 (o Count-1)...Next. Questo mio ragionamento può essere equivalente?
    QueryDefs(n-1) posso scriverlo così nudo e crudo oppure occorre precederlo sempre con il nome del database...non so...leggo sintassi che non mi tornano da questo libro.
    CurrentDb.QueryDefs.Count rischia di diventare troppo lungo. È buona prassi dimensionare una variabile e metterci dentro SEMPRE un "concetto" lungo?

    @Alex ha scritto:


    2) Per fare una funzione o Sub, serve capire se il codice può essere riciclabile
    Questo riesco ad apprezzarlo solo a livello teorico, ma le mie attuali conoscenze mi impediscono di afferrarne le nobili intenzioni. Siccome penso che il VBA sia un emblema del "sbagliando si impara", almeno per il momento che ho ancora una visione corta di questo mondo, posso continuare a pensare ancora soltanto in termini di Private Sub? Quando vorrò riciclarlo, provvederò a Copiare/Incollare oppure imparerò a riadattare su un piano di Public Sub...perdona i miei limiti tecnici e filosofici!!!

    3) Mi suona ancora arabo. Non importa, non devi darmi ulteriori spiegazioni.

    4) Non ho raccolto ancora i benefici del tuo tutorial. Piuttosto vorrei capire...analizziamo la linea di codice:
    DoCmd.OutputTo acOutputQuery, "DDiffDanza", acFormatHTML, H
    - Quando nella finestra VBA digito DoCmd. appare subito dopo una casella combinata dove poter scegliere l'azione (credo si chiami Metodo tecnicamente: vero?): OK
    - Poi metto uno spazio e mi appare una nuova casella combinata dove posso scegliere comodamente acOutputQuery: anche qui OK
    - Poi metto virgola e da questo punto in poi non mi appariranno più caselle combinate che mi tornerebbero molto comode: perchè? L'errore di aver digitato (sul terzo argomento) inizialmente HTML e poi corretto in acFormatHTML è nato da una digitazione "a colpo di fortuna"...poi ho letto la guida il linea su OutputTo e ho corretto...ma almeno per il terzo argomento, sarebbe stato pertinente proporre una casella combinata anche lì. Nelle corrispettive proprietà nella macro, dove possibile, appare sempre la casella combinata. Potresti delucidarmi questo aspetto della digitazione del codice?
  • Re: OutputSu (OutputTo)

    OsvaldoLaviosa ha scritto:


    1) Vorrei sapere: Leggo da un libro che si può fare riferimento a un oggetto (in questo caso query) anche con la sintassi NomeInsieme(NumeroRelativoOggetto). Io pensavo che le mie 12 query fossero così considerate:
    DAreaGeo = QueryDefs(0)
    DDiffDanza = QueryDefs(1)
    DFama = QueryDefs(2)
    ...
    TTitolo = QueryDefs(11)
    So anche che QueryDefs.Count conta tutte le query, quindi potrei anche generalizzare il discorso sfruttando la proprietà Count. Se quello che ho scritto equivale al concetto espresso dal mio libro, io pensavo più a un ciclo con una variabile contatore K (Dim K As Integer) e poi un tradizionale For K = 0 To 11 (o Count-1)...Next. Questo mio ragionamento può essere equivalente?
    QueryDefs(n-1) posso scriverlo così nudo e crudo oppure occorre precederlo sempre con il nome del database...non so...leggo sintassi che non mi tornano da questo libro.
    CurrentDb.QueryDefs.Count rischia di diventare troppo lungo. È buona prassi dimensionare una variabile e metterci dentro SEMPRE un "concetto" lungo?
    Si quello che dici è concettualmente corretto...(ma sintatticamente errato, poi ti spiego...) ma come hai visto nel mio esempio non serve nemmeno sapere l'indice o sapere quanti oggetti ci sono nell'insieme...!
    Se osservi questo codice
    
    Dim qdf As DAO.QueryDef
    For each qdf in Currentdb.QueryDefs
       MsgBox qdf.Name
    Next
    Questo ti mostra che nell'insieme QueryDefs, ci sono degli Oggetti QueryDef, come ti dicevo fai attenzione alla [S]... e non serve sapere nè quanti sono ne quali sono gli indici...!
    Come dicevo quello che hai scritto è parzialmente errato...
    Quello che tu indichi così:
    DAreaGeo = QueryDefs(0)
    In realtà ha 2 errori:
    1) Per puntare all'Oggetto Query di INDICE(0) devi riferirti all'Insieme ma in modo ESPLICITO deve contenere il PADRE dell'insieme... e le sintassi sono 2
    
    Currentdb.QueryDefs(0)
    DbEngine(0)(0).QueryDefs(0)
    2) Questo riferimento tuttavia non corrisponde al NOME della query, ma all'Oggetto Query che per il VBA è un'oggetto QueryDef, quindi
    
    Dim DAreaGeo As DAO.QueryDef
    Set DAreaGeo = QueryDefs(0)
    Il Set serve per l'assegnazione degli OGGETTI...!
    Se vuoi assegnare il NOME invece serve una Variabile STRINGA e serve recuperare la Proprietà NAME dell'Oggetto QueryDef:
    
    Dim DAreaGeo As String
    DAreaGeo = QueryDefs(0).Name

    OsvaldoLaviosa ha scritto:


    3) Mi suona ancora arabo. Non importa, non devi darmi ulteriori spiegazioni.
    4) Non ho raccolto ancora i benefici del tuo tutorial. Piuttosto vorrei capire...analizziamo la linea di codice:
    DoCmd.OutputTo acOutputQuery, "DDiffDanza", acFormatHTML, H
    - Quando nella finestra VBA digito DoCmd. appare subito dopo una casella combinata dove poter scegliere l'azione (credo si chiami Metodo tecnicamente: vero?): OK

    OsvaldoLaviosa ha scritto:


    - Poi metto uno spazio e mi appare una nuova casella combinata dove posso scegliere comodamente acOutputQuery: anche qui OK
    - Poi metto virgola e da questo punto in poi non mi appariranno più caselle combinate che mi tornerebbero molto comode: perchè? L'errore di aver digitato (sul terzo argomento) inizialmente HTML e poi corretto in acFormatHTML è nato da una digitazione "a colpo di fortuna"...poi ho letto la guida il linea su OutputTo e ho corretto...ma almeno per il terzo argomento, sarebbe stato pertinente proporre una casella combinata anche lì. Nelle corrispettive proprietà nella macro, dove possibile, appare sempre la casella combinata. Potresti delucidarmi questo aspetto della digitazione del codice?
    Si chiama INTELLISENSE questo, e mostra METODI(Funzioni e Sub), PROPRIETA' ed EVENTI degli Oggetti.
    La differenza è mostrata delle ICONE.
    In sostanza questa è la programmazione ad OGGETTI, ed ogni Oggetto espone queste 3 tipologie.
  • Re: OutputSu (OutputTo)

    1. Rimanendo nell'ambito della mia limitatezza di ambito-conoscenze, mi stai dicendo che la tua prima proposta di codice è molto più snella/preferibile?

    OsvaldoLaviosa ha scritto:


    CurrentDb.QueryDefs.Count rischia di diventare troppo lungo. È buona prassi dimensionare una variabile e metterci dentro SEMPRE un "concetto" lungo?
    Non hai risposto a questa domanda. Ammesso che quella sintassi non sia corretta, ma in linea generale è una filosofia consolidata e utile?
  • Re: OutputSu (OutputTo)

    OsvaldoLaviosa ha scritto:


    1. Rimanendo nell'ambito della mia limitatezza di ambito-conoscenze, mi stai dicendo che la tua prima proposta di codice è molto più snella/preferibile?
    Si

    OsvaldoLaviosa ha scritto:


    CurrentDb.QueryDefs.Count rischia di diventare troppo lungo. È buona prassi dimensionare una variabile e metterci dentro SEMPRE un "concetto" lungo?
    Non hai risposto a questa domanda. Ammesso che quella sintassi non sia corretta, ma in linea generale è una filosofia consolidata e utile?
    Non ho risposto perchè la domanda non ha senso... per come l'hai posta.
    Quando sarai addentro al DEBUG, capirai il perchè è preferibile una scelta o l'altra... ma certamente non dipende dalla LUNGHEZZA.
  • Re: OutputSu (OutputTo)

    Grazie mille, anche se sto impazzendo non poco!
  • Re: OutputSu (OutputTo)

    Io ho scritto questo, associandolo a un altro pulsante [EsportaQuery]
    Private Sub EsportaQuery_Click()
    Dim qdf As DAO.QueryDef
    Dim strPath As String
    For Each qdf In DBEngine(0)(0).QueryDefs
        strPath = CurrentProject.Path & "\HTML\" & qdf.Name & ".html"
        DoCmd.OutputTo acOutputQuery, qdf.Name, acFormatHTML, strPath
    Next
    End Sub
    non funziona. Cliccando su Debug, si evidenzia la linea DoCmd e sembra che il difetto stia su
    DoCmd.OutputTo acOutputQuery, qdf.Name, acFormatHTML, strPath
    Curiosamente, se avvicino il mouse su entrambi i qdf.Name, appare la seguente scritta:
    qdf.Name = "~sq_cCercaTitolo~sq_cElenco5"
    Ho provato (giusto per) a sostituire qdf.Name con UnaQueryQualsiasi ad es. DFama. L'esportazione produce 18 file.html con l'aggiunta di 6 files che riportano strani nomi simili a "~sq_cCercaTitolo~sq_cElenco5", ma tutti contenenti la stessa sostanza, cioè la query DFama.
    Gli strani nomi erano pezzi di altri codici relativi all'apertura di altre query sotto il clic di altri pulsanti sparsi in varie maschere.
    Cosa non funziona?
  • Re: OutputSu (OutputTo)

    La cosa credo sia riassumibile in 2 possibili problemi:
    1) Le Query non sono di tipo SELECT, quindi nel caso di ACTION non puoi esportarle...
    2) Non esiste il percorso o la cartella HTML come SubFolder...

    Ci sono poi delle Queries nascoste che ciclando l'insieme QueryDefs possono ingannare, sono Queries di Sistema che spesso chi sviluppa non vuole vedere... quindi dovresti SKIPPARE... verificandole.
    Le queries di sistema hanno la TILDE[~] iniziale.

    Il Debug in questo caso non aiuta in quanto sono cose che dovresti verificare prima...
    Ti faccio un'esempio, facendoti vedere:
    1) Come controllare se la Query è di Sistema
    2) Come controllare se la Query è di tipo SELECT o meno
    3) Come controllare l'esistenza di una Folder ed eventualmente come crearla se manca
    :
    
    Private Sub EsportaQuery_Click()
        Dim qdf As DAO.QueryDef
        Dim strPath As String
        For Each qdf In DBEngine(0)(0).QueryDefs
            ' Controllo Query di Sistema
            If IsSystemQuery(qdf.Name) = False Then
                ' Controllo Tipo di QUERY...
                If qdf.Type = DAO.QueryDefTypeEnum.dbQSelect Then
                    ' Controllo esistenza FOLDER...
                    If EsisteFolder(CurrentProject.Path & "\HTML") = False Then MkDir CurrentProject.Path & "\HTML"
                    strPath = CurrentProject.Path & "\HTML\" & qdf.Name & ".html"
                    DoCmd.OutputTo acOutputQuery, qdf.Name, Access.Constants.acFormatHTML, strPath
                End If
            End If
        Next
    End Sub
    Questo codice GENERICO lo puoi mettere in un Modulo Esterno come Public.
    
    Public Function IsSystemQuery(ByVal ObjName As String) As Boolean
        IsSystemQuery = ObjName Like "~*"
    End Function
    
    Public Function EsisteFolder(ByVal str As String) As Boolean
        On Error Resume Next
        EsisteFolder = ((GetAttr(str) And vbDirectory) = vbDirectory)
    End Function
    A tutto questo andrebbe aggiunta una gestione errori...
Devi accedere o registrarti per scrivere nel forum
11 risposte