Como saber se o cliente já foi cadastrado ?

Criar uma rotina para identificar se o cliente já se encontra cadastrado é relativamente simples!  Usamos para este objetivo a função DCount() que informa a quantidade de registros existentes na tabela, de acordo com o tipo de filtragem aplicada.   Queremos aqui, que a função DCount() informe apenas a quantidade de registros do cliente, supostamente cadastrado. 

A função DCount() tem a seguinte estrutura:

DCount("NomeDoCampo","NomeDatabela", Filtro)

Vamos supor que eu tenha uma tabela de nome tblClientes e que irei solicitar a contagem de registros, utilizando o campo número exclusivo do cliente (idCliente).

TotalDeRegistros = DCount("idCliente","tblClientes")

Como não utilizei o filtro, a função irá contar todos os registros existentes na tabela.

Agora, vamos supor que eu queira contar apenas os registros do cliente cadastrado "Avelino Sampaio"

TotalDeRegistros = DCount("idCliente","tblClientes","cli_nome ='Avelino Sampaio'")

Se existir o nome Avelino Sampaio no campo cli_nome da tabela, a função irá retornar a contagem de 1 registro e se o nome pesquisado não existir no cadastro, a função irá retornar com o valor 0(zero).

Fica fácil, então, usarmos esta função para saber se o cliente foi ou não, previamente cadastrado!

Usamos o evento Antes de Atualizar, do campo que recebe o nome do cliente.  Observe que o evento tem o argumento Cancel, que usamos para manter o foco no campo.

Exemplo do usos da função DCount() no evento:

Private Sub cli_Nome_BeforeUpdate(Cancel As Integer)
If DCount("idCliente","tblClientes","cli_Nome =""" & Me!cli_Nome & """") > 0 Then
   'A função DCount() contou um ou mais registros existentes
   MsgBox "O Cliente " & Me!cli_Nome & " já existe..."
   Me.Undo 'Limpa o campo
   Cancel = True 'mantém o foco no campo.
End If
End Sub

Só que esta função nos traz uma pegadinha bem sutil, da qual já fui vítima!  Meu cliente, um dia me ligou, bem irritado, comunicando que havia encontrado no cadastro, o sobrenome de uma empresa, iniciando com letra minúscula e quando foi corrigir a letra para maiúscula, o programa não permitiu, acusando que o cliente já se encontrava cadastrado.  Huumm!!! De fato, neste caso, não houve mudança alguma no nome para a função acima, que detectou a presença do cliente, no cadastro!  A saída, para este caso em particular, foi a de armazenar o nome do cliente atual, na memória, usando uma variável, e então comparar se o nome alterado difere do nome original, armazenado na variável. 

O primeiro passo é armazenar o nome do cliente, no instante em que é acessado o registro.  Isso é feito pelo evento No atual do formulário:

Option Compare Database
'Variável criada para armazenar o nome do cliente original
Dim NomeOriginal As String
 
Private Sub Form_Current()
   'Capturando o nome do cliente ao entrar no registro.
   NomeOriginal = Nz(Me!cli_Nome, "")
End Sub

Agora, acrescentamos no evento Antes de Atualizar, do campo cliente, o código que analisa se de fato o nome sofreu alteração.  Caso não tenha sofrido alteração, não permitimos que a função DCount() seja executada.

Observe abaixo, o acréscimo do código no evento:

Private Sub cli_Nome_BeforeUpdate(Cancel As Integer)

'---------------------------------------------------------------------
'Se não houver alteração do nome, sair do procedimento, impedindo assim
'que a função DCount() seja disparada.
If NomeOriginal = Me!cli_Nome Then Exit Sub
'---------------------------------------------------------------------
 
If DCount("idCliente","tblClientes","cli_Nome =""" & Me!cli_Nome & """") > 0 Then
   'A função DCount() contou um ou mais registros existentes
   MsgBox "O Cliente " & Me!cli_Nome & " já existe..."
   Me.Undo
   Cancel = True
End If
End Sub

Uma outra questão, resolvida na prática: certa ocasião fui chamado por um dos meus clientes para investigar o que estava acontecendo de errado em relação ao Cadastro de Clientes. Alegou que alguns dos clientes cadastrados possuíam mais de um registro.  Após algumas observações, percebi que as funcionárias da empresa ao cadastrarem novos clientes, cometiam erros de digitação, o que contribuía para os vários registros referentes ao mesmo cliente. Isto era recorrente na empresa, envolvendo mais de um cliente cadastrado, porque as sutis alterações do nome do cliente ao ser digitado, passavam despercebidas.  Exemplo:

Celula Serviços Tecnologicos
Celula Servicos Tecnológicos
Celula Serviços Tecnológicos Ltda

Ora, considerei que isso não era um problema pertinente à programação, mas sim à falta de atenção das funcionárias, durante a digitação!  Para resolver o problema, fiz uma reunião para orientar que antes de iniciar o cadastro era necessário investigar, através de uma combobox, se o cliente já havia sido registrado!

Em pouco tempo, o problema voltou a se repetir.  Quem disse que as funcionárias, antes de prosseguir com o cadastro, investigavam se determinado cliente já havia sido registrado?!   O meu cliente ficou muito irritado com a situação e sobrou bronca para todos, inclusive para mim, é claro! 

Após o ocorrido, fiquei pensando de que forma poderia resolver a questão!  Surgiu, então, uma idéia fantástica para o caso: criei uma tela para que na medida em que o novo cliente for registrado, a lista de cadastros existentes seja filtrada e exibida numa listbox.

Observe, na imagem abaixo, a tela usada para registrar o novo cliente:

Usando Access - Cadastro de clientes

 

Veja que ao começar a digitar o novo cliente (Ce), a lista dos clientes já cadastrados, na listbox, começa a se reduzir. 

Usando Access - Cadastro de clientes com lista de cadastrados

 

Peguei elas! (risos). 

O fato é que tive sim, minha parcela de culpa no caso, por não ter avaliado corretamente o comportamento humano!  Recomendo muito que você leia este artigo sobre usabilidade.

Se quiser aprender como se filtra uma listbox, a medida que se digita em campo texto, leia o artigo e assista a vídeo-aula sobre filtragens, clicando aqui.

O emprego, das técnicas aqui apresentadas, está à sua disposição no aplicativo Maestro, que forneço aqui no site.  Clicando no botão novo, do formulário de Cadastro de Clientes, você terá acesso à tela apresentada acima, para realizar testes. 

Usando Access - Cadastro de clientes do Maestro

 

Arquivo exemplo

Para entrar na estrutura do Maestro (Maestro_v3.accdb), basta manter pressionada a tecla SHIFT , na inicialização.

Senha do usuário admin  > admin
Senha do usuário Avelino > 1234
Senha do Maestro_v3_be.accdb (tabelas) > a1234

 


 

 


27 comentário(s)

Gilberto Mendes   08/02/2012 08:40:10

Já tive esse problema. Eu resolvi verificando se é registro novor ( If Me.NewRecord then... ). Se a quantidade é 1 eu dou um aviso que já existe. Se não é registro novo, eu vejo se o DCount retorna 2.

Boa dica! Parabéns pelo trabalho

Gilberto Mendes
www.accesspro.com.br

Eduardo Sousa   08/02/2012 10:05:55

Muito útil.
Obrigado por mais esta ajuda.

Edson Junho   08/02/2012 13:01:36

Avelino, poderia colocar um exemplo banco do nº 01, como verificar se o cliente já está cadastrado. Tentei fazer e não consegui.

edjunhoscj@gmail.com

Welson Zeferino de Oliveira Junior   08/02/2012 16:42:05

Avelino, meus parabéns. Mais uma vez, mostra de forma simples coisas que para aprendizes demoram muito para encontrar a solução.

Avelino Sampaio   08/02/2012 17:19:09

Edson,

já lhe enviei o arquivo exemplo modificado.

Bom estudo!

Avelino Sampaio   08/02/2012 17:20:37

Gilberto, Eduardo e Welson

muito obrigado pela participação de vcs.

Sucesso!

MARCIO MELO - RJ   08/02/2012 18:19:58

Gostei muito desse artigo, e cada vez mais tenho o seu site como meu manual online. Aos poucos você vem abordando assuntos conhecidos mas de maneira diferente e com uma ótima didática. No meu caso as vezes descubro um procedimento e não tenho a certeza do funcionamento e aqui você nos mostra o passo a passo. Continue assim, é muito bom ler, entender e acompanhar o seu raciocinio lógico... Parabéns... Ahhh adorei a sua vídeo aula de setup e os arquivos pré definidos, uma mão na roda...

Sou mais Brasil!

Marcelo David   08/02/2012 20:01:11

Nossa Avelino, realmente cada vez mais você nos surpreende e mostra o quanto é profissional a programação Access/VBA....

Simplesmente fantástico!!

Ricardo   15/02/2012 14:38:08

Olá Avelino, eu tenho uma situação idêntica mas o meu código está um pouco diferente, no evento antes de actualizar de uma caixa de texto do formulário eu tenho o seguinte,

Eu consigo ver se existe o registo que o utilizador está a introduzir, se existir aparece uma mensagem onde o utilizador pode escolher editar esse mesmo registo ou inserir um novo (diferente claro). Eu não estou a conseguir é preencher o formulário com os dados correspondentes se o utilizador escolher editar.

Private Sub instalação_BeforeUpdate(Cancel As Integer)
'Verifica antes de ir a frente se ja foi digitado um código de instalação
'Dim rst As Recordset, instal As String
Dim response As VbMsgBoxResult
Dim StrSQL As String

'Abre o recordset do tipo Table.
Set rst = CurrentDb.OpenRecordset("Clientes", dbOpenTable)
instal = Me.instalação
With rst
'Informa o nome do índice na tabela.
.Index = "PrimaryKey"
'Pesquisa o campo na tabela.
.Seek "=", instal
'Se encontrar, então...
If Not .NoMatch Then
response = MsgBox("A instalação '" & (instal) & "' já existe!" + Chr$(13) & "Deseja editar o registo existente ou inserir um novo? " + Chr$(13) & "Para editar clique Sim" + Chr$(13) & "Para inserir novo clique Não", vbYesNo, "Instalação Existente")
If response = vbYes Then
StrSQL = "SELECT * FROM [clientes] WHERE [instalação] = " & instalação & ""
DoCmd.RunSQL StrSQL
Else
instalação.Undo 'limpa a caixa de texto
Cancel = True 'Cancela o evento.
End If
End If
End With
Set rst = Nothing 'Libera memória.
End Sub

Ricardo   15/02/2012 20:25:45

Fiz algumas alterações e já consigo carregar o formulário com os dados se o utilizador clicar em Sim (Editar) no entanto estou com outro problema. Neste formulário eu tenho um subformulário que recebe os dados de uma tabela que está relacionada com a tabela de onde provêm os dados que são carregados no formulário principal e quando introduzo um registo existente e o utilizador clica em sim este subformulário é carregado com os dados (não fiz qualquer código para isso) no entanto não consigo editar nem adicionar novos dados a esse subformulário aparece a seguinte mensagem "As alterações pedidas para a tabela não foram bem sucedidas pois iriam criar valores duplicados no índice ou no relacionamento, altere o índice ou remova o índice para que as entradas possam ser duplicadas" Eu entendo que tem algo a ver com a chave primária que relaciona as duas tabelas e pla qual eu faço a pesquisa, no entanto eu queria que ele entendesse que eu não quero duplicar o registo mas sim editar / adicionar informação. :)

O meu código do evento antes de actualizar da caixa de texto está assim,

Os meus conhecimentos são básicos, eu pesquiso vou lendo, tentando e adaptando o meu código, não sei se está feito da forma mais correcta.

Private Sub instalação_BeforeUpdate(Cancel As Integer)

Dim rst As Recordset
Dim banco As Database
Dim instal, StrSQL As String
Dim response As VbMsgBoxResult

'Set rst = CurrentDb.OpenRecordset("Clientes", dbOpenTable)
Set banco = CurrentDb
Set rst = banco.OpenRecordset("Clientes")

instal = Me.instalação

With rst
'Informa o nome do índice na tabela.
.Index = "PrimaryKey"
'Pesquisa o campo na tabela.
.Seek "=", instal
'Se encontrar, então...

If Not .NoMatch Then

response = MsgBox("A instalação '" & (instal) & "' já existe!" + Chr$(13) & "Deseja editar o registo existente ou inserir um novo? " + Chr$(13) & "Para editar clique Sim" + Chr$(13) & "Para inserir novo clique Não", vbYesNo, "Instalação Existente")

If response = vbYes Then
StrSQL = "SELECT cNOme, cMorada, cContacto, Concelho" & _
" FROM clientes" & _
" WHERE instalação = '" & instalação.Text & "';"
Set banco = CurrentDb
Set rst = banco.OpenRecordset(StrSQL)
Me.AllowEdits = True
Me.CortesBTN2.Form.AllowEdits = True
Me.CortesBTN2.Form.AllowAdditions = True
rst.Edit
Me.cNome = rst.Fields("cNome").Value
Me.cMorada = rst.Fields("cMorada").Value
Me.cContacto = rst.Fields("cContacto").Value
Me.CConcelho = rst.Fields("Concelho").Value
rst.Update
Else
instalação.Undo 'limpa a caixa de texto
Cancel = True 'Cancela o evento.
End If
End If
End With
Set rst = Nothing 'Libera memória.
End Sub

Denilson   04/03/2012 21:30:41

Para não acontecer esse tipo de cadastro duplicado basta incluir um campo CNPJ e deixar ele como chave primária, aposto que os operadores não conseguirão duplicar registros nunca mais...muito simples...abraços.

Avelino Sampaio   05/03/2012 06:39:09

Denilson,

Sem dúvida é uma ótima opção usar o CNPJ ou o CPF mas existem muitos casos na prática em que esses dados só são obtidos em um segundo momento. Pre cadastros são muito comuns na prática.

Obrigado pela sua contribuição pois assim temos mais uma opção para o programador decidir o que cabe melhor ao projeto dele.

Osmar   29/10/2012 15:21:08

Eu tenho uma dúvida e gostaria de como solucionar, caso alguém possa ajudar-me, pois meus conhecimentos em access são precários:
Eu tenho uma tabela com o campos cd_Posto, Ano_Posto, num_caixa, status e gostaria de saber como posso fazer um VBA onde ao atualizar o registro ele verifique se já existe um registro onde cd_Posto = Ano_Posto = num_caixa e não permita o cadastramento.

Alessandro   25/11/2012 23:33:37

Pessoal eu estava precisando de um codigo que procurasse se o registro existe e retornar a mensagem. Ótima dica, esse codigo funcionou certinho. Acontece que eu gostaria, que ao aparecer a mensagem avisando que o codigo já existe, abrisse o registro para que pudesse ser editado.

Avelino Sampaio   26/11/2012 05:54:34

Alessandro,

Observe que no formulário de cadastrar o novo cliente, basta dar dois cliques sobre o cliente existente na listbox que o cadastro será aberto.

Se estiver usando o evento "antes de atualizar" do campo para isso, acrescente a proprieadade FILTER. Exemplo:

Private Sub cli_nome_BeforeUpdate(Cancel As Integer)
Dim filtro As String
If NomeOriginal = Me!cli_Nome Then Exit Sub
filtro = "cli_Nome =""" & Me!cli_Nome & """"
If DCount("idCliente", "tblClientes", filtro) > 0 Then
MsgBox "O Cliente " & Me!cli_Nome & " já existe..."
Me.Undo
Cancel = True
Me.Filter = filtro
Me.FilterOn = True
End If
End Sub

Sucesso!


Alisson   20/05/2013 00:26:45

Caro Avelino,

Podemos usar a função Dcount para mais de um criterio? Gostaria que o fosse comparado tres campos da tabela e tentei esse codigo, mas aparece o erro 13 Tipos incompativeis.
Os campos sao selecionados em combos e o CodFundo é numero.

'verifica se o cadastro esta duplicado
If DCount("codControle", "tblControleContratos", "CodFundo=" & Me.cboFundo & "" _
And "CodCorretora = '" & Me.cboCorretora & "'" And "CodGestor='" & Me.cboGestor & "'") > 0 Then
'A função DCount() contou um ou mais registros existentes
MsgBox "Este Fundo já esta cadastrado nesta Corretora", vbExclamation, NomeApp
End If

O que esta errado?

Avelino Sampaio   20/05/2013 05:30:16

Alison,

tente assim:

If DCount("codControle", "tblControleContratos", "CodFundo=" & Me.cboFundo & " And CodCorretora = '" & Me.cboCorretora & "' And CodGestor='" & Me.cboGestor & "'") > 0 Then

Sucesso!

Alisson   20/05/2013 07:55:46

Avelino

Agora funcionou, muito obrigado!

luis otavio da silva   16/07/2013 13:20:57

gostaria de saber se a recado

Pedro Trindade   19/09/2013 00:47:29

Olá, Avelino

Como eu completo o código para que eu escolha entre desistir da duplicação ou continuar com a edição do registro duplicado?
Eu quero que a caixa de msg me pergunte se desejo ou não continuar.
No meu caso, a mensagem será só um alerta para eu não cadastrar um aluno duas vezes no mesmo curso.

Obrigado

JGaspar   26/09/2013 18:01:08

Usei parte do seu código e me ajudou.
Valeu e obrigado!!!

JGaspar   26/09/2013 18:02:20

Amigo, faça igual ao um blog para podermos assinar o post e tudo mais!
Abraços

Anibal   16/01/2014 18:05:26

estou com uma dificuldade semelhante, esta dando erro 3464, segue o código:

If DCount("SERIAL", "ALMOX", "SERIAL=" & Me.Texto0 & " And STATUS_EQUIP = 'INICIALIZADO'") > 0 Then
MsgBox "O Serial " & Me!Texto0 & " já esta cadastrado no Sistema!", vbExclamation, "INFORMAÇÃO"
Me.Undo
Cancel = True
Texto12.SetFocus
End If

Avelino Sampaio   17/01/2014 08:09:53

Anibal,

SERIAL é do tipo String ou Numérico ? Se for do tipo String estaria faltando os apóstrofes. Exemplo:

If DCount("SERIAL", "ALMOX", "SERIAL='" & Me.Texto0 & "' And STATUS_EQUIP = 'INICIALIZADO'") > 0 Then
...

Se for do tipo númerico, experimente:

If DCount("SERIAL", "ALMOX", "SERIAL=" & val(Me.Texto0) & " And STATUS_EQUIP = 'INICIALIZADO'") > 0 Then
...

No aguardo

Anibal   17/01/2014 10:02:29

funcionou perfeitamente, Obrigado Avelino.

Gilvane   24/06/2014 17:34:12

Muito bom! Era justamente o que eu estava precisando.

Formiga10x   13/07/2014 15:57:04

Grande mestre Avelino suas aulas são incríveis. Através das experiências por vc já vivida nos faz aprimorar mais e mais a nossa.
Muito obrigado.
Abraço.


Envie seu comentário: