SQL complesse in VBA

di il
8 risposte

SQL complesse in VBA

Dovrei eseguire una query abbastanza complessa: una union di due select, con molti campi e molte condizioni basate anche su valori presi da una maschera. Vorrei poi memorizzarne il risultato in un recordset modificabile che mi consenta di aggiornare alcuni campi, con il risultato di ulteriori query e poi visualizzare il tutto in una maschera.

La prima query è attualmente una query salvata e produce correttamente i risultati richiesti. Le query successive vengono invece eseguite in VBA e anch'esse sono corrette.
Ora il problema è che la prima query è troppo lunga per poter essere gestita in una unica riga di codice VBA, a meno di non comporre la stringa con assegnazioni multiple. Però con questo metodo comprometterei completamente la leggibilità della query.

Quale potrebbe essere la strada da seguire per portare la query in VBA, mantenedo il codice pulito?

Grazie in anticipo per qualsiasi suggerimento

8 Risposte

  • Re: SQL complesse in VBA

    Se ti risponde un utente più esperto di me sarebbe meglio. Per quel poco che so, prenderei in considerazione il fatto che l'istruzione:
    CurrentDb.QueryDefs("NomeQuery").SQL
    preleva l'intera stringa SQL di una query.
  • Re: SQL complesse in VBA

    MonkeyH ha scritto:


    Dovrei eseguire una query abbastanza complessa: una union di due select, con molti campi e molte condizioni basate anche su valori presi da una maschera. Vorrei poi memorizzarne il risultato in un recordset modificabile che mi consenta di aggiornare alcuni campi, con il risultato di ulteriori query e poi visualizzare il tutto in una maschera.

    La prima query è attualmente una query salvata e produce correttamente i risultati richiesti. Le query successive vengono invece eseguite in VBA e anch'esse sono corrette.
    Ora il problema è che la prima query è troppo lunga per poter essere gestita in una unica riga di codice VBA, a meno di non comporre la stringa con assegnazioni multiple. Però con questo metodo comprometterei completamente la leggibilità della query.

    Quale potrebbe essere la strada da seguire per portare la query in VBA, mantenedo il codice pulito?

    Grazie in anticipo per qualsiasi suggerimento
    Inizia pubblicando le query.
  • Re: SQL complesse in VBA

    Fatico a capire nel concreto di cosa hai bisogno...!
    Ora una Query SQL lunga, in qualsiasi modo tu la voglia vedere è di difficile interpretazione e leggibilità... sia questa visualizzata nel QBE che in una Stringa SQL.
    In questo secondo caso peraltro, devi ricordare che le stringhe in generale non possono avere una lunghezza consecutiva di RIGA oltre a(non ricordo quanto)... quindi la sintassi da usare è questa:
    
    Dim strSQL As String
    strSQL=strSQL & "SELECT fld1, fld2, NomeFunction(fld1) As fldCalc1 "
    strSQL=strSQL & "fld3, fld4, NomeFunction2(fld5) As fldCalc21 "
    strSQL=strSQL & "FROM T1 "
    strSQL=strSQL & "WHERE Year(fld3)=Year(Now()) AND fld4='" & Me!NomeControllo.Value & "' "
    strSQL=strSQL & "ORDER BY fld1 DESC, fld2 DESC "
    Ora se devi realizzare una UNION fai la UNION...
    Ser apri con QBE una qry lunga è altrettanto inleggibile... poichè anche se la strutturi con indentazione, il QBE la ottimizza e fa un TRIM di spazzi e quant'altro...

    Se sei certo che scrivere una Query in VBA sia la soluzione più adatta(io non la prediligo moltissimo in quanto è poco flessibile, ma è una possibilità...) allora porterai pazienza sulla perfezione della leggibilità, chiaramente dovrai cercare di scrivere il codice in modo da rendere leggibile al meglio.
  • Re: SQL complesse in VBA

    Beh.... se le query funzionano a dovere, a meno che non hai esigenze particolari, fosse per me non andrei a complicarmi la vita e lascerei il mondo come sta.
    A parte questo, mi sembra che il limite in VBA di una lunghezza di una stringa composta dovrebbe essere sui 1020 caratteri (ma sinceramente è una di quelle informazioni che anche se le leggi, non te le ricordi quindi prendiamola per sbagliata).

    La soluzione migliore a mio avviso è quella proposta da Alex, perchè in realtà diventa anche la più leggibile e la più chiara, perchè ti permette di avere una query molto complessa suddivisa in parti più semplici.
    Trattandosi di una stringa composta, per la sua esecuzione è il risultato finale dell'unione delle sottoparti che conta, quindi puoi tranquillamente dividere il codice come meglio credi, anche singola parola per singola parola, tanto come detto è l'unione finale che conta (e che manderai in esecuzione) e se le parti sono unite bene il risultato è garantito.

    Anzi per ogni singolo step, puoi anche mettere un commento esplicativo di cosa fa quella porzione di codice all'interno della query.

    Cosa che con altri sistemi sarebbe impossibile da fare.

    esempio:
    
    Dim strSQL As String 'variabile finale
    strSQL=strSQL & "SELECT fld1, fld2, NomeFunction(fld1) As fldCalc1 " ' seleziono da queste tabelle etc etc
    strSQL=strSQL & "fld3, fld4, NomeFunction2(fld5) As fldCalc21 " ' e poi aggiungo dalle tabelle
    strSQL=strSQL & "FROM T1 "
    strSQL=strSQL & "WHERE Year(fld3)=Year(Now()) AND fld4='" & Me!NomeControllo.Value & "' "
    strSQL=strSQL & "ORDER BY fld1 DESC, fld2 DESC "
    Forse l'utilità di usare Il VBA per le query complesse è proprio la possibilità di riportare la query a valori atomici.

    Diciamo che abbiamo normalizzato la query in NF1
    (va beh... questa me la potevo risparmiare )
  • Re: SQL complesse in VBA

    Non vorrei restare troppo nel concreto, prendevo spunto dal problema per farne una questione di metodo. Il presupposto è che l'utente faccia una interrogazione il cui risultato comporti l'esecuzione di più query, anche complesse. Per quanto ne so, in questo caso non si può fare a meno di gestire queste query con VBA ed esistono ovviamente diverse modalità per farlo.
    Mi chiedevo quale fosse la migliore o se non altro quella da preferire nella maggior parte dei casi.
    Per quanto mi riguarda, sarei orientato a separare la parte SQL da quella VBA, per suddividere la complessità: potrei testare la query indipendentemente dalla routine di gestione della stessa...
    In questo caso, il suggerimento di usare la proprietà .sql di querydefs è sicuramente molto utile.
    In ogni caso mi sono reso conto che se si usano tabelle temporanee, la complessità delle query può essere notevolmente ridotta. E qui pero' si apre un altro post
  • Re: SQL complesse in VBA

    MonkeyH ha scritto:


    Non vorrei restare troppo nel concreto, prendevo spunto dal problema per farne una questione di metodo. Il presupposto è che l'utente faccia una interrogazione il cui risultato comporti l'esecuzione di più query, anche complesse. Per quanto ne so, in questo caso non si può fare a meno di gestire queste query con VBA ed esistono ovviamente diverse modalità per farlo.
    Parliamone... questi sono aspetti tecnici concreti, esponi qualche esempio di questi metodi...

    MonkeyH ha scritto:


    Mi chiedevo quale fosse la migliore o se non altro quella da preferire nella maggior parte dei casi.
    Per quanto mi riguarda, sarei orientato a separare la parte SQL da quella VBA, per suddividere la complessità: potrei testare la query indipendentemente dalla routine di gestione della stessa.
    Le query funzionano meglio, se sono in QueryDefs e sono compilate... ci sono poi altre considerazioni...
    Leggi questo:

    MonkeyH ha scritto:


    In questo caso, il suggerimento di usare la proprietà .sql di querydefs è sicuramente molto utile.
    E' utile e no a seconda di come si lavora... se si usano Query PARAMETRICHE potrebbe non avere un senso...

    MonkeyH ha scritto:


    In ogni caso mi sono reso conto che se si usano tabelle temporanee, la complessità delle query può essere notevolmente ridotta. E qui pero' si apre un altro post
    Non è possibile farne una questione di METODO, dal momento che tu come metro di confronto utilizzi la sola LEGGIBILITA' di un predicato SQL.
    Posso dirti che l'idea di Tabelle temporanee al solo scopo di rendere più semplice l'interpretazione e meno complesse le Query, mi ha fatto molto specie... non che non sia una tecnica disponibile, quanto che il main driver sia la semplificazione invece che l'ottimizzazione prestazionale...(addio indicizzazione)

    Insomma serve avere le idee chiare, query belle pulite corte e scritte bene non sono indice di sistema che funziona bene e che risponde veloce... se vedi le SP di un RDBMS potresti anche perdere il filo di cosa fanno... ma se fatte bene(strutturalmente con i concetti importanti rispettati e non sono quelli dell'estetica... funzionano eccome...) ...ma tant'è...
  • Re: SQL complesse in VBA

    @Alex ha scritto:


    Parliamone... questi sono aspetti tecnici concreti, esponi qualche esempio di questi metodi...
    Supponi ad esempio di avere la seguente query:
    
    (
       SELECT DISTINCT ARTICOLI.CODARTP AS CODART,
          ARTICOLI.IDART AS CODARTINT,
          ARTICOLI.IDAZ AS AZ,
          ARTICOLI.DESCRI AS DESCRIZIONE,
          UBICAZIONI.IDUBIN_M AS UBIC,
          MARCHE.IDMARCA_M AS CODMARCA,
          MARCHE.DESMAR AS MARCA,
          0.00 AS DISP,
          0.00 AS GIACENZA,
          0.00 AS IMPCLI,
          0.00 AS ORDFOR
       FROM ARTICOLI,
          GESTIONALE,
          UBICAZIONI,
          MARCHE
       WHERE GESTIONALE.IDMAG = 1
          AND ARTICOLI.IDAZ = [Forms]![Articoli_per_ubicazione_input]![ditta_cb]
          AND (GESTIONALE.IDUBIN = UBICAZIONI.IDUBIN)
          AND (ARTICOLI.IDMARCA = MARCHE.IDMARCA)
          AND (ARTICOLI.IDART = GESTIONALE.IDART)
          AND (UBICAZIONI.IDUBIN_M LIKE [Forms]![Articoli_per_ubicazione_input]![ubic_ib] )
    )
    UNION (
       SELECT DISTINCT ARTICOLI.CODARTP AS CODART,
          ALTERNATIVI.IDART AS CODARTINT,
          '' AS AZ,
          ARTICOLI.DESCRI AS DESCRIZIONE,
          '' AS UBIC,
          MARCHE.IDMARCA_M AS CODMARCA,
          MARCHE.DESMAR AS MARCA,
          0.00 AS DISP,
          0.00 AS GIACENZA,
          0.00 AS IMPCLI,
          0.00 AS ORDFOR
       FROM ARTICOLI,
          MARCHE,
          ALTERNATIVI
       WHERE (ARTICOLI.IDMARCA = MARCHE.IDMARCA)
          AND ARTICOLI.IDAZ = [Forms]![Articoli_per_ubicazione_input]![ditta_cb] 
          AND (ALTERNATIVI.IDARTA = ARTICOLI.IDART)
          AND
             ALTERNATIVI.IDART  IN (
                SELECT ARTICOLI.IDART
                FROM ARTICOLI,
                   GESTIONALE,
                   UBICAZIONI
                WHERE GESTIONALE.IDMAG = 1
                AND (ARTICOLI.IDART = GESTIONALE.IDART)
                AND (GESTIONALE.IDUBIN = UBICAZIONI.IDUBIN)
                AND (UBICAZIONI.IDUBIN_M LIKE [Forms]![Articoli_per_ubicazione_input]![ubic_ib] )
             )
    )
    ORDER BY CODARTINT;
    
    I campi inizializzati a zero saranno popolati successivamente con i risultati di calcoli fatti in altrettante query. Per fare questo, a mio avviso, non si puo' fare a meno di VBA, ma ovviamente mi interessano opinioni diverse.

    @Alex ha scritto:


    Leggi questo:

    Molto interessanti.
  • Re: SQL complesse in VBA

    MonkeyH ha scritto:


    
    (
       SELECT DISTINCT ARTICOLI.CODARTP AS CODART,
         ...
       FROM ARTICOLI,
          GESTIONALE,
          UBICAZIONI,
          MARCHE
       WHERE GESTIONALE.IDMAG = 1
          AND ARTICOLI.IDAZ = [Forms]![Articoli_per_ubicazione_input]![ditta_cb]
          AND (GESTIONALE.IDUBIN = UBICAZIONI.IDUBIN)
          AND (ARTICOLI.IDMARCA = MARCHE.IDMARCA)
          AND (ARTICOLI.IDART = GESTIONALE.IDART)
          AND (UBICAZIONI.IDUBIN_M LIKE [Forms]![Articoli_per_ubicazione_input]![ubic_ib] )
    )
    UNION (
       SELECT DISTINCT ARTICOLI.CODARTP AS CODART,
        ...
       FROM ARTICOLI,
          MARCHE,
          ALTERNATIVI
       WHERE (ARTICOLI.IDMARCA = MARCHE.IDMARCA)
          AND ARTICOLI.IDAZ = [Forms]![Articoli_per_ubicazione_input]![ditta_cb] 
          AND (ALTERNATIVI.IDARTA = ARTICOLI.IDART)
          AND
             ALTERNATIVI.IDART  IN (
                SELECT ARTICOLI.IDART
                FROM ARTICOLI,
                   GESTIONALE,
                   UBICAZIONI
                WHERE GESTIONALE.IDMAG = 1
                AND (ARTICOLI.IDART = GESTIONALE.IDART)
                AND (GESTIONALE.IDUBIN = UBICAZIONI.IDUBIN)
                AND (UBICAZIONI.IDUBIN_M LIKE [Forms]![Articoli_per_ubicazione_input]![ubic_ib] )
             )
    )
    ORDER BY CODARTINT;
    
    I campi inizializzati a zero saranno popolati successivamente con i risultati di calcoli fatti in altrettante query. Per fare questo, a mio avviso, non si puo' fare a meno di VBA, ma ovviamente mi interessano opinioni diverse.
    Forse è opportuno creare una query apposita che metta già in relazione le tabelle ARTICOLI, GESTIONALE, UBICAZIONI, MARCHE con INNER JOIN anziché l'uso del WHERE. O almeno usare INNER JOIN nella query pubblicata, sempre al posto di WHERE per la corrispondenza tra i campi delle varie tabelle (ho preso spunto dal paragrafo "Other optimizations" di )
    Per la parte relativa ai calcoli e al fatto che si tratti di una UNION query non so dare alcun contributo.
Devi accedere o registrarti per scrivere nel forum
8 risposte