Conteggio records lato molti

di Mailman il
8 risposte

Buongiorno,

devo conteggiare tramite VBA in una tabella lato molti, quanti records ci sono per una determinata FK.

E' meglio utilizzare la funzione DCount oppure aprire un recordset filtrato e contare quanti records restituisce?

Considerate che la tabella contiene attualmente circa 8900 righe (dopo circa 5 anni di utilizzo).

Grazie per il consiglio

8 Risposte

  • Devi contarli in una Tabella o in una Maschera...?
    Ti chiedo perchè se fosse una maschera hai già il Recordet e basterebbe Filtrarlo...

    Se devi contarli in una tabella, usa Dcount, anche su interrogazioni cicliche la differenza è minima...

    Se proprio verifica tra queste quale sia più efficiente(test da fare su unb ciclo di almeno 1000):

    DCOUNT("*","Dominio","FK=" & TuaFK)
    DCOUNT("PK",Domino", "FK=" & TuaFK)
    DCOUNT("FK",Domino", "FK=" & TuaFK)

    Pur pensando siano uguali, feci qualche test ed i risultati sono differenti.

  • 10/06/2026 - @Alex ha scritto:

    Devi contarli in una Tabella o in una Maschera...?

    Grazie @Alex come sempre.

    Li devo contare in una tabella.

    Attualmente adotto il primo Dcount che hai suggerito, ma provo anche gli altri per vedere se ci sono differenze, anche se la mia richiesta era finalizzata a capire quale metodo era il piu' consono. 

    Ragionavo sul fatto che il Dcount deve leggere e contare tutto il recordset, mentre se creo "al volo" un recordset gia'  filtrato il conteggio e' limitato a soli pochi records per cui presumibilmente piu' veloce...

    Set rst = DBEngine(0)(0).OpenRecordset("SELECT * FROM MiaTabella WHERE FK=" & MiaFK, dbOpenSnapshot, dbReadOnly)

    Non avevo specificato che il risultato del conteggio puo' variare da minimo 1 a massimo 10 records...

    Devo discriminare se il risultato e' 1 o piu' di 1 

  • DCount è la soluzione migliore. Le sintassi proposte da @Alex sono valide...correggo solo le virgolette.

    DCOUNT("*","Dominio", "FK=" & TuaFK) 
    DCOUNT("PK","Dominio", "FK=" & TuaFK) 
    DCOUNT("FK","Dominio", "FK=" & TuaFK)
  • 10/06/2026 - Mailman ha scritto:

    10/06/2026 - @Alex ha scritto:

    Devi contarli in una Tabella o in una Maschera...?

    Grazie @Alex come sempre.

    Li devo contare in una tabella.

    Attualmente adotto il primo Dcount che hai suggerito, ma provo anche gli altri per vedere se ci sono differenze, anche se la mia richiesta era finalizzata a capire quale metodo era il piu' consono. 

    Ragionavo sul fatto che il Dcount deve leggere e contare tutto il recordset, mentre se creo "al volo" un recordset gia'  filtrato il conteggio e' limitato a soli pochi records per cui presumibilmente piu' veloce...

    Set rst = DBEngine(0)(0).OpenRecordset("SELECT * FROM MiaTabella WHERE FK=" & MiaFK, dbOpenSnapshot, dbReadOnly)

    La velocità va contestualizzata...!

    Se la chiamata è singola la differenza di 50ms non ha senso di essere considerata... mentre se devi inserirlo in un Loop di un migliaio di Records, le cose cambiano.

    Io ricordo vagamente di aver fatto un test e le differenze erano veramente molto ridotte a tal punto che io uso sempre DCount, perchè più semplice e più comodo.

    Non avevo specificato che il risultato del conteggio puo' variare da minimo 1 a massimo 10 records...

    Devo discriminare se il risultato e' 1 o piu' di 1 

    Potresti eventualmente fare una cosa simile:

    SELECT
        Count(FK) > 1 AS ConteggioFK
    FROM
        Dominio
    HAVING
        FK = TuoValore;

    Questa restituisce un Boolean già fatto, allo stesso modo:

    TuoValore=DCOUNT("*","Dominio", "FK=" & TuaFK) >1
    TuoValore=DCOUNT("PK","Dominio", "FK=" & TuaFK)>1
    TuoValore=DCOUNT("FK","Dominio", "FK=" & TuaFK)>1

    Fai un test con un Timer ed un ciclo di 1000 interrogazioni segnando il Tempo prima di iniziare il Loop e dopo vedi dal differenza in ms e poi capisci se vale la pena o meno...

    Sub DCountVsRecordset()
       Const TABLE = "yourtablehere"
       Const MAX = 1000
       Dim clock As Single
       Dim tmp As String
       Dim i As Integer
       
       clock = Timer
       For i = 1 To MAX
          tmp = DCount("*", TABLE, "......")
          'tmp = DCount("FK", TABLE, "......")
       Next
       Debug.Print "DCount(): " & Round(Timer - clock, 4)
       
       clock = Timer
       For i = 1 To MAX
          tmp = CurrentDb.OpenRecordset("SELECT Count(*) FROM " & TABLE).Fields(0)
       Next
       Debug.Print "Recordset: " & Round(Timer - clock, 4)
       
       Beep
       Debug.Print "***"
       
    End Sub

    Leggi anche questo, potresti avere sorprese piacevoli:
    https://codekabinett.com/rdumps.php?Lang=2&targetDoc=access-performance-counting-records

  • 10/06/2026 - @Alex ha scritto:

    Leggi anche questo, potresti avere sorprese piacevoli:
    https://codekabinett.com/rdumps.php?Lang=2&targetDoc=access-performance-counting-records

    Interessante il test ma fatto su una select di conteggio PK senza filtri; inserendo una where forse i risultati cambiano.

    Provo ad adattare il Tuo suggerimento su una tabella con molti records per vedere che differenze ci sono tra i vari metodi...

    Ci sentiamo presto.

    Grazie come sempre

  • Ok ho fatto il test su una tabella con circa 115000 records; i risultati sono questi:

    1) Dcount (*): 1,0898 sec.

    2) Dcount (PK): 1,1211 sec.

    3) Recordset Count (*): 1,4922 sec.

    4) Dcount (FK): 2,125 sec.

  • Come dicevo il DCOUNT va più che bene... ;-)
    In ogni caso deve essere stato fatto un cambiamento radicale sulle funzioni di Dominio di Access, in quanto fino ad A2003 sono certo che il paragone era a vantaggio dei RS, oggi(non so da quando) invece pare abbiano ottimizzato le funzioni di aggregazione native, e direi che hanno fatto centro.

  • Interessante, ma non ho capito se stai cercando il tempo impiegato o quanti record detail hai per pk...

    Io sono quello del tutto e subito.

    SELECT
        IDPadre,
        Count(*) AS NumOccorrenze
    FROM TabellaMolti
    GROUP BY IDPadre;

    Le chiavi dovrebbero essere indicizzate e il tempo ridotto al minimo.

    Oppure se vuoi sapere quanti e quali orfani hai:

    SELECT
        d.IDPadre,
            COUNT(*) AS NumOccorrenze,
                CASE
                        WHEN m.ID IS NULL
                                    THEN CONCAT('ID FK non trovato nella master: ', d.IDPadre)
                                            ELSE 'Nessun errore'
                                                END AS Esito
                                                FROM Detail d
                                                LEFT JOIN Master m
                                                    ON m.ID = d.IDPadre
                                                    GROUP BY d.IDPadre, m.ID;
Devi accedere o registrarti per scrivere nel forum
8 risposte