Selecionando registro de um Recordset usando GetRows


Selecionar uma determinada quantidade de registros de um base de dados é uma das tarefas mais frequentes em aplicações usando banco de dados. E pode ser o gargalo da sua aplicação se não for bem planejada. A esta altura já cabe a pergunta : Como você faz para extrair registros de um base de dados ? Qual o método frequentemente utilizado ? Vamos analisar...

Selecionado registros da tabela Authors da base de dados Biblio.mdb

1-) Creio que muitos usam o seguinte código para tal tarefa:

Dim codigo as integer
Dim autor as string
Dim ano as integer

Set db = DBEngine.Workspaces(0).OpenDatabase(app.path & "\blibio.mdb")
Set rs = db.OpenRecordset("Authors", dbOpenTable)

Do Until tabela.EOF
  codigo = rs("Au_Id")
  autor = rs("Author")
  ano = rs("Year_Born")
  rs.movenext
  ....
  aqui voce realiza o seu processsamento
Loop

rs.close
set rs=nothing

Ou seja, você vai percorrendo (movenext) o Recordset , extraindo os registros e fazendo o processamento. Funciona ! voce pode dizer . Tudo bem , funciona , mas você já pensou no fato de que se o Recordset possuir 1000 registros e você está selecionando três campos vai ter 3000 requisições de leitura a sua base de dados ? E se a base de dados possuir 10.000 registros e você estiver selecionando 10 campos ? serão 100.000 requisições de leitura.

Para preencher um grid com os registros selecionados também enfrentamos o mesmo problema. Como os controles vinculados oneram demais o processamento, geralmente usamos o modo não vinculado(sem usar um controle de dados) dos grids (DBGrid) . Para preencher um grid no modo não vinculado precisamos conhecer dois parâmetros: quantas linhas e quantas colunas irão compor o grid. O número de linhas é o total de registros que estaremos selecionando do recordset e o número de colunas são os campos que selecionamos do recordset. Aqui começam os problemas...

Para conhecermos o número de campos do recordset é simples , usamos a propriedade Count do objeto Recordset, assim:

Dim icampos as integer

Set db = DBEngine.Workspaces(0).OpenDatabase(app.path & "\blibio.mdb")
Set rs = db.OpenRecordset("Authors", dbOpenTable)

icampos = rs.fields.Count

E para determinar a quantidade de registros selecionados ? Geralmente os métodos mais usados são:

1-) Usando a propriedade RecordCount

dim registros

Set db = DBEngine.Workspaces(0).OpenDatabase(app.path & "\blibio.mdb")
Set rs = db.OpenRecordset("Authors", dbOpenTable)

rs.movelast
rs.movefirst

registros = rs.Recordcount....

Ou seja você percorrendo todo o Recordset até o final e volta depois ao início para saber quantos registros vai ter o grid. Acho que nem preciso dizer que este método não é aconselhável .

2-) Usando a função agregada Count da SQL

dim registros

Set db = DBEngine.Workspaces(0).OpenDatabase(app.path & "\blibio.mdb")

Set rs = db.OpenRecordset("Authors", dbOpenTable)

set rstmp=db.OpenRecordset("SELECT Count(*) as Registros From Authors")

registros = rstmp.registros
....

Este método pode ser mais rápido que o anterior mas você vai precisar criar dois recordsets : um para preencher o grid e outro para obter a quantidade de registros.

Existe uma forma melhor de fazer o serviço ? Sim existe , usando o método GetRows, vejamos então...

O método GetRows foi introduzido ainda nos tempos da DAO 3.0 e RDO 1.0 , mas apresentava problemas de implementação . Com o advento da ADO o método voltou aperfeiçoado e funcionando perfeitamente.

O objetivo em usar o método GetRows é selecionar múltiplos registros de um recordset e armazená-los em um vetor bidimensional. Nosso foco será o método GetRows da ADO 2.0.

A sintaxe na utilização de GetRows é a seguinte:

Nome_do_Vetor = Recordset.GetRows (Linhas , Inicio, Campos )

GetRows é usado para copiar registro de um Recordset para um vetor bidimensional. O primeiro item do vetor identifica os campos (colunas) e o segundo item identifica os registros.

A variável associada ao vetor tem o seu tamanho alocado dinamicamente quando da seleção dos registros.

Se não for informado o valor do argumento Linhas , GetRows retorna todos os registros do recordset e se for solicitado mais registros do que o disponível , GetRows retorna somente a quantidade existente.

Para restringir os campos selecionados, voce pode passar como argumento o nome do campo ou o seu número ou ainda passar como argumento um vetores de campos/números . Após GetRows retornar os registros do Recordset o próximo registro não lido se torna o registro atual, ou se não há mais registros , a propriedade EOF é definida como True.

Vejamos então o código para selecionar registros de um recordset usando GetRows:

Dim codigo as integer
Dim autor as string
Dim ano as integer
Dim contador as integer
Dim dbvetor as variant

Set db = DBEngine.Workspaces(0).OpenDatabase(app.path & "\blibio.mdb")
Set rs = db.OpenRecordset("Authors", dbOpenTable)

dbvetor= rs.GetRows

rs.close
set rs=nothing
db.close

numero_de_colunas   = Ubound(dbvetor,1)
numero_de_registros = Ubound(dbvetor,2)

for contador=0 to numero_de_registros
  codigo = dbvetor(contador,1)
  autor = dbvetor(contador,2)
  ano = dbvetor(contador,3)
  ....
  aqui voce realiza o seu processsamento

next

Vamos entender o código acima:

  1. dbvetor= rs.GetRows - Retorna todos os registros do recordset e os armazena na variável bidimensional dbvetor. dbvetor tem duas dimensões dbvetor(1,2) : a primeira identifica os campos a segunda os registros.
  2. Após selecionarmos os registros e armazená-los em uma variavel não precisamos mais do recordset nem da base de dados , por isso fechamos tudo: rs.close , db.close
  3. Determinamos o número de campos dos registros selecionados e o numero de registros retornados usando a função UBound. Esta função tem a seguinte sintaxe: UBound(nome_do_vetor[, dimensão])

Ela retorna o valor maior para o indice do vetor na dimensão indicada. Assim se temos um vetor tridimensional definido como:

Dim A(1 To 100, 0 To 3, -3 To 4)
Instrução Valor Retornado
UBound(A, 1) 100
UBound(A, 2) 3
UBound(A, 3) 4
Assim quando fizemos:
numero_de_colunas = Ubound(dbvetor,1)
numero_de_registros = Ubound(dbvetor,2)

Estamos retornando em numero_de_colunas o maior valor do índice para a primeira dimensão: Ora este é o valor relacionado a quantidade de campos selecionado e estamos retornando em numero_de_registros o maior valor para índice da segunda dimensão que é o valor relacionado com a quantidade de registros.

  1. Agora basta percorrer o nosso vetor e fazer o processamento desejado, com as seguintes vantagens : o acesso é mais rápido pois estamos trabalhando com um vetor na memória , não estamos acessando o recordset nem a base de dados e nosso código ficou enxuto e fácil de manter.
for contador=0 to numero_de_registros
   codigo = dbvetor(contador,1)
   autor = dbvetor(contador,2)
   ano = dbvetor(contador,3)
....
aqui voce realiza o seu processsamento

next

Para encerrar abaixo temos um exemplo simples e prático de preenchimento de um MSFlexgrid usando o GetRows:

Private Sub Command1_Click()
Dim cnn As New ADODB.Connection
Dim rst As New ADODB.Recordset
Dim fld As ADODB.Field
Dim avarData() As Variant
Dim introws As Integer
Dim i As Integer
Dim j As Integer
Dim linha As String

'Ábre o Recordset
cnn.Open "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\teste\nwind.mdb;"
'Open the forward-only, read-only recordset
rst.Open "Select * from Customers", cnn, adOpenForwardOnly, adLockReadOnly

'Seleciona todos os registros e armazena no vetor avarData
avarData = rst.GetRows

'fecha o recordset
rst.Close
Set rst = Nothing

'verifica se há registros selecionados
If introws > UBound(avarData, 2) Then
    MsgBox "Não ha registros para selecionar ...", vbAbortRetryIgnore, "JcmSoft"
    Exit Sub
End If

'calcula o total de campos e registros selecionados
colunas = UBound(avarData, 1)
registros = UBound(avarData, 2)

'define o numero de colunas do grid
Grid1.Cols = colunas
'defina as linhas e colunas fixas
Grid1.FixedCols = 0
Grid1.FixedRows = 1

'Preenche o grid
For i = 0 To registros
  For j = 0 To colunas
    linha = linha & avarData(j, i) & Chr(9)
 Next j
    Grid1.AddItem linha
    linha = ""
Next i
End Sub

Private Sub Command2_Click()
  Unload Me
End Sub

Ao executar o projeto inicialmente você verá a tela1 abaixo e , após clicar no botão Preencher Grid terá a figura 2.0 :

Bem... espero que façam bom proveito ....