Tutorial de ADO

Aqui você poderá oferecer suas Contribuições, Dicas e Tutoriais (Texto ou Vídeo) que sejam de interesse de todos.

Moderador: Moderadores

Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Tutorial de ADO

Mensagem por JoséQuintas »

Só pro texto ficar num lugar mais adequado:

ADO é como se fosse uma RDD, pra ler qualquer base de dados.
Neste caso o "driver" de Excel permite trabalhar com a planilha como se fosse banco de dados.
No ADO tem também conector pra TXT, XML, etc.
Trabalha-se como qualquer banco de dados, igual pra todos.

No caso do Harbour, as RDDs permitem trabalhar "estilo DBF".
No caso do ADO, não sei dizer se é "estilo Access" ou estilo ADO mesmo.
Ele tem suas propriedades e métodos, do mesmo jeito que o Harbour tem pra DBF.

Recordset é a tabela, como se fosse um arquivo DBF.
Tem-se as funções :Eof(), :MoveNext(), :MovePrevicous(), :RecordCount(), etc.

Cada registro, igual o DBF tem seus campos, acessados por Fields()
:Name, :Value, etc.

Gerar o recordset (temporário) com o resultado de uma consulta

Código: Selecionar todos

Rs := Conexao:Execute( "SELECT * FROM tabela" )
Trabalhar com recordset

Código: Selecionar todos

? "total de registros:" + Str( Rs:RecourdCount() )
? "Total de campos:" + Str( Rs:Fields:Count() )
DO WHILE ! Rs:Eof()
   ? Rs:Fields(0):Value // o primeiro item é 0 e não 1
   Rs:MoveNext()
ENDDO
Acessar os campos

Código: Selecionar todos

? Rs:Fields(1):Value
? rs:Fields( "CODIGO" ):Value
rs:Fields( "CODIGO" ) = valor
rs:Edit()
rs:Update()
rs:Append()
É um acesso universal a qualquer base de dados, praticamente um RDD universal.
Não é muito divulgado no Harbour porque é formato proprietário da Microsoft, e mais específico pra Windows.

Simplificando: temos acesso a qualquer base de dados no Windows... mas é Windows. Até Excel está incluso nisso.
O uso é livre, mas não é Open Source, e talvez não tenha igual em Linux.

Talvez até isso tenha sido considerado como "A Microsoft querendo dominar o mercado"....rs
Enquanto isso permite usar qualquer base de dados GRÁTIS, no Harbour indicam produtos comerciais PAGOS pra ficar igual DBF.

ADO é só a parte intermediária, o ODBC é que vai dar o tratamento final, uma espécie de driver. Sempre vai depender de existir um "driver" para o banco de dados, quanto mais compatível com ADO melhor. Por isso nem toda base de dados funciona a plena carga no ADO, porque não fizeram "tão compatível". Alguns, como os primeiros ODBC pra dBASE, eram somente pra leitura.
Daria até pra criar um aplicativo somente com ADO e nada mais, usando o formato do ADO pras bases de dados.
Não foi feito pra isso, mas é possível usar, substituindo DBFs por ADO.

Esta parte já seria pra fazer atualizações no recordset, ou até na base de dados, no estilo do ADO.
Como eu disse antes, tudo depende do ODBC ("driver") ter sido criado totalmente compatível com ADO, o que é difícil.
Mas comando SQL sempre funciona.

Código: Selecionar todos

rs:Fields( "CODIGO" ) = valor
rs:Edit()
rs:Update()
rs:Append()
rs:Find()
Esta última parte acabei NUNCA usando.
Mais informações, no site Microsoft, pra lista completa de métodos e propriedades, com muita coisa que NUNCA iremos usar.

Faltou aqui da conexão, ou do arquivo físico de ADO:

Código: Selecionar todos

Cn := win_OleCreateObject( "ADODB.Connection" )
Rs := win_OleCreateObject( "ADODB.Recordset" )
:Open()
:Close()
:ConnectionString
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar do usuário
asimoes
Colaborador
Colaborador
Mensagens: 4919
Registrado em: 26 Abr 2007 16:48
Localização: RIO DE JANEIRO-RJ

Tutorial de ADO

Mensagem por asimoes »

Voltado ao assunto:

Tenho uma consulta que retorna 8000 linhas, acontece o seguinte toda vez que o método execute é feito vem a ampulheta do windows de demora e a famosa mensagem do windows "Não está respondendo" Isso é muito chato ao meu ver, porque da impressão para o usuário que o sistema está falhando, no final o browser é carregado, existe alguma forma de resolver isso ? Notem que até os componentes da tela somem!
2018-03-08 12_40_41-.png
►Harbour 3.x | Minigui xx-x | HwGui◄
Pense nas possibilidades abstraia as dificuldades.
Não corrigir nossas falhas é o mesmo que cometer novos erros.
A imaginação é mais importante que o conhecimento. (Albert Einstein)
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Tutorial de ADO

Mensagem por JoséQuintas »

Talvez fazer o processo numa janela invisível.
Sem janela não vai ter esse efeito.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar do usuário
sygecom
Administrador
Administrador
Mensagens: 7131
Registrado em: 21 Jul 2006 10:12
Localização: Alvorada-RS
Contato:

Tutorial de ADO

Mensagem por sygecom »

asimoes,
Não seria o caso de colocar uma paginação, pra ir trazendo de pouco em pouco os registros ? Tipo 500 por pagina...
Leonardo Machado
xHarbour.org + Hwgui + PostgreSql
Avatar do usuário
asimoes
Colaborador
Colaborador
Mensagens: 4919
Registrado em: 26 Abr 2007 16:48
Localização: RIO DE JANEIRO-RJ

Tutorial de ADO

Mensagem por asimoes »

Tentei até por thread mais não funcionou,

O incrível é 8000 registros coisa boba para dbf rs
►Harbour 3.x | Minigui xx-x | HwGui◄
Pense nas possibilidades abstraia as dificuldades.
Não corrigir nossas falhas é o mesmo que cometer novos erros.
A imaginação é mais importante que o conhecimento. (Albert Einstein)
Avatar do usuário
asimoes
Colaborador
Colaborador
Mensagens: 4919
Registrado em: 26 Abr 2007 16:48
Localização: RIO DE JANEIRO-RJ

Tutorial de ADO

Mensagem por asimoes »

Pensando uma conta aqui

Para saber o número de linhas da tabela faria antes select count(*) from tabela
8000 / 500 = 16


Teria que montar um vetor com isso
E limitando por rownum >= e <=

SELECT * FROM TABELA WHERE ... FILTROS AND ROWNUM >= Vetor[1] and rownnum <= Vetor[2]

Vai fazer 16 selects



Essa tabela eu alimento um dbf temporário

Código: Selecionar todos

Vetor
01	0001	0501
02	0502	1002
03	1003	1503
04	1504	2004
05	2005	2505
06	2506	3006
07	3007	3507
08	3508	4008
09	4009	4509
10	4510	5010
11	5011	5511
12	5512	6012
13	6013	6513
14	6514	7014
15	7015	7515
16	7516	8016 esse aqui seria o caso de fixar a conta para 8000

To viajando aqui, não sei se vai ficar legal, rs
►Harbour 3.x | Minigui xx-x | HwGui◄
Pense nas possibilidades abstraia as dificuldades.
Não corrigir nossas falhas é o mesmo que cometer novos erros.
A imaginação é mais importante que o conhecimento. (Albert Einstein)
alxsts
Colaborador
Colaborador
Mensagens: 3092
Registrado em: 12 Ago 2008 15:50
Localização: São Paulo-SP-Brasil

Tutorial de ADO

Mensagem por alxsts »

Olá

Não seria o caso de melhorar a performance desta consulta? Verifique índices, chaves...

Para paginação, tem o exemplo DICA: PAGINAÇÃO EM CONSULTAS SQL

Seria o caso de colocar em uma procedure e passar os limites por parametro.
[]´s
Alexandre Santos (AlxSts)
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Tutorial de ADO

Mensagem por JoséQuintas »

É mesmo, faltou a pergunta principal: de quanta demora estamos falando? quantos segundos?
Precisa mesmo todos os campos? SELECT * FROM...
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar do usuário
asimoes
Colaborador
Colaborador
Mensagens: 4919
Registrado em: 26 Abr 2007 16:48
Localização: RIO DE JANEIRO-RJ

Tutorial de ADO

Mensagem por asimoes »

Pessoal,

Consegui montar a query fazendo paginação, logo mais eu posto aqui, respondendo ao Quintas, +- 40 segundos, depende também da utilização do banco.

Consegui trazer todos os registros sem o incomodo "não está respondendo"
►Harbour 3.x | Minigui xx-x | HwGui◄
Pense nas possibilidades abstraia as dificuldades.
Não corrigir nossas falhas é o mesmo que cometer novos erros.
A imaginação é mais importante que o conhecimento. (Albert Einstein)
Avatar do usuário
asimoes
Colaborador
Colaborador
Mensagens: 4919
Registrado em: 26 Abr 2007 16:48
Localização: RIO DE JANEIRO-RJ

Tutorial de ADO

Mensagem por asimoes »

AdoSel1 - função que traz uma linha
Exportando para tabela temporária em memória

Com isso resolvi o problema "não está respondendo" e até ficou mais rápido, antes +- 30 seg agora 6 seg.

Código: Selecionar todos

   cQuery := "SELECT Count(*) TOTAL FROM EXPEDIENTE.EXPEDIENTE"  
   
   IF AdoSel1( @cRecordSet, @aDados, cQuery, , @cErro ) = 0
      nTotal := aDados[1] // vetor contendo o total de linhas da tabela
      IF nTotal > 500
         aRowNum := {}
         nTotalSelect := nTotal / 1000 // traz 1000 linhas por vez até acabar
         nLinSel := 1          
         FOR I:=1 TO nTotalSelect
            aAdd( aRowNum, {nLinSel, nLinSel += 1000} )
            nLinSel ++
         NEXT
         aRowNum[nTotalSelect, 2] := nTotal
      ENDIF
   ENDIF
   
   
   cQuery := "SELECT *                          "
   cQuery += "FROM ( SELECT topn.*, ROWNUM rnum "
   cQuery += "FROM ( SELECT  E.*                "
   cQuery += "FROM EXPEDIENTE.EXPEDIENTE E      "
   cQuery += "ORDER BY ROWID ) topn             "
   cQuery += "WHERE ROWNUM <= ? )               " // LINHA FINAL
   cQuery += "WHERE rnum  >= ?                  " // LINHA INICIAL   
   
   FOR EACH oElemento IN aRowNum
      aResult := {}
      aChave  := { oElemento[2], oElemento[1] }
      IF AdoSelect( @cRecordSet, @aResult, cQuery, aChave, , @cErro ) = 0
         FOR EACH oElementoQuery IN aResult
            hwg_WriteStatus( ThisForm, 1, 'Aguarde... ' + Hb_NtoS( oElemento:__EnumIndex ) + "/" + Hb_NtoS( Len( aRowNum ) ) )
            ORGAO->( DBSeek( oElementoQuery[04] ) )
            aAdd( aExpediente, { oElementoQuery[05], ;
                                 SubStr( oElementoQuery[03], 5, 3 ) + SubStr( oElementoQuery[03], 1, 4 ), ;  
                                 Win_OemToAnsi( ORGAO->Descricao ), ; // Win_OemToAnsi para exibir caracteres acentuados no browse HwGui
                                 Win_OemToAnsi( oElementoQuery[08] ), ;
                                 Win_OemToAnsi( oElementoQuery[09] ), ;
                                 Win_OemToAnsi( oElementoQuery[10] ), ;
                                 IF(oElementoQuery[12] = '1', 'Sim','Não') } )
            hwg_DoEvents() 
         NEXT
      ENDIF    
   NEXT 
►Harbour 3.x | Minigui xx-x | HwGui◄
Pense nas possibilidades abstraia as dificuldades.
Não corrigir nossas falhas é o mesmo que cometer novos erros.
A imaginação é mais importante que o conhecimento. (Albert Einstein)
Avatar do usuário
asimoes
Colaborador
Colaborador
Mensagens: 4919
Registrado em: 26 Abr 2007 16:48
Localização: RIO DE JANEIRO-RJ

Tutorial de ADO

Mensagem por asimoes »

Quintas,

Como é que eu faço para criar uma query que faça leitura de registros de 1000 em 1000 até o fim da tabela ?
►Harbour 3.x | Minigui xx-x | HwGui◄
Pense nas possibilidades abstraia as dificuldades.
Não corrigir nossas falhas é o mesmo que cometer novos erros.
A imaginação é mais importante que o conhecimento. (Albert Einstein)
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Tutorial de ADO

Mensagem por JoséQuintas »

asimoes escreveu:Como é que eu faço para criar uma query que faça leitura de registros de 1000 em 1000 até o fim da tabela ?
Com MySQL é: limit x,y

por exemlo:

limit 1, 1000
limit 1001, 2000
etc
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar do usuário
asimoes
Colaborador
Colaborador
Mensagens: 4919
Registrado em: 26 Abr 2007 16:48
Localização: RIO DE JANEIRO-RJ

Tutorial de ADO

Mensagem por asimoes »

O exemplo tem 25404 registros, modifiquei o conteúdo de alguns campos por se tratar de dados de clientes, vejam o tempo que leva para ler a tabela.

Anexos
LerDbf.zip
(933.66 KiB) Baixado 163 vezes
►Harbour 3.x | Minigui xx-x | HwGui◄
Pense nas possibilidades abstraia as dificuldades.
Não corrigir nossas falhas é o mesmo que cometer novos erros.
A imaginação é mais importante que o conhecimento. (Albert Einstein)
Avatar do usuário
asimoes
Colaborador
Colaborador
Mensagens: 4919
Registrado em: 26 Abr 2007 16:48
Localização: RIO DE JANEIRO-RJ

Tutorial de ADO

Mensagem por asimoes »

Se não quiser usar a variável nRecno pode usar ResultSet:AbsolutePosition

Código: Selecionar todos

        IF Mod( ResultSet:AbsolutePosition, 1000 ) = 0 .OR. ResultSet:AbsolutePosition = 1
            @ 11,00 SAY "Tempo Lendo     : " + SecToTime( Seconds() - nSeconds )
            @ 12,00 SAY "Total Registros : " + Transform( nTot, "99999999")
            @ 13,00 SAY "Evento          : " + Transform( ResultSet:AbsolutePosition, "99999999")
            @ 13,Col() + 2 SAY Transform( ( ResultSet:AbsolutePosition / nTot ) * 100, "999.99%" )
         ENDIF
►Harbour 3.x | Minigui xx-x | HwGui◄
Pense nas possibilidades abstraia as dificuldades.
Não corrigir nossas falhas é o mesmo que cometer novos erros.
A imaginação é mais importante que o conhecimento. (Albert Einstein)
Avatar do usuário
asimoes
Colaborador
Colaborador
Mensagens: 4919
Registrado em: 26 Abr 2007 16:48
Localização: RIO DE JANEIRO-RJ

Tutorial de ADO

Mensagem por asimoes »

O que eu notei é que nos primeiros 1000 registros é rápido +- 10 segundos depois esse tempo vai aumentando até chegar aproximadamente 4 minutos ou mais a cada ciclo de 1000 registros.
►Harbour 3.x | Minigui xx-x | HwGui◄
Pense nas possibilidades abstraia as dificuldades.
Não corrigir nossas falhas é o mesmo que cometer novos erros.
A imaginação é mais importante que o conhecimento. (Albert Einstein)
Responder