Auto incremento com sum max?
Boa noite a todos,
Eu gostaria de saber a melhor maneira de implementar um auto incremento no Firebird.
Eu estou fazendo ate o momento com Generators. Estou fazendo alguns testes e não gostei muito.
Quando tento gravar no banco e da algum erro mesmo assim ele gera um novo numero, isso faz com que eu fique
com buracos na numeração do meu banco.
No delphi eu uso o seguinte Código no evento BeforeUpdate Record do DataSetProvider.
onde id é uma variavel que recebe valor 0 na criação do datamodule e é decrementada para passar o valor para o
campo chave da tabela.
Eu tava querendo implementar alguma coisa com select max no evento AfterPost do ClientDataSet.
Queria fazer tipo pra gerar um novo valor só se nao der nem um erro no ApplyUpdates e se todos os campos obrigatorios
estiverem preenchidos ai sim gera o codigo.
So não estou sabendo montar essa instrução.
Alguem tem alguma ideia?
Um exemplo pra me passar?
Eu não quero é deixar furos na numeração.
Eu gostaria de saber a melhor maneira de implementar um auto incremento no Firebird.
Eu estou fazendo ate o momento com Generators. Estou fazendo alguns testes e não gostei muito.
Quando tento gravar no banco e da algum erro mesmo assim ele gera um novo numero, isso faz com que eu fique
com buracos na numeração do meu banco.
No delphi eu uso o seguinte Código no evento BeforeUpdate Record do DataSetProvider.
if UpdateKind = ukInsert then
begin
if SourceDs = sdsCor then
begin
sdsGenCor.Open;
try
id := sdsGenCor.FieldByName('NOVOID').AsInteger;
finally
sdsGenCor.Close;
end;
DeltaDs.FieldByName('CODI_COR').NewValue :=id;
end;
end;
end;onde id é uma variavel que recebe valor 0 na criação do datamodule e é decrementada para passar o valor para o
campo chave da tabela.
Eu tava querendo implementar alguma coisa com select max no evento AfterPost do ClientDataSet.
Queria fazer tipo pra gerar um novo valor só se nao der nem um erro no ApplyUpdates e se todos os campos obrigatorios
estiverem preenchidos ai sim gera o codigo.
So não estou sabendo montar essa instrução.
Alguem tem alguma ideia?
Um exemplo pra me passar?
Eu não quero é deixar furos na numeração.
Willian Amor
Curtidas 0
Respostas
Alisson Santos
19/09/2012
A melhor opção e mais limpa é utilizar o generator com trigger, agora se quiser controlar via programação vai ter que criar uma função para isso.
GOSTEI 0
Deivison Melo
19/09/2012
Dependendo da sua versão do firebird além do controle feito por Generator´s e trigge´s (para alimentar os generator´s), você pode utiliza as sequences (versões mais atuais do firebird).
Ou ainda pode utilizar a função abaixo:
function GeneratorID (aName: string; Connection: TSQLConnection;
Incrementa: Boolean): integer;
var
Qry: TSQLQuery;
begin
Qry := TSQLQuery.Create(nil);
try
Qry.SQLConnection := Connection;
if Incrementa then
Qry.SQL.Add(
'SELECT GEN_ID('+aName+', 1) FROM RDB$DATABASE')
else
Qry.SQL.Add(
'SELECT GEN_ID('+aName+', 0) FROM RDB$DATABASE');
Qry.Open;
Result := Qry.Fields[0].AsInteger;
finally
FreeAndNil(Qry);
end;
end;
Ou ainda pode utilizar a função abaixo:
function GeneratorID (aName: string; Connection: TSQLConnection;
Incrementa: Boolean): integer;
var
Qry: TSQLQuery;
begin
Qry := TSQLQuery.Create(nil);
try
Qry.SQLConnection := Connection;
if Incrementa then
Qry.SQL.Add(
'SELECT GEN_ID('+aName+', 1) FROM RDB$DATABASE')
else
Qry.SQL.Add(
'SELECT GEN_ID('+aName+', 0) FROM RDB$DATABASE');
Qry.Open;
Result := Qry.Fields[0].AsInteger;
finally
FreeAndNil(Qry);
end;
end;
GOSTEI 0
Claudia Nogueira
19/09/2012
A forma correta é realmente generator + trigger.
Tem um artigo meu publicado no firebase sobre esse assunto e espero que seja útil.
Qualquer dúvida pode perguntar.
http://www.firebase.com.br/fb/artigo.php?id=2396
Tem um artigo meu publicado no firebase sobre esse assunto e espero que seja útil.
Qualquer dúvida pode perguntar.
http://www.firebase.com.br/fb/artigo.php?id=2396
GOSTEI 0
Willian Amor
19/09/2012
Vou dar uma olhada nesse que vocês me passaram,
quero uma maneira onde não gere um numero se der erro antes de gravar.
Que so gere um novo valor se realmente o registro for gravado no banco.
quero uma maneira onde não gere um numero se der erro antes de gravar.
Que so gere um novo valor se realmente o registro for gravado no banco.
GOSTEI 0
Willian Amor
19/09/2012
A forma correta é realmente generator + trigger.
Tem um artigo meu publicado no firebase sobre esse assunto e espero que seja útil.
Qualquer dúvida pode perguntar.
http://www.firebase.com.br/fb/artigo.php?id=2396
Tem um artigo meu publicado no firebase sobre esse assunto e espero que seja útil.
Qualquer dúvida pode perguntar.
http://www.firebase.com.br/fb/artigo.php?id=2396
Eu ja havia tentado assim também, porém se der erro na hora de gravação ainda sim ele gera um novo número,
tipo inicializa em zero, o generator ganha o valor 1 e da erro na gravação. Depois se eu for na tabela ela nao tera o
valor 1 ja vai pular para o 2.
function GeneratorID (aName: string; Connection: TSQLConnection;
Incrementa: Boolean): integer;
var
Qry: TSQLQuery;
begin
Qry := TSQLQuery.Create(nil);
try
Qry.SQLConnection := Connection;
if Incrementa then
Qry.SQL.Add(
'SELECT GEN_ID('+aName+', 1) FROM RDB$DATABASE')
else
Qry.SQL.Add(
'SELECT GEN_ID('+aName+', 0) FROM RDB$DATABASE');
Qry.Open;
Result := Qry.Fields[0].AsInteger;
finally
FreeAndNil(Qry);
end;
end;
Incrementa: Boolean): integer;
var
Qry: TSQLQuery;
begin
Qry := TSQLQuery.Create(nil);
try
Qry.SQLConnection := Connection;
if Incrementa then
Qry.SQL.Add(
'SELECT GEN_ID('+aName+', 1) FROM RDB$DATABASE')
else
Qry.SQL.Add(
'SELECT GEN_ID('+aName+', 0) FROM RDB$DATABASE');
Qry.Open;
Result := Qry.Fields[0].AsInteger;
finally
FreeAndNil(Qry);
end;
end;
Eu estava querendo montar o seguinte, uma função realmente.
Por exemplo eu tenho uma função que verifica se os campos obrigatorios foram quando o usuario clica em salvar.
Se foram ele grava, do contrario avisa ao usuario que o campo "TAL" deve ser informado.
O problema é assim. Se passar por essa função mas se der erro no ApplyUpdates(<> 0), ele retorno um erro,
e da maneira como estou fazendo hoje, mesmo dando erro no ApplyUpdates ele gera um novo numero para o Generator,
ai eu perco um numero, fica um furo no meu banco. Eu queria ver se consigo montar algo no beforePost onde
eu ia verificar se ApplyUpdates (= 0) e se os campos obrigatorios foram preenchidos.
Se passar por essas informações ai sim geraria um novo codigo.
Alguem pode me dar uma ideia?
GOSTEI 0
Claudia Nogueira
19/09/2012
Willian eu trabalho com transação, sem ApplyUpdates, então sempre se em um bloco de operações ocorrer um erro (exception) toda a operação é cancelada, sendo assim não incrementa o generator se utilizar o trigger.
Exemplo:
Coloquei aquele iCodigo recebendo o valor do último generator para caso você esteja querendo fazer várias operações, e as inserções subsequentes estiverem ligadas por uma chave com a primeira tabela.
Exemplo:
Var
iCodigo : Integer;
begin
try
IBQuery1.Close;
IBQuery1.SQL.Text := 'INSERT INTO cidade (id_cidade, nome_cidade, uf) VALUES (0, :nome, :uf)';
IBQuery1.ParamByName('nome').AsString := 'SÃO PAULO';
IBQuery1.ParamByName('uf').AsString := 'SP';
IBQuery1.ExecSQL;
iCodigo := 0;
IBQuery1.Close;
IBQuery1.SQL.Text := 'SELECT GEN_ID(GEN_ID_CIDADE, 0) codigo FROM RDB$DATABASE';
IBQuery1.Open;
if not IBQuery1.IsEmpty then
iCodigo := IBQuery1.FieldByName('codigo').AsInteger;
IBTransaction1.CommitRetaining;
except
IBTransaction1.RollbackRetaining;
end;
end;
Coloquei aquele iCodigo recebendo o valor do último generator para caso você esteja querendo fazer várias operações, e as inserções subsequentes estiverem ligadas por uma chave com a primeira tabela.
GOSTEI 0
Alisson Santos
19/09/2012
No caso isso está ocorrendo pois não está abordando o processo, experimente colocar um abort depois que der o erro.
Geralmente eu faço rotina direto no provide dataset abortando o processo.
Geralmente eu faço rotina direto no provide dataset abortando o processo.
GOSTEI 0
Willian Amor
19/09/2012
Willian eu trabalho com transação, sem ApplyUpdates, então sempre se em um bloco de operações ocorrer um erro (exception) toda a operação é cancelada, sendo assim não incrementa o generator se utilizar o trigger.
Exemplo:
Coloquei aquele iCodigo recebendo o valor do último generator para caso você esteja querendo fazer várias operações, e as inserções subsequentes estiverem ligadas por uma chave com a primeira tabela.
Exemplo:
Var
iCodigo : Integer;
begin
try
IBQuery1.Close;
IBQuery1.SQL.Text := 'INSERT INTO cidade (id_cidade, nome_cidade, uf) VALUES (0, :nome, :uf)';
IBQuery1.ParamByName('nome').AsString := 'SÃO PAULO';
IBQuery1.ParamByName('uf').AsString := 'SP';
IBQuery1.ExecSQL;
iCodigo := 0;
IBQuery1.Close;
IBQuery1.SQL.Text := 'SELECT GEN_ID(GEN_ID_CIDADE, 0) codigo FROM RDB$DATABASE';
IBQuery1.Open;
if not IBQuery1.IsEmpty then
iCodigo := IBQuery1.FieldByName('codigo').AsInteger;
IBTransaction1.CommitRetaining;
except
IBTransaction1.RollbackRetaining;
end;
end;
Coloquei aquele iCodigo recebendo o valor do último generator para caso você esteja querendo fazer várias operações, e as inserções subsequentes estiverem ligadas por uma chave com a primeira tabela.
Eu to usando DBExpress.Eu achei que o Provider já cuidava da transação.
No caso isso está ocorrendo pois não está abordando o processo, experimente colocar um abort depois que der o erro.
Geralmente eu faço rotina direto no provide dataset abortando o processo.
Geralmente eu faço rotina direto no provide dataset abortando o processo.
Posso tentar mas quando da erro de Applyupdates ele nao grava nada. Ja aborta a transação. Mas como ele fez a tentativa
de mandar os dados para o banco já gerou um novo numero para o generator.
GOSTEI 0
Willian Amor
19/09/2012
Bom apos realizar alguns testes resolvi usar o Select Max mesmo.
inicialei uma variavel na criação do meu datamodule e no onnewrecord do ClientDataSet eu a decremento para 0.
entao no beforepost do CDS eu verifico se ele for menor que 1 executa o select max, se nao ele deixa o numero que ja está la.
Obrigado a todos....
inicialei uma variavel na criação do meu datamodule e no onnewrecord do ClientDataSet eu a decremento para 0.
entao no beforepost do CDS eu verifico se ele for menor que 1 executa o select max, se nao ele deixa o numero que ja está la.
Obrigado a todos....
GOSTEI 0