Newsgroup: it.comp.lang.visual-basic
Titolo: [SQL?] Conteggio records restituiti

(ADO o DAO è uguale, insomma è un problema SQL):
Disponendo della tabella NOMINATIVI con due campi, COGNOME e NOME, inserisco
4 records:
Bianchi, Franco
Rossi, Mario
Rossi, Mario (duplicato, ma così dev'essere, è un altro e non lo posso
ammazzare)
Verdi, Franco
Facendo:
Select COGNOME, NOME From NOMINATIVI Where COGNOME>'R' Group By COGNOME
ottengo, correttamente, due records:
Rossi, Mario
Verdi, Franco
Facendo:
Select Count(*) as TR, COGNOME, NOME From NOMINATIVI Where COGNOME>'R' Group
By COGNOME
ottengo, correttamente, 2 records:
2, Rossi, Mario
1, Verdi, Franco
Porca %1, %2, %3, ..., etc., come faccio a farmi restituire (in una sola
query, separata e finalizzata allo scopo) che ho ottenuto 2 records (ho
detto 2, non 2+1=3)?
No, fermo lì, il RecordCount non ce l'ho (è solo per questo che sto
impazzendo, per trovare un surrogato!)
Nelle note (SQL Books OnLine) si legge che la funzione Count, ex:
COUNT(expression), in expression non ammette subqueries, ho già perso tempo
a sufficienza in tal senso.
Sudato, arrabbiato e convinto che sia (debba essere!) la cosa più facile di
questo mondo, mi scuso e ringrazio.

 By COGNOME
SELECT Count(Cognome) AS TR
FROM NOMINATIVI
WHERE (Cognome>"R")
--
bye BlackMagic
ICQ: 85485468
Aiuta la ricerca sul cancro 
http://members.ud.com
Join
at:
http://members.ud.com/services/teams/team.htm?id=2E71C62A-8E67-48DB-B472-
BCA129B35412

 WHERE (Cognome>"R")
Infatti, giusto quello che so fare anch'io. Restituisce 3.
Esattamente quello che non voglio. Hai dimenticato la Group By.

Black, mi rendo conto di aver risposto in un modo scorretto.
Ti chiedo scusa, ma sono nervosissimo per 'sta ..gata che mi blocca.

 Ti chiedo scusa, ma sono nervosissimo per 'sta ..gata che mi blocca.
no problem,
ho provato anche usando DISTINCT, ma la somma è sempre 3.... non
ho capito che db usi, ma credo access vero? altrimenti hai già provato
con una subquery?


 con una subquery?
ADO (o DAO, è indifferente) con Access o SQL Server, indifferente.
La finalità sarà solo per ADO+SQL Server, ma non è importante.
Uso la Group By per evitare DISTINCT (e DISTINCTROW, non ammessa in ADO).
Come ho scritto (alura? ;-) ), la Count pare non accettare le subqueries.
Il problema è, comunque, assolutamente generale e, se vogliamo, puramente
teorico/didattico, anche se ne ho assolutamente bisogno in pratica perchè
ADO con apertura adOpenDynamic non gestisce il RecordCount.

 ADO con apertura adOpenDynamic non gestisce il RecordCount.
sicuro?
aprendo con adUseClient, adOpenDynamic la recordcount funziona,
usando adUseServer, adOpenDynamic no, quindi se puoi usare i cursori
lato client ti salvi, se devi usare quelli lato server  sei fregato :-))

 ADO con apertura adOpenDynamic non gestisce il RecordCount.
Ciao Lupo,
forse il metodo GetRows potrebbe fare al caso tuo..
lasciando la tua query così com'è, anzi, se ti serve solo il
surrogato di recordCount, mi sa che il COUNT
manco ti serve più, prova a fare di questo dopo aver aperto il rs:
Dim Numrec as variant
Numrec = Rs.GetRows
Debug.Print UBound(Numrec, 2) + 1
sono andato un po' a memoria, comunque per
ulteriori dettagli dai un'occhiata al metodo GetRows..
può darsi che vada bene.
Ciao
 Valter

 lato client ti salvi, se devi usare quelli lato server  sei fregato :-))
Certo, lato server, la velocità lato client è improponibile!

 può darsi che vada bene.
Ciao Valter. A parte che non mi restituisce quel che voglio (ho provato
anche, dopo aver letto l'help a fare =rs.getrows(999999) e mi ha riempito il
disco e non so dove), ho la sensazione che questo prenda i dati reali e li
metta nella variant a matrice sul client. Quindi impiega ben di più che fare
un cursore lato client, no?!
Io vorrei usare lato server, adOpenDynamic e surrogare il .Clone (questo
l'avrei già fatto) e il recordCount che non ho in tali condizioni.
Ho provato la @@ROWCOUNT in SQL Server e funziona, ma non so come sbatterla
in un comando SQL unico, necessita del GO, credo, e, comunque non ho la
certezza, facendo un comando SQL subito dopo la mia query (con un comando
diretto di tipo T-SQL) che quel valore non venga inficiato da altre query
che, nel frattempo e da altre postazioni, possano essere state eseguite.

che, nel frattempo e da altre postazioni, possano essere state eseguite.
Usa una stored procedure.
-- 
ciao, hal

 Usa una stored procedure.
Non posso, nel senso che l'informazione mi serve per il recordset aperto in
quel momento e non è predeterminato, non lo conosco. E' lui (e ne ho un tot)
ed è stato modificato (selezioni, ordinamenti, etc) dall'operatore, insomma,
non è fisso.

 wrote in message
news:F87N8.33122$K4.8...@twister2.libero.it...

Proverei a posizionarmi in testa al recordset e a fare un ciclo che acceda
sequenzialmente ad ogni record fino alla fine, incrementando
contemporaneamente un contatore. Scusa la scarsa efficienza, ma se hai
bisogno...

 bisogno...
Beh, abbi pazienza, ma cosě preferirei usare il lato cliente, non ti pare?

Ciao Lupo,
la soluzione che ti propongo funziona ma ha lo svantaggio di poter leggere
il RecordCount solo DOPO aver utilizzato il Recordset. Semplicemente ho
creato una Stored Procedure con due SELECT, la prima con i dati che ti
servono, mentre le seconda con il valore della funzione @@ROWCOUNT.
Lato VB ricorro al metodo NextRecordset per leggere il RecordCount.
CREATE PROCEDURE upS_Nominativi
AS
SELECT DISTINCT Cognome, Nome
FROM Nominativi
WHERE Cognome > 'R'
ORDER BY Cognome, Nome
SELECT @@ROWCOUNT AS RecordCount
Private Sub Command1_Click()
    Dim cn As ADODB.Connection
    Dim cmd As ADODB.Command
    Dim rs As ADODB.Recordset
    Set rs = New ADODB.Recordset
    With rs
        .CursorLocation = adUseServer
        .CursorType = adOpenDynamic
        .LockType = adLockOptimistic
    End With
    Set cn = New ADODB.Connection
    cn.ConnectionString = "Provider=SQLOLEDB; Initial Catalog=Lavoro;
Integrated Security=SSPI"
    cn.Open
    Set cmd = New ADODB.Command
    With cmd
        Set .ActiveConnection = cn
        .CommandText = "upS_Nominativi"
        .CommandType = adCmdStoredProc
        Set rs = .Execute
    End With
    With rs
        Do Until .EOF
            Debug.Print "Cognome = " & !Cognome & vbTab & " - Nome = " &
!Nome
            .MoveNext
        Loop
    End With
    Set rs = rs.NextRecordset
    MsgBox "RecordCount = " & rs.Fields("RecordCount").Value
    rs.Close
    cn.Close
    Set rs = Nothing
    Set cmd = Nothing
    Set cn = Nothing
End Sub
Ciao!
--
Lorenzo Benaglia
UGIdotNET - 
http://www.ugidotnet.org

"Lorenzo Benaglia" <lben...@NOSPAMtin.it> ha scritto
Grazie, Lorenzo. Oggi la provo. ;-)))

Ho fatto 3 prove con Query Analyzer, ma non ho ben capito, dopo averla
creata, come eseguire la stored procedure (avrai ben capito che Sql Server
lo uso solo perchè ... devo).
Comunque, ho provato invece a creare una view (togliendo l'eventuale Order
By non ammesso) e poi a fare Select Count (*) from nome_view e ottengo quel
che voglio.
La domanda è: Siccome il mio comando SQL viene composto "al volo" e
continuamente modificato (con selezioni Where ulteriori che ne modificano il
numero di righe restituite), quanto può pesare il fatto di dover ogni volta
cancellare la view (o la sp se capirò mai come fare) e ricrearla col comando
SQL aggiornato e più recente, oppure crearne tante con nome ovviamente
univoco ad ogni variazione, considerando sempre l'ultima, e cancellarle alla
fine?
E' praticabile o mi sto incamminando in un campo minato dove poteri
"correre" molto poco? Grazie.

 wrote in message
news:lJpN8.37046$K4.9...@twister2.libero.it...


 Per maggiori dettagli sul suo utilizzo consulta i Books On Line di SQL
Grazie di tutto, Lorenzo, volevo essere più preciso, chissà mai che non ti
venga qualche idea. Per tutte le "normali" SELECT ho risolto con una SQL che
mi esegue, con tempi buoni, il Count(*) dal comando originale, ricavando
così il benedetto RecordCount che non avrei altrimenti.
Il problema ora è limitato solo a quelle Select con DISTINCT o con GROUP BY
per le quali, non ammettendo il COUNT delle sottoqueries, non posso adottare
la stessa tecnica.

 la stessa tecnica.
Se per te non è un problema avere il RecordCount su un secondo Recordset
referenziabile con il metodo .NextRecordset, potresti adottare la tecnica
che ti ho suggerito:
- Scrivi una (o +) Stored Procedure(s) che prevedano un parametro di input
per la clausola Where;
- Componi dinamicamente lo statrement con la sp_executesql ed esegui il
tutto;
- Al termine esegui una SELECT @@ROWCOUNT AS RecordCount;
Per quale motivo nella tua applicazione non è possibile utilizzare un
cursore client side?
Non penso che nella griglia vengano caricati milioni records... (come
farebbe il povero utente a selezionare quello giusto?!).


 farebbe il povero utente a selezionare quello giusto?!).
Ne carico/espongo 60/100 per volta, ma il recordset che devo inizialmente
comporre ne può (potenzialmente) contenere migliaia. Lo devo comporre tutto
(e poi esporlo a pezzettoni muovendomi al suo interno in su e in giù) perchè
non so, a priori, cosa l'utente vorrà farci, magari una stampa di tutto
l'archivio di magazzino (40.000 articoli). Tutto quanto posso
prevedere/imporre (per esempio le iniziali preimpostate del codice o i
contenuti di una o più descrizioni) fa già parte della Select iniziale, ma,
come dicevo, se uno vuol esporre tutto, mica glielo posso impedire.

 come dicevo, se uno vuol esporre tutto, mica glielo posso impedire.
Perdonami, ma per stampare i 40.000 articoli, li caricheresti tutti in
griglia?!
A cosa servirebbe?
Anche utilizzando un cursore server side ci vorrà del tempo a popolare il
controllo.
Non sarebbe meglio prevedere una funzionalità a parte per le stampe e
limitare sempre, non so, a 500 il numero massimo di records visualizzabili
dall'applicazione?
E' solo un'idea...


 dall'applicazione?
Ohibò, ho detto che creo il recordset completo, non che carico completamente
la griglia...

la griglia...
Uhm, perche' devi caricarlo completamente (stampe a parte, ma nel caso delle
stampe le prestazioni sono meno stringenti, anche perche' entrano in gioco
anche le caratteristiche della rete e la sua situazione in quel momento,
i tipo di stampante, i job in coda, ecc. ecc.).
Penso che la proprieta' CacheSize potrebbe esserti utile (sempre che usi
la griglia in modalita' unbound), cosi' lavori con max 20 / 30 record per volta
(a meno che l' utente non abbia un maxi-schermo e font microscopici).
Usavo questa tecnica con odbc e tabelle da piu' di un milione di record:
vb5 e 32 mb di ram.
-- 
ciao, hal

 i tipo di stampante, i job in coda, ecc. ecc.).
Ok, Hal, spiegami, per favore.
Diciamo che siamo in gestione articolo di magazzino, l'operatore digita "A"
e preme un tasto funzione o un bottone per vedere l'elenco degli articoli
con codice che comincia (o è superiore) con "A". Ce ne sono 30.000. Oppure
non digita un bel niente e vuole l'elenco degli articoli, diciamo 50.000. Io
che faccio? Creo il recordset (completo) con le (poche) scelte restrittive
fatte e ne espongo i primi 50 records in una griglia no-bound.
Ora l'operatore può (e deve potere) fare ricerche, selezioni, ordinamenti,
etc. su qualsiasi combinazione di colonne. Inoltre, stampe, autocomposizione
di altre SQL, scelte in cascata, messa in nota di righe,
"selezionare"/identificare più righe non contigue, insomma molto. Il
problema è: Se anche caricassi nel recordset 50 righe (carico solo quelle
nel recordset, oltre ad esporre solo quelle in griglia), come faccio a
esporre le 50 righe precedenti, seguenti, anche senza contiguità in funzione
di una ricerca, una selezione o di un ordinamento fatto dall'operatore un
istante prima.
Certo, è facile prevedere una griglia semi-statica che espone una porzione
del recordset in su o in giù. A quel punto, ovvio, il recordset viene
composto con quelle _sole_ righe e, con qualche banalità, viene poi
ricomposto con le 50 righe immediatamente precedenti o seguenti. Perchè ho
fatto questo? Perchè (con DAO e con prestazioni più che accettabili, certo,
con un numero limitato di postazioni) io demando alle mie utility di
gestione griglia, assolutamente generiche (non sanno cosa fanno, a loro
passo un recordset già inizialmente composto), assolutamente molto (se non
tutto) senza scrivere (salvo qualche rarissima eccezione) un'sola
applicazione specifica per ogni tipo di informazioni gestite. Per chiarire
ulteriormente, non per banalizzare, dico: Perchè scrivere una procedura di
stampa per gli articoli, una per i movimenti, una per i documenti, una per i
clienti, etc.? Se compongo una griglia (e all'utente lascio la possibilità
di modificarla come vuole, magari con un banalissimo ordinamento che io non
voglio prevedere da programma perchè ne mancherebbe sempre uno) e la passo a
una routine che si limita a stamparla as-it-is, comprendi che io, in
pratica, non scrivo una sola procedura di stampa (sarebbero tutte uguali,
eppur tutte diverse!)?! Ovvio, era un esempio, giusto per farmi meglio
capire.

applicazione specifica per ogni tipo di informazioni gestite. 
Ottima cosa. Con i principi sopra esposti lavori con griglie assolutamente
generiche.
-- 
ciao, hal

 generiche.
Sì, e vorrei continuare a farlo. Ecco perchè tutti i miei problemi.
Grazie, hal! Ciao.

DAO (o sì?)
1. Dimentica DAO con Access se lavori con ADO con db client server:
    le logiche architetturali sono completamente diverse.
2. Una cosa e' MaxRecords (o come si chiama) ed un' altra cosa e' CacheSize
    (che non so che in DAO ci fosse, ma non credo che avrebbe avuto un gran
    senso visto che DAO, rete o no, lavora _sempre_ in locale.
-- 
ciao, hal