Jump to content

Problema com a chave primária


daniel_silva

Recommended Posts

Boa noite programadores.

Estou a fazer um trabalho para Linguagem de Programação é um sistema de stock de stand. Onde regista os clientes, fornecedores, entradas e saídas das viaturas.

Como é óbvio só existe uma matrícula por cada carro, e queria usar uma chave primária para o campo matrícula.

Por exemplo, quando introduzir uma matrícula e essa matrícula já estiver registada no ficheiro aparece uma mensagem a dizer que essa matrícula já foi registada.

O que eu quero mesmo saber, é como vou fazer para o programa saber que a matrícula já existe.

Fico a guardar pela resposta!

Obrigado, e bom ano novo 🙂👍

Link to comment
Share on other sites

Deduzo que estejas a usar ficheiros tipados, é isso?

A "chave primária" podes simular de duas formas:

1. Antes de gravar um registo percorres o ficheiro para ver se o campo matricula (chave) já existe.

2. Crias um ficheiro em paralelo que guarda um índice de registos, nomeadamente a matrícula e a posição dela no ficheiro principal. Este ficheiro tem de ser permanentemente actualizado de cada vez que há alterações ao ficheiro principal, e na hora de gravar, procuras nele se a matricula existe.

Claro que o 2º modo é muito mais complexo e propenso a falhas para quem está a iniciar (até para quem já está nisto há muito).

Logo, imagino que vás optar pela primeira opção.

"A humanidade está a perder os seus génios... Aristóteles morreu, Newton já lá está, Einstein finou-se, e eu hoje não me estou a sentir bem!"

> Não esclareço dúvidas por PM: Indica a tua dúvida no quadro correcto do forum.

Link to comment
Share on other sites

Olá Daniel, claro que concordo totalmente com o nunopicado.

Procura se tem alguma igual, e se encontrar faz uma opção para colocar outra vez a matrícula.E não de esqueças que temos que fazer a 2 opção que o nunopicado propôs.

Edited by FMC

"The greatest mistake you can make in this life is to be continually fearing you will make one."

Elbert Hubbard -

 

Link to comment
Share on other sites

Só por curiosidade, não entendo o objetivo da opção 2? Qual a vantagem?

Se se tem um ficheiro com as matriculas para quê criar um 2º que não vendo vantagens só traz complexidade?

Mais, não interessa se é um campo chave ou não, simplesmente pesquisas no ficheiro para saber se existe ou não e depois ages em conformidade.

Link to comment
Share on other sites

Só por curiosidade, não entendo o objetivo da opção 2? Qual a vantagem?

Se se tem um ficheiro com as matriculas para quê criar um 2º que não vendo vantagens só traz complexidade?

Num ficheiro pequeno, nenhuma vantagem.

Num ficheiro com milhares de registos e dezenas de campos, pesquisar um que só tem dois campos é muito mais rápido do que pesquisar no principal, e depois acede-se directamente ao registo se for preciso.

É um índice.

Imagina pesquisar uma enciclopédia sem um...

  • Vote 1

"A humanidade está a perder os seus génios... Aristóteles morreu, Newton já lá está, Einstein finou-se, e eu hoje não me estou a sentir bem!"

> Não esclareço dúvidas por PM: Indica a tua dúvida no quadro correcto do forum.

Link to comment
Share on other sites

  • 2 weeks later...

Boa noite!

Já fiz uma questão no fórum a perguntar como é que podia fazer, para fazer uma chave primária em pascal zim. O nunopicado sugeriu-me que antes de gravar um registo percorro o ficheiro para ver se o campo que eu quero como chave primária já existia.

Então eu fiz isso... Mas continua a não resultar!

Há coisas que parecem tão fáceis e no entanto só complicam. 😞

Aqui está o código:


Program ChavePrimaria_NifCliente ;
uses crt;

type dados_cliente = Record
    nomeC:string;
    num_biC:string;
    data_nasC:string;
    ruaC:string;
    loteC:string;
    cod_postalC:string;
    localidadeC:string;
    telemovelC:string;
    enderecoC:string;
    end;

total_dados = Record
    cliente:dados_cliente;
    end;

ficheiro_cliente = file of total_dados;

var d:total_dados;

    f_cliente:ficheiro_cliente;

    opcao,fecho_principal:char;
Function exist_fich_cliente:boolean;
begin
assign(f_cliente,'C:\stand\cliente.dat');
{$I-}
reset(f_cliente);
close(f_cliente);
{$I+}
exist_fich_cliente:=(ioresult=0);
end;

Procedure menu_princial(var op:char);                                                        
begin
clrscr;
writeln (' --------------------------');
writeln ('|     MENU PRINCIPAL     |');
writeln (' --------------------------');
writeln;
writeln (' 1: Registrar um cliente');
writeln;
writeln (' A: Pesquisar clientes registrados');
writeln;
writeln (' 0 > Sair');
writeln;
readln (op);
end;

Procedure ler_cliente(var lc:total_dados);
var num_biC:string; fc:ficheiro_cliente; sinal:boolean;
begin
assign(fc,'C:\stand\cliente.dat');
reset(fc);
seek(fc,0);
sinal:=false;
clrscr;
writeln (' ----------------------------');
writeln ('| REGISTRAR UM CLIENTE |');
writeln (' ----------------------------');
writeln;
write ('> Numero de contribuinte: ');                                                        
readln (num_biC);
while not(eof(fc)) do
begin
read(fc,lc);
if ( lc.cliente.num_biC = num_biC ) then
sinal:=true;
end;

if sinal=true then                                                                            
writeln ('[ERRO] Já existe um NIF igual.');

if sinal=false then
begin
with lc do
    begin
    write ('> Nome..................: ');
    readln (cliente.nomeC);
    write ('> Data de nascimento....: ');
    readln (cliente.data_nasC);
    write ('> Rua...................: ');
    readln (cliente.ruaC);
    write ('> Lote..................: ');
    readln (cliente.loteC);
    write ('> Codigo postal.........: ');
    readln (cliente.cod_postalC);
    write ('> Localidade............: ');
    readln (cliente.localidadeC);
    write ('> Telemovel.............: ');
    readln (cliente.telemovelC);
    write ('> E-mail................: ');
    readln (cliente.enderecoC);
    end;
end;
close(fc);
end;

Procedure escrever_cliente(ec:total_dados);
begin
with ec do
begin
writeln ('> Nome..................: ',cliente.nomeC);
writeln ('> Numero de contribuinte: ',cliente.num_biC);
writeln ('> Data de nascimento....: ',cliente.data_nasc);
writeln ('> Rua...................: ',cliente.ruaC);
writeln ('> Lote..................: ',cliente.loteC);
writeln ('> Código postal.........: ',cliente.cod_postalC);
writeln ('> Localidade............: ',cliente.localidadeC);
writeln ('> Telemovel.............: ',cliente.telemovelC);
writeln ('> E-mail................: ',cliente.enderecoC);
end;
end;

Procedure esc_reg_fich_cliente(var fc:ficheiro_cliente);
var efc:total_dados; fecho:char;
begin
assign(fc,'C:\stand\cliente.dat');
reset(fc);
seek(fc,filesize(fc));
Repeat
ler_cliente(efc);
write(fc,efc);
writeln;
    Repeat
    writeln ('Deseja continuar a registrar clientes? S/N ');
    readln (fecho);
    if not (fecho='n') and (fecho='s') or (fecho='N') and (fecho='S') then
    Until (fecho='n') or (fecho='s') or (fecho='N') or (fecho='S');
Until (fecho='N') or (fecho='n');                                            
close(fc);
end;

Procedure pesquisar_clientes(var fc:ficheiro_cliente);
var pc:total_dados; sinal:boolean; pesqcliente:string; num_biC:string;
begin
clrscr;
assign(fc,'C:\stand\cliente.dat');
reset(fc);
seek(fc,0);
sinal:=false;
writeln (' ------------------------------ ');
writeln ('|     Pesquisar clientes     |');
writeln (' ------------------------------ ');
writeln;
write ('> Introduza o nome do cliente: ');
readln (pesqcliente);
while not(eof(fc)) do
begin
    read(fc,pc);
    if (pc.cliente.nomeC = pesqcliente) then
    begin
    writeln;
    escrever_cliente(pc);
    sinal:=true;
    end;
end;
if (sinal=false) then
    begin
    writeln;
    writeln ('[ERRO] Nao existe nenhum cliente com esse nome na base de dados.');
    end;
close(fc);
end;

Begin
if (exist_fich_cliente) then
reset(f_cliente)
else
rewrite(f_cliente);
close(f_cliente);

Repeat
menu_princial(opcao);
case opcao of
'1':esc_reg_fich_cliente(f_cliente);
'a','A':pesquisar_clientes(f_cliente);
end;
writeln;
Repeat
writeln ('- Deseja sair do programa? S/N ');
readln (fecho_principal);
if not (fecho_principal='n') and (fecho_principal='s') or (fecho_principal='N') and (fecho_principal='S') then
Until (fecho_principal='n') or (fecho_principal='s') or (fecho_principal='N') or (fecho_principal='S');
Until (fecho_principal='S') or (fecho_principal='s');

End.

Fico aguardar a resposta, muito obrigado 🙂

Edited by thoga31
GeSHi
Link to comment
Share on other sites

Nao precisas abrir novo tópico, é só continuar o teu anterior. 😉

A primeira coisa que te posso dizer é que se fosse teu professor, não aceitava o trabalho enquanto não estivesse indentado.

Diz-me uma coisa, quando tentas ler o teu código, tu percebes alguma coisa do que lá está escrito? Ou não o lês?

Se o tivesses indentado terias visto que tens dois problemas, detectáveis até sem ler o código, desde que este esteja bem indentado.

Por duas vezes tens if...then...until.

Não dá erro, mas basicamente aquele if é como se não existisse. A seguir ao then não há qualquer comando, apenas o fecho do ciclo.

Dito isto, vamos aos outros problemas:

1. Caminho absoluto

Nunca, repito, NUNCA, uses um caminho absoluto para referenciar um ficheiro.

É terminantemente proibído. E se pensares um pouco, verás porquê.

Imagina lá que no meu computador não existe um C:. É estranho? Talvez, mas acontece.

Ou imagina que no meu computador, o sistema de permissões não permite criar pastas na raíz. É estranho, nem por isso, até é muito comum em PCs empresariais.

Ou ainda, imagina que tenho pouco espaço no C: e quero meter os programas do D:.

Ou imagina que até já tenho uma pasta no C: chamada stand, de um outro programa, e não quero os ficheiros do teu programa lá misturados...

Estás a perceber? O caminho dos ficheiros que referencias tem de ser sempre relativo, ou seja, não pode existir indicação do drive (C:) e de preferência, nem da pasta (Stand).

Das duas uma, ou metes na pasta onde está o executável, seja lá isso onde for (podes saber qual é com a função ParamStr(0)), ou tens de perguntar ao utilizador onde quer guardar os ficheiros.

2. Repetição de valores

Agora vou eu imaginar que tu leste o ponto anterior e até achaste que sim, que eu tenho razão.

Vais alterar o caminho do ficheiro.

Quantas vezes tens de alterar? Se for mais do que uma, já está errado. Tu tens 4.

Deves gravar os valores em constantes, e usar essa constante no código.

Assim, se quiseres alterar o valor, só alteras a constante, e todo o restante código fica bem.

3. 1 ficheiro = 1 Assign

Para um mesmo ficheiro, usas o Assign apenas uma vez. Simples assim. No ponto anterior disse que usas o caminho 4 vezes. Isso acontece porque estás a usar o Assign 4 vezes.

Ficheiros é, 1 variável global, Assign ao inicio do programa, e a partir daí, nunca mais.

Se acaso não quiseres usar uma variável global (embora este seja um dos casos onde é legítimo que seja global), ao passar por referência ela já vai com o assign. Não voltas a fazer.

4. Misturas

Uma procedimento só faz uma coisa. Ou só deve fazer uma coisa. Mas no teu programa, vários procedimentos fazem, ou tentam fazer, várias.

Nomeadamente a pesquisa da chave primária, que tens junto com a leitura de dados, devia estar dentro de uma função, retornar um boolean que indicasse se já existia ou não.

5. Operações lógicas

Uma condição, num IF, por exemplo, devolve um valor lógio (true/false). Um boolean também.

Assim, não precisas fazer "if sinal = true". Se o sinal for true, isto é substituido por "if true = true", que o compilador depois converte em "if true".

Ou seja, bastava-te fazer "if sinal then" e era a mesma coisa.

E logo a seguir fazes "if sinal = false", que também podia ser subsituido por "if not sinal then".

Mas tendo em conta que fazes estas duas operações juntas, porque não substituir o segundo if por um else? Afinal, se não for true, é false. 😉

6. Gravação de dados

O Pascal não grava verdadeiramente os dados no ficheiro quando fazes write. O write prepara os dados a escrever, mas só quando fazes close é que o ficheiro é realmente guardado.

Se puseres o reset antes do ciclo, e o close no fim do ciclo, geralmente não há problema.

Mas se dentro do ciclo vais pesquisar se um valor existe no ficheiro, ele vai dar sempre que não para todos os valores ainda não gravados, apesar de já os teres inserido.

Para resolver isto, é simples. O reset antes do write, o close depois do write. De cada vez que inseres um cliente, ele guarda os dados, e fica tudo bem.

7. Por fim, o principal motivo de não te funcionar a chave primária.

Tu lês o num_biC, depois pesquisas o num_biC, e se não existir, gravas o... pois, gravas tudo menos o num_biC. Se reparares, em lado nenhum atribuis o num_biC lido à tua variável LC.

Ou seja, ele realmente grava o registo no ficheiro, todos os campos, menos o num_biC. Assim, quando a seguir inseres outro e vais verificar se já existe, ele não existe, pois no ficheiro não há nenhum.

Basta isto:

if sinal
  then writeln ('[ERRO] Já existe um NIF igual.')
  else begin
            with lc do
                 begin
                      cliente.num_biC := num_biC;  // Esta é a linha que te falta

                      write ('> Nome..................: ');
                      readln (cliente.nomeC);
                      write ('> Data de nascimento....: ');
                      readln (cliente.data_nasC);
                      write ('> Rua...................: ');
                      readln (cliente.ruaC);
                      write ('> Lote..................: ');
                      readln (cliente.loteC);
                      write ('> Codigo postal.........: ');
                      readln (cliente.cod_postalC);
                      write ('> Localidade............: ');
                      readln (cliente.localidadeC);
                      write ('> Telemovel.............: ');
                      readln (cliente.telemovelC);
                      write ('> E-mail................: ');
                      readln (cliente.enderecoC);
                 end;
       end;      

Não te esqueças de ver o resto, se quiseres melhorar.

"A humanidade está a perder os seus génios... Aristóteles morreu, Newton já lá está, Einstein finou-se, e eu hoje não me estou a sentir bem!"

> Não esclareço dúvidas por PM: Indica a tua dúvida no quadro correcto do forum.

Link to comment
Share on other sites

Boa noite nunopicado 👍

Gostei muito dos seus pontos de vista...

No seu ponto de vista do if...then..until e não ter nenhuma condição por baixo o facto de ter assim é que imagine que o utilizador mete uma tecla sem ser o "S/N" para sair do programa ou para continuar a registar clientes, assim aparece novamente a mensagem para sair até que o utilizar introduza a tecla "S" ou "N", pode parecer que não tem muito sentido, mas na minha opinião faz 😛

Se calhar deveria meter uma mensagem de erro para dar uso ao if...then. Tem razão!

Gostei também da sua ideia de perguntar ao utilizador onde quer guardar a pasta com os ficheiros, sinceramente nunca me tinha lembrado disso é uma boa ideia 😄

Por fim, agradeço muito por me ter ajudado na dúvida da chave primária! É menos um problema que tenho de me preocupar 🙂

Aproveito já para dar a minha opinião sobre este fórum... É dos melhores fóruns que conheço! 😄

Muito obrigado pela sua ajuda nunopicado 👍

Abraço.

Link to comment
Share on other sites

@daniel_silva, achas que estes dois trechos de código fazem sentido?

  if not (fecho='n') and (fecho='s') or (fecho='N') and (fecho='S') then
  Until (fecho='n') or (fecho='s') or (fecho='N') or (fecho='S');   // <-- o que é isto?
Until (fecho='N') or (fecho='n');

// ...

  if not (fecho_principal='n') and (fecho_principal='s') or (fecho_principal='N') and (fecho_principal='S') then
  Until (fecho_principal='n') or (fecho_principal='s') or (fecho_principal='N') or (fecho_principal='S');
     // ^^ o que é isto?
Until (fecho_principal='S') or (fecho_principal='s');

until faz parte da estrutura reepeat, não pode ser usada desta forma.

Knowledge is free!

Link to comment
Share on other sites

Como é que fazias? @thoga31

Não sei o que achas que aquele if faz porque, como disse o @nunopicado, ele não tem ali qualquer género de função:

repeat
  // ...
  if not (fecho='n') and (fecho='s') or (fecho='N') and (fecho='S') then
     // then... then what??
Until (fecho='n') or (fecho='s') or (fecho='N') or (fecho='S');

Aquele if só faz sentido se tu quiseres dizer alguma coisa ao utilizador caso ele não pressione as teclas S e N.

Algumas notas (aplicadas ao exemplo aqui citado, mas aplicável a todos os locais onde tentaste fazer aquilo):

  1. A condição no if está mal implementada:

    1. O not só está a abranger a condição (fecho='n');
    2. Os and e or estão mal aplicados.

[*]Em vez de...



Until (fecho='n') or (fecho='s') or (fecho='N') or (fecho='S')

... usa antes uma das seguintes opções:



until (upcase(fecho)) = 'N') or (upcase(fecho)) = 'S'); // upcase transforma em maiuscula
until (lowercase(fecho)) = 'n') or (lowercase(fecho)) = 's'); // lowercase transforma em minúscula

until upcase(fecho) in ['N','S']; // uso do operador IN

Knowledge is free!

Link to comment
Share on other sites

Thoga31 eu uso o if mesmo por essa razão! Se o utiluzador não pressionar a tecla S ou a tecla N.

Eu até poderia usar o upcase e o lowercase mas o meu professor não ensinou essas 2 instruções...

Já agora, para que serve o upcase e o lowercase?

Abraço.

Edited by daniel_silva
Link to comment
Share on other sites

Thoga31 eu uso o if mesmo por essa razão! Se o utiluzador não pressionar a tecla S ou a tecla N.

Tenta perceber isto: O IF não faz nada. Absolutamente nada.

A ideia poderia até ser essa, mas na prática, não é.

Experimenta tirá-lo a ver se muda alguma coisa... Nada!

Eu até poderia usar o upcase e o lowercase mas o meu professor não ensinou essas 2 instruções...

Eu até compreendo que há professores que sabem pouco do que estão fazer e então não querem que os alunos explorem sozinhos, não vão eles descobrir algo que eles próprios não sabem.

Mas um programador não pode limitar-se ao que aprendeu. O limite deve ser o que pode aprender.

Um programador deve saber procurar as soluções indicadas para o seu problema. Se estás à espera do que te possa ensinar o professor, não fazes nada.

Lembra-te que o professor, mesmo que seja bom, tem um programa a seguir, e tem vários alunos com diferentes níveis de aprendizagem.

Ele não vai poder falar de tudo.

Logo que saibas justificar bem o porquê de usar isto em detrimento daquilo, podes e deves procurar aprender e usar o que aprendes, se isso for a melhor solução para o problema. Isto não inclui, é claro, usar coisas que aprendeste só porque sim, sem nenhuma mais-valia para a solução.

Que o professor possa não gostar? Pode. Mas só se ele for de visão limitada.

Mas se o professor for em condições, esse tipo de interesse só serve para subires uns pontos.

Já agora, para que serve o upcase e o lowercase?

Upcase converte tudo em maiúsculas, lowercase converte em minúsculas.

O Thoga31 já tinha dito lá atrás.

  • Vote 1

"A humanidade está a perder os seus génios... Aristóteles morreu, Newton já lá está, Einstein finou-se, e eu hoje não me estou a sentir bem!"

> Não esclareço dúvidas por PM: Indica a tua dúvida no quadro correcto do forum.

Link to comment
Share on other sites

Thoga31 eu uso o if mesmo por essa razão! Se o utiluzador não pressionar a tecla S ou a tecla N.

Relê o comentário que fiz ao teu código:

repeat
  // ...
  if not (fecho='n') and (fecho='s') or (fecho='N') and (fecho='S') then
     // then... then what??
Until (fecho='n') or (fecho='s') or (fecho='N') or (fecho='S');


Eu até poderia usar o upcase e o lowercase mas o meu professor não ensinou essas 2 instruções...

Reforço veemente este ponto feito pelo @nunopicado:

(...) um programador não pode limitar-se ao que aprendeu. O limite deve ser o que pode aprender.


Já agora, para que serve o upcase e o lowercase?

Relê os comentários ao código:

until (upcase(fecho)) = 'N') or (upcase(fecho)) = 'S');        // upcase transforma em maiuscula
until (lowercase(fecho)) = 'n') or (lowercase(fecho)) = 's');  // lowercase transforma em minúscula

Knowledge is free!

Link to comment
Share on other sites

ou tens de perguntar ao utilizador onde quer guardar os ficheiros.

Boa tarde @nunopicado

Ando a melhorar o meu projeto, e vou fazer o que tu me sugeriste... Perguntar ao utilizador onde quer guardar os ficheiros.

Pelo que já pensei vou ter de fazer uma variável do tipo string (se não estiver enganado) e o utilizador vai ter de introduzir o caminho todo.

Agora a minha dúvida é: Como vou fazer?

Preciso de sugestões pessoal... 😕

Obrigado.

Link to comment
Share on other sites

A minha sugestão é que ponhas isso em opção no menu.

Por exemplo, quando entra no programa a primeira vez, ele assume que o caminho é a pasta onde está o executável.

Depois no menu, o utilizador poderia escrever outro campo.

O que ele escrever terias de guardar num ficheiro, e esse teria mesmo de ser junto ao executável.

"A humanidade está a perder os seus génios... Aristóteles morreu, Newton já lá está, Einstein finou-se, e eu hoje não me estou a sentir bem!"

> Não esclareço dúvidas por PM: Indica a tua dúvida no quadro correcto do forum.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...

Important Information

By using this site you accept our Terms of Use and Privacy Policy. We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.