02a - SQL02c - Varie Database DB2 for i

SQL: conteggio preventivo dei record da leggere

In alcune situazioni può essere necessario conoscere in anticipo il numero di record che si stanno per leggere e presentare all’utente. Pensiamo per esempio ad applicazioni realizzate per il Web, dove un elenco viene mostrato a gruppi e a video compaiono dei pulsanti per spostarsi da una pagina all’altra. Esempio:

Qui si nota come compaia già il numero totale di elementi visualizzabili, mostrati a gruppi di 10 per volta.
Per estrarre i dati è necessario definire un cursore SQL e caricare tutti i record letti in una schiera di DS, gestendo poi il posizionamento pagina per pagina.
Il conteggio si può ottenere impostando in una variabile il risultato di una COUNT(*) a fronte di uno statement che contenga gli stessi criteri di estrazione del cursore definito in precedenza.
Esiste però una soluzione più efficace, che ci evita di scrivere due istruzioni praticamente uguali…
L’istruzione GET DIAGNOSTICS restituisce numerose informazioni relative all’ultima istruzione SQL eseguita. Qui la documentazione dettagliata da IBM. Nel nostro caso, l’informazione che ci interessa è DB2_NUMBER_ROWS che, eseguita dopo la OPEN di un cursore, contiene il numero di righe della tabella risultante dalla selezione.

Exec SQL
	GET DIAGNOSTICS :righe = DB2_NUMBER_ROWS ;

Ecco un esempio di semplice programma che dichiara una query SQL e reperisce il numero di righe:

        //                                                         
        // Conteggio righe con GET DIAGNOSTICS - DB2_NUMBER_ROWS   
        //                                                         
                                                                   
        // *ENTRY PLIST                                            
        dcl-pi FAQ40001 ;                                          
        end-pi;                                                    
        dcl-s  righe       packed(5:0);                            
                                                                   
        *inLR=*on;                                                 
        Exec SQL                                                   
          SET OPTION Commit = *none,                               
                     CloSqlCsr=*EndMod,                            
                     DlyPrp=*YES                                   
          ;                                                        
                                                                   
         Exec SQL                                                  
           DECLARE c1 CURSOR FOR                                   
           SELECT                                                  
           m.tipoArt, m.articolo, descrizione,                     
           codMag, dataMovimento, segno, m.um, quantita            
           FROM  mduca1.movmag00f m                                
           LEFT JOIN mduca1.anaart00f a ON                         
            (m.tipoArt, m.Articolo)=(a.tipoArt, a.Articolo)     
           WHERE quantita > 50                                  
           ;                                                    
         Exec SQL                                               
           OPEN c1;                                             
         Exec SQL                                               
           GET DIAGNOSTICS :righe = DB2_NUMBER_ROWS;            
                                                                
         dsply ('RIGHE = ' + %char(righe)) ;                    
                                                                
        return;                                                 

Lanciando il programma a fronte di un database di test, questo è il risultato:

 DSPLY  RIGHE = 409                  
                                     
 Premere Invio per continuare.                                          

Andiamo a verificare eseguendo la stessa query da una sessione SQL, selezionando il solo conteggio dei record:

Ma… c’è qualcosa che non quadra ! Per una stessa query il programma trova 408 righe, e l’SQL ne trova 448 ?
La risposta a questa “stranezza” la dà il manuale IBM: per cursori di tipo “dinamico” (come quello visto sopra) il valore restituito in DB2_NUMBER_ROWS è da considerarsi una approssimazione, in quanto eventuali righe inserite o cancellate possono avere impatto sul set di risultati finale.
Per ottenere il numero esatto di righe occorre quindi definire esplicitamente il cursore come “INSENSITIVE”; in questo modo il set di risultati viene “congelato” al momento dell’apertura del cursore e le eventuali modifiche alle tabelle refenziate nell’istruzione non avranno effetto. I cursori di tipo INSENSITIVE non possono essere usati per operazioni di aggiornamento o cancellazione.

         Exec SQL                                                  
           DECLARE c1 INSENSITIVE CURSOR FOR   
			ecc...

Rilanciamo il programma dopo la modifica… ed ora finalmente tutto quadra !

                    Visualizzazione messaggi del programma                     
                                                                               
DSPLY  RIGHE = 448                                                 
                                                                                
Premere Invio per continuare.    

Attenzione: se si gestisce la paginazione direttamente nel cursore SQL (con le parole chiave LIMIT o FETCH FIRST n ROWS ONLY e OFFSET), GET DIAGNOSTICS non restituirà il totale delle righe del set di risultati, ma solo quelle specificate nella clausola LIMIT. Per ottenere il totale sarà quindi necessario definire un secondo cursore senza la clausola di limitazione del numero di righe lette.

About author

Senior Analyst/Developer e divulgatore in ambito IBM i. Già collaboratore dell'edizione italiana della rivista "System i News" ed autore di diverse pubblicazioni su tools e tecniche di sviluppo in ambiente IBM i.

Rispondi

%d blogger hanno fatto clic su Mi Piace per questo: