Bom, hora de fechar o tema sobre tabelas temporárias no Delphi! Espero que nos dois primeiros artigos você tenha compreendido, de forma satisfatória, como trabalhar com tabelas temporárias utilizando ClientDataSet. Este último artigo apenas apresenta algumas observações relacionadas a tabelas temporárias que podem ser úteis durante o desenvolvimento.
Tabelas temporárias em runtime
Tabelas temporárias também podem ser criadas em tempo de execução, bem como a definição dos seus campos. Observe o exemplo abaixo, onde instancio um TClientDataSet
e adiciono três campos de diferentes tipos de dados (integer, string e float):
1 2 3 4 5 6 7 8 9 |
var ClientDataSet1: TClientDataSet; // a unit DBClient deve ser declarada na "uses" begin ClientDataSet1 := TClientDataSet.Create(nil); ClientDataSet1.FieldDefs.Add('CODIGO', ftInteger); ClientDataSet1.FieldDefs.Add('DESCRICAO', ftString, 60); ClientDataSet1.FieldDefs.Add('VALOR', ftFloat); ClientDataSet1.CreateDataSet; end; |
E campos agregados também! Caso você não conheça, campos agregados servem para realizar cálculos em uma determinada coluna do ClientDataSet. No exemplo a seguir, criei um campo agregado para somar automaticamente o valor total de todos os itens da tabela.
1 2 3 4 5 6 7 |
with ClientDataSet1.Aggregates.Add do begin AggregateName := 'Valor Total'; Expression := 'SUM(TOTAL)'; Active := True; end; ClientDataSet1.AggregatesActive := True; |
Muitas vezes pode ser necessário “esvaziar” a tabela temporária, como por exemplo, no botão “Limpar” ou “Cancelar” de um formulário. Essa instrução pode ser realizada com apenas uma linha de código:
1 |
ClientDataSet1.EmptyDataSet; |
Barbada, não?
Explorando outros recursos da classe TClientDataSet
Além disso, tabelas temporárias também permitem a navegação entre os registros na memória utilizando os métodos tradicionais já conhecidos:
1 2 3 4 |
ClientDataSet1.First; // move para o primeiro registro ClientDataSet1.Last; // move para o último registro ClientDataSet1.Prior; // move para o registro anterior ClientDataSet1.Next; // move para o próximo registro |
Outro recurso bastante interessante do ClientDataSet é o clone do conjunto de dados. Através do comando CloneCursor
é possível copiar os dados de um ClientDataSet para outro, e então manipulá-los de maneira independente.
1 2 |
// ClientDataSet2 "clona" os dados de ClientDataSet1 ClientDataSet2.CloneCursor(ClientDataSet1, True); |
Agora, imagine que estamos utilizando uma tabela temporária para gravar itens de uma venda. Não é interessante que produtos repetidos sejam inseridos na tabela, concorda? Afinal, se o código do produto fizer parte da chave primária, ocorrerá um erro ao gravar os itens da venda. Para resolver isso, podemos utilizar a função Locate
e controlar a inserção de itens repetidos:
1 2 3 4 |
if ClientDataSet1.Locate('COD_PRODUTO', edtCodProduto.Text, []) then ShowMessage('Este produto já foi adicionado!') else // grava o registro na tabela |
Para filtrar os registros, não há segredo. No exemplo abaixo, tenho um componente do tipo TEdit
chamado edtPesquisa
, e permito o filtro da descrição de um registro na tabela temporária conforme o conteúdo digitado no campo:
1 2 |
ClientDataSet1.Filter := 'DESCRICAO like ' + QuotedStr(edtPesquisa.Text + '%'); ClientDataSet1.Filtered := True; // ativa o filtro |
Só lembrando que o símbolo de porcentagem permite que todos os registros que iniciem com a palavra digitada em edtPesquisa
sejam encontrados. Por exemplo, se o usuário digitar a letra “A”, todas as descrições que começam com essa letra serão filtradas.
Mas atenção: não esqueça de desativar o filtro quando for necessário trabalhar com todos os registros da tabela temporária.
Bom, pessoal, espero que tenham gostado dessa série de artigos sobre tabelas temporárias, e que de alguma forma venha a ser útil pra vocês! Boa sorte no trabalho e até breve!
Confira os outros artigos:
Tabela temporária com ClientDataSet – Conceito
Tabela temporária com ClientDataSet – Prática
Tabela temporária com ClientDataSet – Final
Eu já programo em Delphi há algum tempo e sempre tive o interesse em trabalhar com banco de dados, porém sempre achei um pouco complicado. Este artigo foi muito interessante e didático que percebi que é simples e de certa forma fácil trabalhar com banco de dados no Delphi. Vou estudar este artigo e implementar nos meus aplicativos.
Obrigado.
Júlio.
Olá, Julio. Fico feliz que o artigo tenha lhe ajudado. Obrigado pelo comentário e continue visitando o blog!
Prezado André.
Estou carregando tabelas na estrutura de Client Data Set, porém no meio do processo de importação dos dados é interrompido com uma mensagem de “memory insufficient for this operation”. Meu computador é uma máquina de 64bits e 8GB de memória RAM e as tabelas totalizam 534 MB. Você poderia me orientar em como solucionar este problema?
Obrigado.
Júlio.
Olá, Julio, tudo bem?
Para analisar melhor a situação, vou entrar em contato para solicitar o código, ok?
Abraço!
ola tem como usar um if dentro do locate? exemplo quero varre os registro de encontro o campo diferente de nulo.. mas nao tenho valor certo..
Olá, Marcos. Não entendi muito bem a sua dúvida. Vou entrar em contato com você por e-mail. Obrigado pela visita!
André, tenho utilizado com sucesso tabelas temporárias com ClientDataset.
Uma dúvida: Como acrescento um novo campo após a tabela ter sido utilizada ?
Sempre que necessito um erro é gerado.
Olá, Álvaro! Após a criação do ClientDataSet não é possível adicionar um novo campo, já que essa operação altera a estrutura interna dos Fields. Sendo assim, para criar um novo campo, é necessário remover todos os campos existentes e adicioná-los novamente:
ClientDataSet2.Close;
ClientDataSet2.FieldDefs.Clear;
// adicione todos os campos anteriores e o campo novo
ClientDataSet2.CreateDataSet;
Espero que lhe ajude! Abraço!
Obrigado André. Consegui fazer em tempo de desenho mas é muito mais difícil, o ideal é excluir o ClientDataSet e iniciar o processo mesmo.
Seu exemplo é uma das vantagens de criação de componentes ( ou algumas propriedades ) por código.
Muito obrigado e um abraço.
Boa tarde.
Como faço após clonar todos os registros grava-los fisicamente na tabela de dados?
Desde já, agradeço a atenção.
Olá, Valtencir. Para gravar os registros que estão na tabela temporária, basta iniciar um loop e percorrê-los um a um, gravando-os no banco de dados. Vou enviar um exemplo de código no seu e-mail, ok? Abraço!
Boa noite André.
Agradeço muito sua atenção, vou analisar o e-mail e implementar o que você me enviou.
Grande abraço.
Boa Tarde André. Explicação muito boa sobre tabela temporária. Entretanto tenho uma dúvida. Veja: Criei um campo aggregates para poder somar alguns valores de acordo com as vendas. Esta somando normal, porém a mascara que inseri no campo aggregates não funciona ou seja o valor da moeda do corrente ‘R$’ não é mostrado. Pesquisei na maioria dos fóruns Delphi e não há uma explicação. Vi alguns tutos ensinado por linha de código em evento, mas penso que deve ter algum modo pela propriedades Objecto Inspector.
Obrigado
Abraço.
Olá, Sócrates!
As versões do Delphi anteriores que a versão 2010 contém um bug na formação de campos Aggregates. Mesmo colocando máscaras ou marcando a propriedade “currency” como True, o número não é formatado. Neste caso, uma alternativa é formatar o número no próprio código fonte:
Edit1.Text := FormatFloat('R$ ###,###,##0.00', ClientDataSet1.FieldByName('CAMPO_AGGREGATE').Value);
Segundo alguns sites, também há uma opção de corrigir esse bug do Delphi. Na unit “DB.pas”, no método “TAggregateField.GetText”, basta substituir a linha:
if FResultType in [ftFloat, ftCurrency] then
por:
if FResultType in [ftFloat, ftCurrency, ftFMTBcd] then
Lembrando que, se essa alteração for feita, a unit “BD.pas” deve ser recompilada para que as alterações entrem em vigor.
Abraço!
Bom dia André,
Muito obrigado pela atenção. Optei pela primeira opção e deu certo. Substitui o Edit por um Label e alcancei o resultado esperado. Agradeço a explicação e solução postada.
Abraço!
Legal, Sócrates! Que bom que funcionou! Abraço!
ayuda amigo necesito profesor
ponete en contacto conmigo
Hello, Alfredo!
Unfortunately, I don’t speak Spanish. If you’re able to speak English, maybe I could help you through email.
Let me know if it’s possible, ok?
Regards!
Bom dia André L. Celestino
Eu admiro as pessoas que tem o dom de ensinar sem cobrar, simplesmente pelo prazer de ensinar parabéns!. André, eu acabei de me formar em Tecnologia em Análise e Desenvolvimento de Sistemas acho que até um pouco tarde pela minha idade. Mas tenho um sonho e quero me tornar programador em Delphi linguagem que escolhi para desenvolver mas não tenho muita prática, poderia me dar uma dica, para seguir.
Olá, José Roberto!
Em primeiro lugar, não se preocupe com a sua idade! Nunca é tarde para adquirir novos conhecimentos!
José, eu não sei exatamente qual é o seu nível de habilidade em lógica de programação, mas eu posso lhe encaminhar algumas apostilas de Delphi para iniciantes. Vou entrar em contato para mais detalhes.
Abraço!
me foi muito util, igual a varias outras coisas q vc posta! XD
eu acho q seria legal republicar essas materias do clientdataset mas com firedac, basicamente so precisa mudar uma propriedade como true do query, um usuario no forum quebrou a cabeca com isso, e eu acabei descobrindo, a sugestao é basicamente para q com isso aumente a documentacao do firedac, e uma funcionalidade muito importante para quem nao teve contato com firedac é a questao de trabalhar com dados em memoria, enfim, fica aqui a sugestao!
Olá, Conde!
Tem razão, ainda preciso elaborar alguns artigos abordando o FireDAC. Atualmente há poucos materiais na internet sobre essa tecnologia.
Assim que possível, trabalharei nesse tema.
Abraço!
André, bom dia.
Parabens pelo conteúdo do artigo, de todos q procurei o seu realmente foi mto esclarecedor.
Pergunto: É possível trabalhar com colunas definidas como PK( primary key )?
Como seria a definição?
Obg. e sucesso.
Olá, Marco!
Ótima pergunta!
É possível trabalhar com o comportamento parcial de uma Primary Key, ou seja, podemos definir um campo (Field) como obrigatório alterando a propriedade Required do campo para True. Entretanto, não é possível definir uma coluna como Unique (que não pode se repetir). Neste caso, você terá que controlar esse comportamento manualmente, checando se o valor já existe na tabela antes de gravar.
Abraço!
Gostei, belas dicas, simples e fáceis de entender…
Obrigado pelo feedback, Daniel!
Abraço!
Uma pequena correção no comentário acima. É possível usar coluna com Unique em um TClienteDataSet. Basta ir na propriedade IndexDef do ClienteDataSet criar um novo index, na propriedade Fields do index coloque o campo que você deseja que não se repita e marque as opções ixPrimary e ixUnique. Escolha um nome para o index e atribua esse mesmo nome na propriedade IndexName no ClienteDataSet.
Olá, Felipe, tudo bem?
Muito obrigado pela contribuição! Eu sinceramente desconhecia essa forma de atribuir o comportamento de valor único para uma coluna de um TClientDataSet! Bem interessante!
@Marco, confira essa dica do Felipe.
Abraços!
Bom dia, André !
Primeiramente, parabéns pelo blog e estou sempre aqui dando uma olhada.
“Segundamente”, poderiam tentar me ajudar com o seguinte erro que ocorre quando executo o comando ClientDataSet1.ApplyUpdates(0)
—————————
Project Project1.exe raised exception class TDBXError with message ‘Table ‘gaucho.lista’ doesn’t exist’.
—————————
Acontece que a tabela, no banco, está com letras maiúsculas, gaucho.LISTA seria o certo.
Se executo uma query/comando manual por um TSQLDataSet ou TSQLQuery o banco atualiza normalmente.
Se mudo o nome da tabela para letras minúsculas também funciona.
Utilizo o Quarteto: TSQLConnection + TSQLDataSet + TDataSetProvider + TClientDataSet
Bom dia, Diogo! Bom, isso parece ser um problema de Dialeto do componente de conexão.
Vou entrar em contato com você, ok?
Abraço!
Boa noite, André !
Obrigado pela atenção.
Com relação a dica que me deste não há este item no parms do meu TSQLConnection…
bom dia, André !
Desculpe, esqueci de dizer que estou tentando conexão com MySql…
bom dia, André !
Desculpe, esqueci de dizer que estou tentando conexão com MySql…
Bom dia André.
Excelente, aprendi mais duas usar like e % em um filtro, nunca imaginei, da pra usar containing também?
Valeu mesmo.
Olá, Gerson!
Opa, que bom que aprendeu algo com o artigo!
O Containing não está disponível na propriedade Filter justamente porque o like e o símbolo “%” já dão conta do recado!
Abraço!
Carissimo Andre, adorei tudo que escreveu, mas tenho problema já bem antigo. Sonho diariamente em criar uma tela de qualquer coisa que me permita criar desde o ClientDataset ligado a uma dsp ligado a uma query, tudo em tempo de execução, com campos calculado e campos aggregates. No entanto, até o momento só cheguei a obter resultado até o campos calculado, só me falta o aggregate, o maldito se nega a funcionar.
Fiz assim
Até aqui está tudo funcionando, só tem um detalhe, estou usando CommandText.
Daqui pra frente, só falta dizer que quero adicionar o AggregateField, já usei diversas forma, já perdi meses tentando descobrir a funcionalidade disso, mas até agora nada.
A idéia geral é não usar nenhum componente em tempo de projeto.
Se puder me dar uma pequena dica, agradeço
Marcelo
Andre, mesmo não tendo respondido, agradeço assim mesmo e informo que depois meses tentando fazer a operação acima, acabei descobrindo sozinho.
Se alguem tiver a mesma dúvida, hoje posso instruir
abraço a todos
Olá, boa tarde, Marcelo!
Peço desculpas pela demora para responder o seu comentário, mas, ao mesmo tempo, fico feliz que já tenha encontrado a solução.
Neste mesmo artigo, apresento um exemplo de como criar um campo Aggregate em tempo de execução. Foi dessa forma que você criou?
Se puder colaborar com a sua solução, a comunidade Delphi ficará agradecida! 🙂
Apenas para aproveitar o ensejo, você pode criar a sua própria rotina de criação de Fields para reduzir a repetição de código. Por exemplo:
E então, você chamaria dessa forma:
Abraço!
Prezado André, boa tarde. Mais uma vez, outro excelente artigo. Veja se pode me ajudar, por favor. Num form de pedido, busco os dados do cliente normalmente… aí vem os itens do pedido… achei super prático essa tabela temporária e vem muito a ajudar… Minha dúvida é a seguinte: como eu poderia inserir os itens do pedido em um DBGrid e depois salvar os itens do DBGrid no banco de dados? Tipo, digito o código do produto em um edit e me retorna a descrição e o valor.. aí digito a quantidade e calcula o total daquele item… aí clico em um botão “Inserir Item”. Quando clicar nesse botão, queria que os dados fossem para um DBGrid para poder inserir outros itens… E só quando clicar no botão “Salvar Pedido” que tudo fosse salvo no banco de dados, entendeu?
Olá, Jonismar.
Entendi perfeitamente a sua questão. Tabelas temporárias são úteis para esse tipo de cenário que você mencionou. Você pode inserir vários registros em uma tabela temporária (“Inserir item”) e solicitar que todos eles sejam persistidos de uma vez só no banco de dados (“Salvar Pedido”).
Eu faço essa demonstração na segunda parte do artigo. Clique aqui para acessá-la.
Qualquer dúvida, envie um e-mail para “[email protected]” para que eu possa ajudá-lo melhor.
Abraço!
Olá André! Primeiramente parabéns pelo artigo; bem didático e de simples interpretação.
Estou tendo uma dificuldade com um filtro, o que não tem nada a ver com tabelas temporárias, mas se possível, gostaria de uma dica sua, caso já tenha se deparado com este problema.
Meu ambiente de trabalho:
Delphi 2006 – MySQL 5.7 – DBExpress
SITUAÇÃO:
Tenho um dbGrid que traz o conteúdo de um ClientDataSet com um tabela do banco. Alguns campos string, inteiros e memo.
Muitos programadores têm dificuldade com utilizar o filter, porém após tanto estudar e testar, o utilizo da seguinte forma:
Ex. campo inteiro .: ” > 2″
Ex. campo string ..: ” lower() like lower(‘%’++’%’)”
‘%’ usado antes e depois do texto para que possa encontrar a palavra em qualquer posição da string.
Ex. campo memo ….: ” like ‘%’++’%’ ”
‘%’ mesma finalidade do campo string
FilterOptions = foCaseInsensitive
Quando o contém acentos, ele passa por um procedimento que troca cada letra acentuada pelo caratere ‘_’, fazendo com que ele aceite qualquer caractere naquela posição.
PROBLEMA:
Em alguns campos memo a pesquisa encontra algumas palavras e outras não, sem motivo aparente!
Às vezes ocorre em palavras acentuadas, às vezes em palavras não acentuadas…
Não consegui identificar um motivo para isto ocorrer.
Após a pesquisa enviada para o filter e o filtered ativado, eu exibo o conteúdo do filter na tela e nada demais tem em sua estrutura.
Para ficar claro, coloquei 4 imagens com as pesquisas onde o erro ocorrre.
Imagem 1: pesquisa realizada: “esclarecendo” ( sem acento – traz o campo na pesquisa )
http://www.hexadesenvolvimento.com.br/downloads/screenshots/20170727_delphi_filter/tela01.png
Imagem 2: pesquisa realizada: “sobreaviso” ( sem acento – não traz o campo na pesquisa )
http://www.hexadesenvolvimento.com.br/downloads/screenshots/20170727_delphi_filter/tela02.png
Imagem 3: pesquisa realizada: “misericórdia” ( com acento – traz o campo na pesquisa )
http://www.hexadesenvolvimento.com.br/downloads/screenshots/20170727_delphi_filter/tela03.png
Imagem 4: pesquisa realizada: “médicos” ( com acento – não traz o campo na pesquisa )
http://www.hexadesenvolvimento.com.br/downloads/screenshots/20170727_delphi_filter/tela04.png
Todas as palavras pesquisadas podem ser encontradas no mesmo campo memo, porém algumas palavras não retornam o campo.
Agradeço demais qualquer ajuda que possa dar quanto à este problema.
Olá, Jeferson, tudo bem?
Vou entrar em contato com você para resolvermos esse mistério do Filter, rsrs.
Abraço!
Bom dia André,
Como sempre, parabéns, ótimo post sobre ClientDataSet, sempre ajuda.
Em minhas dúvidas, sempre consulto seu blog e sempre tem algo de bom a se tirar.
Gostaria se possível que tirasse uma dúvida sobre o ClientDataSet. Creio que essa dúvida não é só minha.
Trabalho com Delphi sem utilizar componentes dataware. Até então tudo bem. O problema é trabalhar com campos blob no DataSnap. Sempre que vou atualizar o registro (sem modificar o valor do campo), se existir algum valor, ele apaga o conteúdo. Porém, se alterar o valor contido no momento, ele grava sem problemas. Isso é uma falha do componente ClientDataSet ou é apenas um erro de configuração das propriedades do componente?
O legal seria um post sobre o assunto, iria ajudar muitos desenvolvedores, assim como eu.
Obrigado.
Olá, boa noite, Francisco.
Fiquei um pouco perplexo com o seu problema. O campo BLOB não deveria perder o seu conteúdo.
Vou entrar em contato para solicitar mais detalhes.
Abraço!
Tanto tempo postado e ainda atual e ajudando tanta gente. Sua didática é excelente, obrigado pelo seu tempo de dedicação.
Minha dúvida é simples. Criei um cds temporario conforme suas dicas (declarei a unit) mas ao digitar CdsTemp.FieldDefs.Add(‘Codigo’, ftinteger), o Delphi diz “undeclared identifier ‘ftinteger'”. O mesmo para ftstring. Mas não deu erro ao declarar:
Obs: Delphi 2010. Se eu digitar “integer” ao invés de “ftinteger”, ele nao dá o erro acima mas ao compilar acusa: Unit1.pas ‘(‘expectd but ‘)’ found, ou seja, ele queria que eu abrisse outro parentesis…. para que? Estou preso nisso… kkk help!
Olá, Emerson, tudo certo?
Acho que esse problema é simples de resolver. Experimente adcionar a unit DB na seção uses. Os tipos de dados (ftInteger, ftString, ftFloat, etc…) estão declarados nessa unit.
Obrigado! Abraço!
Boa tarde, André ótimo post , uma duvida quando acontecer uma queda de energia ou maquina desligue existe uma maneira de recuperar esse dados ?
Att
Olá, Júnior! Ótima pergunta!
Caso ocorra uma queda de energia, os dados realmente serão perdidos, já que as tabelas temporárias trabalham com dados em memória.
No entanto, esse risco pode ser contornado se gravarmos os dados em disco temporariamente. Por exemplo, a cada registro inserido em uma tabela temporária, podemos salvar os dados em um arquivo temporário (utilizando o comando
SaveToFile
doTClientDataSet
). Dessa forma, caso seja necessário recuperá-los, basta carregar o arquivo temporário (com o métodoLoadFromFile
). Uma boa funcionalidade, hein? 🙂Abraço!
Bom dia André.
Aproveitando o gancho sobre Cds e TFields temporários, preciso definir uma rotina no evento OnGetTExt, como posso fazer esse uso já que os fields foram adicionados em tempo de execução? Muito Obrigado e Feliz 2020.
Olá, Eugenio. Feliz Ano Novo pra você também! 🙂
Já que os Fields foram criados em tempo de execução, então o evento OnGetText também deverá ser associado em tempo de execução. Por exemplo, primeiro você codifica o evento:
Em seguida, associe o evento ao Field:
Espero que tenha respondido.
Abraço!
Bom dia André,
Problema resolvido. Muito Obrigado pelo retorno.
Abraços e Deus abençoe !!!
Certo, Eugenio!
Eu que agradeço pelo retorno!
Bom dia André,
Preciso de mais um help.
Todos meus ClientDataSets (CDS) do projeto estão no DataModule.
Tenho validações de campos no BeforePost de CDS, e caso haja erro, gostaria de levar o foco para o DBEdit que está no formulário de entrada de dados.
Minha dúvida: Como posso colocar o foco no DBEdit do formulário de entrada de dados para que o usuário possa corrigir estes dados, previamente validados?
Obs: Uso Delphi XE6 com Oracle e FB.
Obrigado mais uma vez.
Eugenio
Olá, Eugenio, boa tarde!
Como o DataModule não “conhece” o formulário, não é possível focar no campo no evento BeforePost. Para que isso fosse possível, o DataModule deveria fazer referência ao formulário, mas, neste caso, causaríamos um problema conhecido como “referência circular”, ou seja, o formulário usa o DataModule, e o DataModule usa o formulário. Não é correto.
Portanto, eu sugiro duas alternativas:
Grande abraço!
Bom dia Andre,
Muito agradecido. Estarei estudando o artigo sobre Controller.
Abraços!
Eu que agradeço pelo comentário, Eugenio!
Olá mestre André,
Tudo bem?
Você tem algum artigo sobre as declarações Virtual/Override/Overload , (Virtual: Abstract), usado em procedimentos e funções?
Obrigado mais uma vez!
Olá, Eugenio!
Não publiquei artigos sobre estes tópicos ainda. No entanto, a documentação da Embarcadero traz uma explicação bastante detalhada sobre cada uma dessas diretivas:
Methods (Delphi)
Vale a pena conferir!
Abraço!
Boa Noite Andre,
Como sempre, atencioso.
Muito Obrigado.
Muito Obrigado André Celestino! Gostei bastante do post… Espero encontrar aquilo que eu procuro para o meu trabalho de licenciatura… Sou de Angola/Cabinda…
Olá, Sapalo!
Eu que agradeço pelo seu comentário! Espero que esse artigo (e outros também) ajude você no seu trabalho!
Um dia gostaria de conhecer a Angola.
Abraços!
Olá meu amigo tudo bem?
Parabéns pelo conteúdo!!!
Estou tentando gravar a venda no banco de dados e esta dando esse erro Query1: Field ‘COD_VENDA’ not found.
Estou usando banco de Dados Mysql.
Obrigado
Olá, Denis, boa tarde.
Há duas possibilidades para esse erro:
1) Verifique o comando SQL da Query. Um bom teste é copiar o comando SQL e executar na ferramenta do banco de dados. Se o comando falhar, há um erro na instrução SQL.
2) Caso contrário, talvez há algum evento ou método que esteja fazendo referência à coluna ‘COD_VENDA’ e, neste momento, essa coluna não existe.
Se o erro persistir, envie um e-mail para [email protected].
Abraço!
Ola!
É possivel usar expressoes sql no filter de um clientdataset? Por exemplo que queria usar o Distinct para filtrar dados unicos de uma coluna.
Obrigado
Olá, Zink.
O filtro do TClientDataSet aceita apenas operações simples. Infelizmente não é possível usar o Distinct.
Se a sua necessidade é excluir registros duplicados em um filtro, você pode utilizar o evento OnFilterRecord.
Há alguns exemplos na internet, como nesse link:
http://www.festra.com/wwwboard/messages/13525.htm
Espero que ajude. Abraço!