Página 1 de 2

Trabalhar com ADO recordset

Enviado: 14 Out 2014 03:56
por JoséQuintas
Alguém sabe como trabalhar com ADO recordset?
Achei que era Access, mas não é.

Gerei assim, depois de um select:

Código: Selecionar todos

rs := cnMySql:Execute( "SELECT * FROM harbourdoc" )
rs:Save( "d:\temp\harbourdoc.mdb" )
Consigo usar assim, lendo sequencial:

Código: Selecionar todos

   rs := win_OleCreateObject( "ADODB.Recordset" )
   rs:Open( "d:\temp\harbourdoc.mdb" )
   DO WHILE .NOT. rs:Eof()
      APPEND BLANK
      REPLACE name       WITH rs:Fields( "NAME" ):Value
      REPLACE oneliner   WITH rs:Fields( "ONELINER" ):Value
      REPLACE Syntax     WITH rs:Fields( "SYNTAX" ):Value
      REPLACE Constructo WITH rs:Fields( "CONSTRUCTOR" ):Value
      REPLACE Datalink   WITH rs:Fields( "DATALINK" ):Value
      REPLACE DataNoLink WITH RS:Fields( "DATANOLINK" ):Value
      REPLACE MethodsLin WITH rs:Fields( "METHODSLINK" ):Value
      REPLACE Arguments  WITH rs:Fields( "ARGUMENTS" ):Value
      REPLACE Returns    WITH rs:Fields( "RETURNS" ):Value
      REPLACE Descriptio WITH rs:Fields( "DESCRIPTION" ):Value
      REPLACE Template   WITH rs:Fields( "TEMPLATE" ):Value
      REPLACE Library    WITH rs:Fields( "LIBRARY" ):Value
      REPLACE AltCategor WITH rs:Fields( "ALTCATEGORY" ):Value
      REPLACE AltSubCate WITH rs:Fields( "ALTSUBCATEGORY" ):Value
      REPLACE AltGroup   WITH rs:Fields( "ALTGROUP" ):Value
      REPLACE Files      WITH rs:Fields( "FILES" ):Value
      REPLACE Compliance WITH rs:Fields( "COMPLIANCE" ):Value
      REPLACE SeeAlso    WITH rs:Fields( "SEEALSO" ):Value
      REPLACE Author     WITH rs:Fields( "AUTHOR" ):Value
      REPLACE Platform   WITH rs:Fields( "PLATFORM" ):Value
      REPLACE Remarks    WITH rs:Fields( "REMARKS" ):Value
      REPLACE LastUpdate WITH rs:Fields( "LASTUPDATE" ):Value
      ? rs:Fields( "NAME" ):Value
      rs:MoveNext()
   ENDDO
   rs:Close()
A dúvida é: É possível fazer selects, ordenar, pesquisar, etc?

Trabalhar com ADO recordset

Enviado: 14 Out 2014 09:34
por Itamar M. Lins Jr.
Quando eu trabalhei com VB eu usei MySql e tinha todos esses comandos, select, insert into etc... e era ADO...

Saudações,
Itamar M. Lins Jr.

Trabalhar com ADO recordset

Enviado: 14 Out 2014 10:12
por JoséQuintas
Sim tem.
Após um select do MySql eu salvei o resultado da pesquisa.
Mas o resultado parece ser apenas um arquivo igual DBF, e não uma base de dados aonde possa executar comandos SQL.

Aliás...
O interessante de usar ADO é isso: tudo acaba sendo através de arquivos temporários nesse formato.
Se existisse um ADOHarbour, bastaria que esse temporário fosse um DBF, mas usando ADO direto o formato é esse mesmo.
E ao contrário do que eu pensava, o arquivo temporário não deixa nada lento (lógico, depende também do que está sendo selecionado).

Só como comentário:

Cheguei a usar os arquivos Clipper no VB em simultâneo ao Clipper.
Pra isso usava o ADS Local - ODBC do Advantage Database Server, mas uso local.
A SIXCDX também tinha algo parecido, mas nunca consegui usar no VB.

Um pequeno trecho só pra mostrar o SQL aplicado a DBF fica igual aos outros:
Selecionando dados de conhecimentos, contratos de frete e ordens de coleta pra comparação em um gráfico, e também pra visualizar num "'dbedit".
São 2 comandos SQL pra ter o resultado pro "dbedit" e outro para o resultado pro gráfico, apesar das informações virem de pelo menos 4 dbfs diferentes. Naquela época não existia o subselect no ADS, senão eram só 2.

Código: Selecionar todos


cSql = "select " & _
   "cnDatEmi DtEmissao, " & _
   "count(*) CtrcQtd, " & _
   "Sum(cnPeso) CtrcPeso, " & vbCrLf & _
   "Sum(cnValor) CtrcValor, " & _
   "Sum(cnVlMerc) ValorMerc, " & _
   "0 CFQtd, " & vbCrLf & _
   "0 CFValor, " & _
   "0 ColetaQtd, " & _
   "0 ColetaVlr, " & vbCrLf & _
   "0 ColVlMerc " & vbCrLf & _
   "into lixo " & _
   "From gtconhe group by DtEmissao "
cSql = cSql & _
   "union all " & vbCrLf & _
   "select cfDatEmi DtEmissao, " & _
   "0 CtrcQtd, " & _
   "0 CtrcPeso, " & vbCrLf & _
   "0 CtrcValor, " & _
   "0 ValorMerc, " & _
   "count(*) CFQtd, " & vbCrLf & _
   "Sum(CFValor) CfValor, " & _
   "0 ColetaQtd, " & _
   "0 ColetaVlr, " & vbCrLf & _
   "0 ColVlMerc " & vbCrLf & _
   "From gtcontr group by DtEmissao "
cSql = cSql & vbCrLf & _
   "union all " & _
   "Select " & _
   "ceDatEmi DtEmissao, " & _
   "0 CtrcQtd, " & vbCrLf & _
   "0 CtrcPeso, " & _
   "0 CtrcValor, " & _
   "0 ValorMerc, " & vbCrLf & _
   "0 CFQtd, " & _
   "0 CFValor, " & _
   "Count(*) ColetaQtd, " & vbCrLf & _
   "Sum(ceValFat) ColetaVlr, " & _
   "Sum(jpnftr1.ntValor) ColVlMerc " & vbCrLf & _
   "from jpordem " & _
   "left join jpnftr1 on jpordem.ceNumLan = jpnftr1.ntColeta " & _
   "group by DtEmissao " & vbCrLf
   Set Rs = RsFromConexao(cnConn, cSql)
   Rs.Close
   cnConn.Close
   cSql = "select DtEmissao, Sum(CtrcQtd) CtrcQtd, Sum(CtrcPeso) CtrcPeso,  " & _
   "Sum(CtrcValor) CtrcValor, Sum(ValorMerc) ValorMerc, " & vbCrLf & _
   "Sum(CFQtd) CFQtd, Sum(CFValor) CFValor, " & _
   "Sum(ColetaQtd) ColetaQtd, Sum(ColetaVlr) ColetaVlr, Sum(ColVlMerc) ColVlMerc " & _
   "from lixo group by DtEmissao order by DtEmissao Desc "
   Set Rs = RsFromConexao(cnConn, cSql)
   Set MSHFlexGrid2.DataSource = Rs
   Rs.Close
   cnConn.Close
   cSql = "select Year(DtEmissao)*100+Month(DtEmissao) Mes, " & _
   "Sum(CtrcQtd) CtrcQtd, Sum(CtrcPeso) CtrcPeso,  Sum(CtrcValor) CtrcValor, Sum(ValorMerc) ValorMerc, " & vbCrLf & _
   "Sum(CFQtd) CFQtd, Sum(CFValor) CFValor, " & vbCrLf & _
   "Sum(ColetaQtd) ColetaQtd, Sum(ColetaVlr) ColetaVlr, Sum(ColVlMerc)ColVlMerc " & _
   "from lixo group by Mes order by Mes Desc "
   Set Rs = RsFromConexao(cnConn, cSql)

Trabalhar com ADO recordset

Enviado: 14 Out 2014 11:08
por rochinha
Amiguinhos,

Em meus exemplos de uso das funções ADOxB voces podem encontrar os métodos para estes variados usos.

Um recordset pode ser visto como uma área, bastando para isto analisar o uso do objeto que o suporta.

Se voce usar uma variável para suportar um recordset contendo os valores de uma ou mais tabelas mas deseja ter várias outras basta criar mais recordsets com nomes especificos.

No seguinte exemplo dou uma alusão de abertura de várias tabelas e o coração deste recurso está na função ADOSelect() em conjunto com ADOUse().

Código: Selecionar todos

Function Teste()
StrDatabase := [adomysql]
StrServer := [mysql4.shoppmarketing.com]
StrPort := 3306
StrUserID := [adomysql_user]
StrUserPWD := [adomysql_pass]
StrDriver := "MySQL ODBC 3.51 Driver"

StrConnection := "driver={" + StrDriver +"};database=" + StrDatabase + ;
";server=" + StrServer + ;
";uid=" + StrUserID + ;
";pwd=" + StrUserPWD + ;
";option=35"

MsgRun( "Conectando…" )

ADO CONNECT StrConnection

// Abre as tabelas existentes na base
ADO USE clientes
ADO USE siglas

// Verifica se ja possuem dados
ADO SELECT clientes
nRegistros := ADORecCount()
if nRegistros = 0
ADO APPEND BLANK
ADO REPLACE nome WITH "ROCHINHA"
ADO REPLACE email WITH "EMAIL@ISP.COM.BR"
ADO COMMIT 
endif

ADO SELECT siglas
nRegistros := ADORecCount()
if nRegistros = 0
ADO APPEND BLANK
ADO REPLACE uf WITH "SP"
ADO REPLACE estado WITH "SAO PAULO"
ADO COMMIT 
ADO APPEND BLANK
ADO REPLACE uf WITH "RJ"
ADO REPLACE estado WITH "RIO DE JANEIRO"
ADO COMMIT 
endif

MsgRun( "Executando…" )
ADO SELECT clientes
ADO GOTOP

MsgRun( "Executando SET FILTER TO nome like '*tete*'…" )
ADO SET FILTER TO "nome like '*tete*'"
if ADOEof()
? 'Nada foi filtrado'
ADO SET FILTER TO
ADO GOTOP
endif
Browse( oRs )
ADO SET FILTER TO

MsgRun( "Executando LOCATE nome like 'TESTES'…" )
ADO LOCATE "nome like 'TESTES*'"
if ADOEof()
? 'Nada foi encontrado'
ADO GOTOP
endif
Browse( oRs )

ADO CLOSE
return .t.
O interessante é pensar nas possibilidade advindas deste uso. Um exemplo foi uma duvida de um amigo do Maranhão que necessitava passar dados de uma base Access para MySQL. Neste caso fazendo-se o uso de conexões multiplas usando por exemplo:

Código: Selecionar todos

ADO CONNECT StrMDBConnection
ADO CONNECT StrMySqlConnection
Os recordset abertos em cada conexão poderiam ser lidos transparentemente e os dados transportados de uma base a outra. Lógico que neste caso é apenas uma idéia, pois não testei para verificar quais alterações nas funçoes da biblioteca seriam necessárias para este suporte.

usando um trecho de seu código e demonstrando o uso de áreas você teria:

Código: Selecionar todos

 rs[1] := win_OleCreateObject( "ADODB.Recordset" )
 rs[1]:Open( "d:\temp\harbourdoc.mdb" )
 DO WHILE .NOT. rs:Eof()
   APPEND BLANK
   REPLACE name   WITH rs[1]:Fields( "NAME" ):Value
   REPLACE oneliner WITH rs[1]:Fields( "ONELINER" ):Value
   ...
   rs[1]:MoveNext()
 ENDDO
 rs[1]:Close()
Veja que neste caso o recordset passou de usar uma variável padrão para uma variável de vetor. Neste caso cada recordset poderá ser alocada para um elemento do vetor e fácilmente recuperado. Tenha em mente que só alterei a variável para te demonstrar sendo que o comando OPEN do seu código talvez não funcionaria.

Trabalhar com ADO recordset

Enviado: 14 Out 2014 18:00
por JoséQuintas
Só pra clarear mais pra quem nunca mexeu com isso.

Código: Selecionar todos

cnMySql := win_OleCreateObject( "ADODB.Connection" )
cnMySql:Open()
Isso é uma conexão com um banco de dados. Só definir os parâmetros da conexão, e isso já define o banco de dados.
O open vai abrir a conexão, deixando pronta pra uso.

Código: Selecionar todos

rsMySql := cnMySql:Execute( "SELECT * FROM cadcli" )
Isso trás o resultado da consulta para o recordset rsMySql, que seria equivalente a um arquivo.
É temporário, se está em disco ou memória, é o que menos importa.
O importante é que está disponível pra uso.
O comando pode relacionar arquivos, ordenar, somar, agrupar, filtrar, combinar vários arquivos, etc.
O resultado é um único "arquivo temporário" com o resultado.

Código: Selecionar todos

DO WHILE .NOT. rsMySql:Eof()
   ? rsMySql:Fields( "NOME" ):Value
   rsMySql:MoveNext()
ENDDO
Esse seria o uso do resultado final.
Podemos comparar o Fields( "NOME" ):Value com o FieldGet(), com a diferença de que aceita nome ou número sequencial do campo.
Requer mais código fonte do que um DBF comum, mas estaria preparado pra qualquer base de dados.
Não importa o banco de dados, o resultado sempre vém em um arquivo no formato do "ADO".
O ADO está disponível em qualquer Windows. O "driver" pras bases de dados Microsoft já vém instaladas no Windows. Pra MySql e DBF, aí precisa instalar o "driver" correspondente, chamado de ODBC. No caso ODBC MySql, e ODBC do ADS que também atende uso local .
A grande maioria dos ODBCs são grátis, e aí é que fica mais legal ainda.

Mas só tem pra Windows.
Talvez por isso não tenha tanto incentivo, por não ser open source.
No Harbour só precisa da função win_OleCreateObject() da hbwin, e nada mais. Essa função deixa usar componentes pré-instalados no Windows.

Nem que seja pra quebra galho, sempre dá pra usar ADO.
Pode até acessar planilhas Excel por ele, sem precisar do Excel instalado

Mas voltando ao arquivo do recordset...
Eu salvei todo conteúdo do site harbourdoc pra um recordset.
Estou tentando montar alguma coisa disponível offline.
Em dbf precisa 4mb, e em recordset são 2mb, metade do tamanho.
Qualquer dos dois formatos compactados fica entre 400kb e 500kb.
A próxima tentativa vai ser instalar um Access pra criar um arquivo mdb.
A partir daí, daria pra usar comandos SQL pra ordenar, filtrar, etc.

Trabalhar com ADO recordset

Enviado: 14 Out 2014 18:21
por Itamar M. Lins Jr.
Quintas isso que vc está querendo já existe.
Eu faço com SQLMIX, que usa ODBC.
Porque o SQLMIX roda Linux/Windows e o ADO só via windows.

Saudações,
Itamar M. Lins Jr.

Trabalhar com ADO recordset

Enviado: 15 Out 2014 01:15
por rochinha
Amiguinhos,

Salvar o recordset é simples, mas só salva em XML. Veja no código http://www.5volution.com.br/downloads/forum/adoxb.txt como funciona as funções ADOSave() e ADOConvert().

Valores para PersistFormatEnum

Código: Selecionar todos

adPersistADTG	0	Saves in a Microsoft Advanced Data TableGram (ADTG) format.
adPersistXML	1	Saves in Extensible Markup Language (XML) format
adPersistADO	1	Saves in ADO's own Extensible Markup Language (XML) format. This value is the same as adPersistXML and is included for backwards compatibility
adPersistProviderSpecific	2	The provider will persist the Recordset using its own format
Se tiver afinidade em XML poderá trabalhar em cima do arquivo gerado.

Trabalhar com ADO recordset

Enviado: 27 Fev 2015 00:13
por JoséQuintas
Quintas isso que vc está querendo já existe.
Eu faço com SQLMIX, que usa ODBC.
Porque o SQLMIX roda Linux/Windows e o ADO só via windows.
Poderia mostrar como abre o recordset do ADO e faz os comandos SQL com SQLMIX?

Rochicha, não sei se percebeu, mas mostrou como acessar o MySql pela sua lib, mas não como abrir o recordset ADO.

Trabalhar com ADO recordset

Enviado: 27 Fev 2015 01:02
por Itamar M. Lins Jr.
Poderia mostrar como abre o recordset do ADO e faz os comandos SQL com SQLMIX?
Não abre via ADO. Usa acesso nativo é muito mais rápido.
Olhe a pasta \contribs\sddmy que vc vai entender melhor.
Os comandos são 100% SQL
? rddInfo( RDDI_EXECUTE, "DROP TABLE country" )
? rddInfo( RDDI_EXECUTE, "CREATE TABLE country (CODE char(3), NAME char(50), RESIDENTS int(11))" )
? rddInfo( RDDI_EXECUTE, "INSERT INTO country values ('LTU', 'Lithuania', 3369600), ('USA', 'United States of America', 305397000), ('POR', 'Portugal', 10617600), ('POL', 'Poland', 38115967), ('AUS', 'Australia', 21446187), ('FRA', 'France', 64473140), ('RUS', 'Russia', 141900000)" )

Código: Selecionar todos

#require "rddsql"
#require "sddmy"

#include "dbinfo.ch"
#include "error.ch"

REQUEST SDDMY
REQUEST SQLMIX

ANNOUNCE RDDSYS

FIELD RESIDENTS

PROCEDURE Main()

#if defined( __HBSCRIPT__HBSHELL )
   rddRegister( "SQLBASE" )
   rddRegister( "SQLMIX" )
   hb_SDDMY_Register()
#endif

   rddSetDefault( "SQLMIX" )

   ? "RDDs:"; AEval( rddList(), {| x | QQOut( "", x ) } )

   IF rddInfo( RDDI_CONNECT, { "MYSQL", "localhost", "test", , "test" } ) == 0
      ? "Unable connect to the server"
      RETURN
   ENDIF

   CreateTable()

   ? "Let's browse table (press any key)"
   Inkey( 0 )
   dbUseArea( .T., , "SELECT * FROM country", "country" )
   Browse()

   ? "Let's browse table ordered by resident count (press any key)"
   Inkey( 0 )
   INDEX ON field->RESIDENTS TAG residents TO country
   Browse()

   dbCloseAll()

   RETURN

STATIC PROCEDURE CreateTable()

   ? rddInfo( RDDI_EXECUTE, "DROP TABLE country" )
   ? rddInfo( RDDI_EXECUTE, "CREATE TABLE country (CODE char(3), NAME char(50), RESIDENTS int(11))" )
   ? rddInfo( RDDI_EXECUTE, "INSERT INTO country values ('LTU', 'Lithuania', 3369600), ('USA', 'United States of America', 305397000), ('POR', 'Portugal', 10617600), ('POL', 'Poland', 38115967), ('AUS', 'Australia', 21446187), ('FRA', 'France', 64473140), ('RUS', 'Russia', 141900000)" )

   RETURN
A parte que vc se refere em ADO seria essa aqui da query .
rsMySql := cnMySql:Execute( "SELECT * FROM cadcli" )
Em SQLMIX!
dbUseArea( .T., , "SELECT * FROM country", "country" )
Não precisamos de usar isso aqui no resultado "rs:Eof()" ou isso " rs[1]:Fields( "NAME" ):Value"
Não tem necessidade desse rs:(record set ?)

O resultado já está todo transformado para DBF na memória RAM, muito melhor!!! podemos trazer a resposta toda prontinha via SQL
"SELECT * FROM country ORDER BY LEFT JOIN..." entendeu agora ?
Essa linha abaixo:
IF rddInfo( RDDI_CONNECT, { "MYSQL", "localhost", "test", , "test" } ) == 0
Corresponde a essas todas em ADO:
StrDatabase := [adomysql]
StrServer := [mysql4.shoppmarketing.com]
StrPort := 3306
StrUserID := [adomysql_user]
StrUserPWD := [adomysql_pass]
StrDriver := "MySQL ODBC 3.51 Driver"

StrConnection := "driver={" + StrDriver +"};database=" + StrDatabase + ;
";server=" + StrServer + ;
";uid=" + StrUserID + ;
Entendeu o poder do SQLMIX ? Deixa essas outras opções no chinelo p/ quem entende de comandos em SQL e comandos em DBF ao mesmo tempo.

Saudações,
Itamar M. Lins Jr.

Trabalhar com ADO recordset

Enviado: 27 Fev 2015 01:11
por Itamar M. Lins Jr.
que usa ODBC.
Para as que não tem acesso nativo.
MSSQL usa ODBC, MySQl é nativo, PostGres é nativo, Oracle é nativo, FB é nativo.

Saudações,
Itamar M. Lins Jr.

Trabalhar com ADO recordset

Enviado: 27 Fev 2015 01:20
por Itamar M. Lins Jr.
Outro exemplo simples p/ abrir tabelas MDB.

Código: Selecionar todos

#require "rddsql"
#require "sddodbc"

#include "simpleio.ch"

REQUEST SDDODBC, SQLMIX

PROCEDURE Main()

#if defined( __HBSCRIPT__HBSHELL )
   rddRegister( "SQLBASE" )
   rddRegister( "SQLMIX" )
   hb_SDDODBC_Register()
#endif

   Set( _SET_DATEFORMAT, "yyyy-mm-dd" )

   rddSetDefault( "SQLMIX" )
   ? "Connect:", rddInfo( RDDI_CONNECT, { "ODBC", "DBQ=" + hb_DirBase() + "..\..\hbodbc\tests\test.mdb;Driver={Microsoft Access Driver (*.mdb)}" } )
   ? "Use:", dbUseArea( .T., , "select * from test", "test" )
   ? "Alias:", Alias()
   ? "DB struct:", hb_ValToExp( dbStruct() )
   Inkey( 0 )
   Browse()

   INDEX ON FIELD->SALARY TO salary
   dbGoTop()
   Browse()
   dbCloseArea()

   RETURN
Para incluir na tabela MATRIZ tem que usar SQL!
rddInfo( RDDI_EXECUTE, "INSERT INTO country values...
Essa parte dbgotop(), browse(), já é no resultado todo transformado em DBF VIRTUAL! Não tem mais nada de requisições ao servidor, podemos usar o comando xBase que quiser.

Saudações,
Itamar M. Lins Jr.

Trabalhar com ADO recordset

Enviado: 27 Fev 2015 01:33
por Itamar M. Lins Jr.
Algumas strings p/ bases que eu já acessei usando SQLMIX.
nConn := RDDINFO( RDDI_CONNECT, { "FIREBIRD","localhost", "SYSDBA","masterkey","c:\temp\basefb.gdb" } )
nConn := RDDINFO( RDDI_CONNECT, { "ODBC", "DBQ=c:\dados\lr_2003.xls;ReadOnly=0;Driver={Microsoft Excel Driver (*.xls)}" } )
nConn := RDDINFO( 1001, { "ODBC", "Driver={SQL Server Native Client 10.0};Server=localhost;database=LRXX;Uid=basematriz;Pwd=matriz" })
Não sei se estão corretas pois, já remexi e nem lembro direito.

O resto são comandos SQL e Xbase.

Saudações,
Itamar M. Lins Jr.

Trabalhar com ADO recordset

Enviado: 27 Fev 2015 02:17
por JoséQuintas
Só fiquei com uma dúvida: Se não sabe o que recordset ADO, porque afirmou que faz com SQLMIX?

Trabalhar com ADO recordset

Enviado: 27 Fev 2015 05:06
por rochinha
Amiguinhos,

Quintas
Rochicha, não sei se percebeu, mas mostrou como acessar o MySql pela sua lib, mas não como abrir o recordset ADO.
O comando ADO USE tabela é quem abre um recordset. Os recordsets na biblioteca são um vetor, cada vez que o ADO USE é usado ele acrescenta ou armazena a posição do vetor.

Trabalhar com ADO recordset

Enviado: 27 Fev 2015 08:24
por Itamar M. Lins Jr.
Você escreveu isso!!!
Se existisse um ADOHarbour, bastaria que esse temporário fosse um DBF,
Eu respondi que o SQLMIX faz isso..., só porque faz não significa que faz usando ADO.
...
...Se não sabe o que recordset ADO, porque afirmou que faz com SQLMIX?
Faz a mesma coisa Quintas, a mesma coisa! sem precisar usar ADO.
Se sei ou não sei o que importa ?

http://www.macoratti.net/dao_ado2.htm
Recordset consiste em um conjunto de registros retornados de um consulta a um banco de dados.
http://www.superasp.com.br/paginas_exib ... =0,0&id=98

Saudações,
Itamar M. Lins Jr.