Campo Serial
Criei um campo tipo serial no meu BD e tudo bem ? Porém quando vou mandar gravar na tabela através do sistema eu não defino valor para este campo achando que quem deve fazê-lo é o BD. Porém ele me retorna erro dizendo que este campo não pode ser gravado vazio. Alguém sabe como
resolver isso ?
Grande abraço.
resolver isso ?
Grande abraço.
Winfor
Curtidas 0
Respostas
Bon Jovi
16/09/2005
Isso não é normal acontecer, o q está fazendo de diferente? Está usando o q pra inserir o registro? Isso pode ser uma característica do componente que vc está usando.
Ex. normal:
CREATE TABLE tabela
(
sequencial serial NOT NULL,
descricao varchar(50),
CONSTRAINT pk_tabela PRIMARY KEY (sequencial)
);
INSERT INTO tabela (descricao) VALUES (´aaa´);
Executou tudo ok.
SELECT * FROM tabela;
Retornado:
sequencial;descricao
1;´aaa´
Ex. normal:
CREATE TABLE tabela
(
sequencial serial NOT NULL,
descricao varchar(50),
CONSTRAINT pk_tabela PRIMARY KEY (sequencial)
);
INSERT INTO tabela (descricao) VALUES (´aaa´);
Executou tudo ok.
SELECT * FROM tabela;
Retornado:
sequencial;descricao
1;´aaa´
GOSTEI 0
Winfor
16/09/2005
Na verdade, estou utilizando os componentes da Devexpress e utilizando os comando normais de inclusão de registros. Append, post, e applyupdates.
O problema ocorre quando confirmo a inclusão do registro. E eu nem coloquei um componente ligado ao campo código para não haver problema.
A única coisa que fiz de anormal, foi modificar o tipo do campo na tabela após a mesma ter sido criada. Ou seja, ele estava como integer e eu passei para Serial.
No programa de manipulação do BD que é o EMS Manager funciona normalmente.
O problema ocorre quando confirmo a inclusão do registro. E eu nem coloquei um componente ligado ao campo código para não haver problema.
A única coisa que fiz de anormal, foi modificar o tipo do campo na tabela após a mesma ter sido criada. Ou seja, ele estava como integer e eu passei para Serial.
No programa de manipulação do BD que é o EMS Manager funciona normalmente.
GOSTEI 0
Bon Jovi
16/09/2005
Vc deverá dar Refresh após um ApplyUpdates, para que o componente possa saber que o campo SERIAL foi atribuído pelo SEQUENCE no servidor. Ex.:
Gravou no banco e retornou: 1, 2, 3
procedure TfrmTeste.btnTesteClick(Sender: TObject); var i: integer; begin ADOCommand1.CommandText := ´CREATE TABLE teste (id_teste serial PRIMARY KEY, descricao VARCHAR(10))´; ADOCommand1.Execute; ADODataSet1.CommandText := ´SELECT id_teste, descricao FROM teste´; ClientDataSet1.Open; for i := 1 to 3 do begin ClientDataSet1.Append; ClientDataSet1.FieldByName(´descricao´).AsString := ´teste_´ + IntToStr(i); ClientDataSet1.Post; ClientDataSet1.ApplyUpdates(-1); ClientDataSet1.Refresh; end; ClientDataSet1.First; while not ClientDataSet1.Eof do begin ShowMessage(´ID_TESTE = ´ + ClientDataSet1.FieldByName(´id_teste´).AsString); ClientDataSet1.Next; end; end;
Gravou no banco e retornou: 1, 2, 3
GOSTEI 0
Bon Jovi
16/09/2005
Podem haver outras saídas mais otimizadas, pois não sou de usar o tipo ´SERIAL´. Eu prefiro usar SEQUENCE (CREATE SEQUENCE), ou seja, desamarrado do campo, assim ganha-se mais controle.
GOSTEI 0
Winfor
16/09/2005
Amigo Bon Jovi
Na verdade, quando eu modifiquei o campo para serial ele criou um item na seção sequences do BD. Desta forma:
CREATE SEQUENCE ´public´.´professores_wpro_codigo_seq´
INCREMENT 1 MINVALUE 1
MAXVALUE 2147483647 START 5
CACHE 1;
Imagino que este sequence se assemelha ao campo Generator do Interbase, mas não sei como buscá-lo em tempo de execução. Na edição desta seguencia ele me mostra quais os valores aceita acima e qual será o próximo, mas não tô sabendo buscar isso de dentro do programa.
Vc busca na hora de postar o código ? Como ?
Estou estudando o manual do Postgres mas ainda não cheguei lá.
Valeu pela força. Grande abraço.
Wellington.
Na verdade, quando eu modifiquei o campo para serial ele criou um item na seção sequences do BD. Desta forma:
CREATE SEQUENCE ´public´.´professores_wpro_codigo_seq´
INCREMENT 1 MINVALUE 1
MAXVALUE 2147483647 START 5
CACHE 1;
Imagino que este sequence se assemelha ao campo Generator do Interbase, mas não sei como buscá-lo em tempo de execução. Na edição desta seguencia ele me mostra quais os valores aceita acima e qual será o próximo, mas não tô sabendo buscar isso de dentro do programa.
Vc busca na hora de postar o código ? Como ?
Estou estudando o manual do Postgres mas ainda não cheguei lá.
Valeu pela força. Grande abraço.
Wellington.
GOSTEI 0
Winfor
16/09/2005
Aliás, estou tentando buscar este valor assim:
Wdm_cadastro.Qry_auxCadastro.Close;
Wdm_cadastro.Qry_auxCadastro.SQL.Add(´SELECT nextval(´public´.´sequence´.´professores_wpro_codigo_seq´) AS ULTIMOCODIGO´);
Wdm_cadastro.Qry_auxCadastro.Open;
Wdm_cadastro.Qry_auxCadastro.ExecSQL;
Nem sei se está certo, pq estou começando agora com SQL, mas ele erro se coloco public, se coloco sequence e se não coloco nada em nextval.
Vc sabe a sintaxe correta pra isso aí :)
Valeu mais uma vez !!!
Wdm_cadastro.Qry_auxCadastro.Close;
Wdm_cadastro.Qry_auxCadastro.SQL.Add(´SELECT nextval(´public´.´sequence´.´professores_wpro_codigo_seq´) AS ULTIMOCODIGO´);
Wdm_cadastro.Qry_auxCadastro.Open;
Wdm_cadastro.Qry_auxCadastro.ExecSQL;
Nem sei se está certo, pq estou começando agora com SQL, mas ele erro se coloco public, se coloco sequence e se não coloco nada em nextval.
Vc sabe a sintaxe correta pra isso aí :)
Valeu mais uma vez !!!
GOSTEI 0
Bon Jovi
16/09/2005
Sim, ele cria, mas se vc agora está querendo atribuir manualmente, por que está usando o tipo SERIAL?
Faz normal:
CREATE TABLE cliente (id_cliente numeric(15) primary key, nome_cliente varchar(50));
CREATE SEQUENCE sequencial_cliente MINVALUE 1;
E no Delphi atribui ao campo:
SELECT nextval(´sequencial_cliente´) AS proximo
Faz normal:
CREATE TABLE cliente (id_cliente numeric(15) primary key, nome_cliente varchar(50));
CREATE SEQUENCE sequencial_cliente MINVALUE 1;
E no Delphi atribui ao campo:
SELECT nextval(´sequencial_cliente´) AS proximo
GOSTEI 0
Winfor
16/09/2005
Na verdade, não estou querendo atribuir manualmente. Como ele está me retornando erro falando que o campo não pode ficar vazio. Estou tentando buscar em tempo de execução qual será o próximo código e atribí-lo no post. Assim ele não dará mais este erro, por isso que estava usando a instrução Sql acima. Mas da forma que vc colocou ele fala que não existe o campo.
Para dar um select na tabela a partir da Query, ele somente aceitou quando eu coloquei assim:
SELECT * FROM ´public´.´professores´
De outra forma, sem o public ele fala que não existe a tabela.
Por isso que ao buscar o próximo código usei aquela instruição acima.
Continuo tentando.... aqui...
Obrigado pela paciência migão...
Para dar um select na tabela a partir da Query, ele somente aceitou quando eu coloquei assim:
SELECT * FROM ´public´.´professores´
De outra forma, sem o public ele fala que não existe a tabela.
Por isso que ao buscar o próximo código usei aquela instruição acima.
Continuo tentando.... aqui...
Obrigado pela paciência migão...
GOSTEI 0
Bon Jovi
16/09/2005
Usou o Refresh após o ApplyUpdates como no exemplo? Pois isso funciona.
GOSTEI 0
Bon Jovi
16/09/2005
Se não estiver funcionando com sua aplicação, execute meu exemplo completo em uma aplicação nova e verá que funciona. Daí vc vai vendo o q tem de diferente na sua aplicação.
Só não coloquei a parte de conexão nesse exemplo, em que usei conexão ADO com driver ODBC.
Só não coloquei a parte de conexão nesse exemplo, em que usei conexão ADO com driver ODBC.
GOSTEI 0
Winfor
16/09/2005
É. Fiz uma nova aplicação, segui bem de perto os passos que vc fez, a diferença é que estou usando o Zeos 6.5.1 que tem protocolo até o Postgres 7.4 enquanto estou usando o 8.01.
Fiz uma nova aplicação, porém ao dar o Post, ele retorna o mesmo erro, mesmo dando o Refresh junto com o Apply. Mudei o Refresh de lugar, tentei outra atualização e não deu certo.
E na instrução SQL fala que não existe o campo sequencial que estou me referindo. Tentei usando ´public´, ´public´.´sequence´.nomedocampo, somente o nome do campo e ele continua não localizando o mesmo no BD.
Acho que o caminho é por aqui, tenho só que arranjar uma forma na sintaxe SQL de me comunicar com este campo serial e pegar o próximo valor dele. Fazendo isto posso atribuí-lo a um Dbedit e mandar postar pq aí eu sei que funciona. Pois já fiz o teste atribuindo diretamente um valor ao campo.
Continuando minha saga, obrigado pela atenção e ajuda.
Fiz uma nova aplicação, porém ao dar o Post, ele retorna o mesmo erro, mesmo dando o Refresh junto com o Apply. Mudei o Refresh de lugar, tentei outra atualização e não deu certo.
E na instrução SQL fala que não existe o campo sequencial que estou me referindo. Tentei usando ´public´, ´public´.´sequence´.nomedocampo, somente o nome do campo e ele continua não localizando o mesmo no BD.
Acho que o caminho é por aqui, tenho só que arranjar uma forma na sintaxe SQL de me comunicar com este campo serial e pegar o próximo valor dele. Fazendo isto posso atribuí-lo a um Dbedit e mandar postar pq aí eu sei que funciona. Pois já fiz o teste atribuindo diretamente um valor ao campo.
Continuando minha saga, obrigado pela atenção e ajuda.
GOSTEI 0
Bon Jovi
16/09/2005
Se não usar SERIAL e criar o SEQUENCE solto já seria uma solução imediata.
Coloque o trecho do seu código aqui, DFM dos componentes relacionados tb. Assim posso ver o q está fazendo. Coloque tudo que for diretamente relacionado, script da tabela tb.
Coloque o trecho do seu código aqui, DFM dos componentes relacionados tb. Assim posso ver o q está fazendo. Coloque tudo que for diretamente relacionado, script da tabela tb.
GOSTEI 0
Winfor
16/09/2005
Olá, Bon Jovi
Estive fora por 3 dias por isso sumi.
Eu utilizo um Trial da EMS Manager PostgresSQL para gerenciar e criar as tabelas, índices e outros do BD. Por isso não preciso necessariamente postar instruções SQL dentro da aplicação para dar manutenção do BD.
Na tela em questão do problema do campo serial, utilizo componentes da Devexpress normalmente, então coloco componentes cxdbEdit, CxMaskEdit, etc...
Utilizo tb o componente de menu da MaxComponets para o menu tipo outlook
Todos componentes tipo padrão que não dão interferências.
Então, após conectado o BD e criadas as tabelas com os Querys, clientDatasets, providers e DataSource. E criados os respectivos Tfields, dou um insert ou append e após a edição dos campos faço a rotina abaixo.
if MessageDlg(´Confirma a gravação dos dados deste funcionário ?´, mtConfirmation, [mbYes, mbNo], 0) = mrYes then
begin
//CxTextEdit2.Text := intToStr(Wdm_cadastro.CDfuncionarioWPRO_CODIGO.value);
Try //Se a tabela está inserindo
If (Wdm_cadastro.CDfuncionario.State = DsInsert) then
Begin
Ufuncoes.WBotoes(Wdm_cadastro.DSfuncionario.DataSet,6);
end
else
ShowMessage(´Falha na atualização, o arquivo não está em modo de alteração !´);
Wdm_cadastro.CDfuncionario.ApplyUpdates(-1);
Wdm_cadastro.CDfuncionario.Refresh;
except
ShowMessage(´Erro de gravação´);
end;
At_botoes;
end;
Tudo dentro do padrão que a maioria está acostumada.
Dentro do EMS Manager os campos já estão definidos como serial. A única coisa que eu acho que poderia fazer alguma diferença, é o fato do campo codigo ter sido criado como Integer e depois eu o passai para Serial.
Se precisar de mais aguma informação é só falar.
Brigado migão...
Estive fora por 3 dias por isso sumi.
Eu utilizo um Trial da EMS Manager PostgresSQL para gerenciar e criar as tabelas, índices e outros do BD. Por isso não preciso necessariamente postar instruções SQL dentro da aplicação para dar manutenção do BD.
Na tela em questão do problema do campo serial, utilizo componentes da Devexpress normalmente, então coloco componentes cxdbEdit, CxMaskEdit, etc...
Utilizo tb o componente de menu da MaxComponets para o menu tipo outlook
Todos componentes tipo padrão que não dão interferências.
Então, após conectado o BD e criadas as tabelas com os Querys, clientDatasets, providers e DataSource. E criados os respectivos Tfields, dou um insert ou append e após a edição dos campos faço a rotina abaixo.
if MessageDlg(´Confirma a gravação dos dados deste funcionário ?´, mtConfirmation, [mbYes, mbNo], 0) = mrYes then
begin
//CxTextEdit2.Text := intToStr(Wdm_cadastro.CDfuncionarioWPRO_CODIGO.value);
Try //Se a tabela está inserindo
If (Wdm_cadastro.CDfuncionario.State = DsInsert) then
Begin
Ufuncoes.WBotoes(Wdm_cadastro.DSfuncionario.DataSet,6);
end
else
ShowMessage(´Falha na atualização, o arquivo não está em modo de alteração !´);
Wdm_cadastro.CDfuncionario.ApplyUpdates(-1);
Wdm_cadastro.CDfuncionario.Refresh;
except
ShowMessage(´Erro de gravação´);
end;
At_botoes;
end;
Tudo dentro do padrão que a maioria está acostumada.
Dentro do EMS Manager os campos já estão definidos como serial. A única coisa que eu acho que poderia fazer alguma diferença, é o fato do campo codigo ter sido criado como Integer e depois eu o passai para Serial.
Se precisar de mais aguma informação é só falar.
Brigado migão...
GOSTEI 0
Winfor
16/09/2005
Outro detalhe me chamou a atenção hoje aqui, ao fazer um outro exemplo simples usando clientDataset, query, provide, Datasource e Zeos Zconection, e os componentes padrão do Delphi.
2 DbEdit´s e um Dbnavigator.
Além de dar o mesmo erro de não aceitar o campo código vazio, se eu preencher o campo código com algum número, ele não atualiza o contador serial da tabela.
Por exemplo:
Tabela de portadores: Codigo (serial), Descricao (Varchar(30)
Tabela Vazia.
Ao inserir um registro com o dbedit em branco dá erro.
Ao inserir um registro com o dbedit com valor = 1 ele aceita
Ao inserir um registro com o dbedit com valor = 2 ele aceita
Ao tentar inserir um registro pelo gerenciador EMS Manager ele começa a contagem novamente dos registros. Ou seja, começa do 1. Pode ???
Tá complicado...
2 DbEdit´s e um Dbnavigator.
Além de dar o mesmo erro de não aceitar o campo código vazio, se eu preencher o campo código com algum número, ele não atualiza o contador serial da tabela.
Por exemplo:
Tabela de portadores: Codigo (serial), Descricao (Varchar(30)
Tabela Vazia.
Ao inserir um registro com o dbedit em branco dá erro.
Ao inserir um registro com o dbedit com valor = 1 ele aceita
Ao inserir um registro com o dbedit com valor = 2 ele aceita
Ao tentar inserir um registro pelo gerenciador EMS Manager ele começa a contagem novamente dos registros. Ou seja, começa do 1. Pode ???
Tá complicado...
GOSTEI 0
Bon Jovi
16/09/2005
Vc está usando uma variedade de componentes de terceiros, infelizmente fica complicado pra eu ajudar em relação a eles, ainda mais sem ver o código completo do .pas, .dfm e script .sql.
Zeos já está bem estável com Midas?? Costumo sempre que possível usar os componentes mais padrões. Com ADO sei que funciona redondo. Se puder faz esse teste simples com ADO + ODBC. Ou poste um novo tópico mais específico: ´Campo Serial com Zeos + Midas´.
Zeos já está bem estável com Midas?? Costumo sempre que possível usar os componentes mais padrões. Com ADO sei que funciona redondo. Se puder faz esse teste simples com ADO + ODBC. Ou poste um novo tópico mais específico: ´Campo Serial com Zeos + Midas´.
GOSTEI 0
Winfor
16/09/2005
Grande Bon Jovi,
Cara depois de muita luta e de te encher a paciência, consegui fazer funcionar o lance do campo serial. Consegui, assim. Como eu já havia lhe dito, como o bd me retornava erro e não adicionava sozinho o próximo código a um campo serial, eu optei por buscar com nextval e passar ao campo para que o erro não existisse.
Então estava utilizando a query desta forma.
Wdm_cadastro.Qry_auxCadastro.Close;
Wdm_cadastro.Qry_auxCadastro.SQL.Clear;
Wdm_cadastro.Qry_auxCadastro.SQL.Add(´SELECT nextval(´+quotedStr(´public.professores_wpro_codigo_seq´)+´) AS ULTIMOCODIGO´);
Wdm_cadastro.Qry_auxCadastro.Open;
Result := Wdm_cadastro.Qry_auxCadastro.params[0].assinteger;
E descobri depois que a aplicação simplesmente não estava exergando o parâmetro ULTIMOCODIGO apesar dele existir e estar criado no componente. Então simplesmente mudei o final da instrução para:
Result := Wdm_cadastro.Qry_auxCadastro.fieldbyName(´ultimocodigo´).AsInteger;
E funcionou bala.
Agora só tenho a te agradecer pela constante ajuda e disposição em me dar novas informações. Você é um kra 10. Valeu mesmo.
Só me responde mais uma coisa. Se o Servidor do Postgres só instala em Winxp, 2000, NT, etc... como fica o acesso a partir de estações com W98 ? Existe um Client do Postgres específico para ele ?
Grande abraço e conte com esse amigo aqui.
Cara depois de muita luta e de te encher a paciência, consegui fazer funcionar o lance do campo serial. Consegui, assim. Como eu já havia lhe dito, como o bd me retornava erro e não adicionava sozinho o próximo código a um campo serial, eu optei por buscar com nextval e passar ao campo para que o erro não existisse.
Então estava utilizando a query desta forma.
Wdm_cadastro.Qry_auxCadastro.Close;
Wdm_cadastro.Qry_auxCadastro.SQL.Clear;
Wdm_cadastro.Qry_auxCadastro.SQL.Add(´SELECT nextval(´+quotedStr(´public.professores_wpro_codigo_seq´)+´) AS ULTIMOCODIGO´);
Wdm_cadastro.Qry_auxCadastro.Open;
Result := Wdm_cadastro.Qry_auxCadastro.params[0].assinteger;
E descobri depois que a aplicação simplesmente não estava exergando o parâmetro ULTIMOCODIGO apesar dele existir e estar criado no componente. Então simplesmente mudei o final da instrução para:
Result := Wdm_cadastro.Qry_auxCadastro.fieldbyName(´ultimocodigo´).AsInteger;
E funcionou bala.
Agora só tenho a te agradecer pela constante ajuda e disposição em me dar novas informações. Você é um kra 10. Valeu mesmo.
Só me responde mais uma coisa. Se o Servidor do Postgres só instala em Winxp, 2000, NT, etc... como fica o acesso a partir de estações com W98 ? Existe um Client do Postgres específico para ele ?
Grande abraço e conte com esse amigo aqui.
GOSTEI 0
Bon Jovi
16/09/2005
Result := Wdm_cadastro.Qry_auxCadastro.params[0].assinteger;
Qto a isso aí, nem é por questao do campo serial, mas o mais correto é usar FieldByName: Result := Query.FieldByName(´ULTIMOCODIGO´).AsInteger;
Sobre estação cliente Win98, é possível sim acessar o servidor PostgreSQL. Por exemplo, pra quem usa ADO deve instalar o driver ODBC ou OLE DB. Nao sei responder sobre Zeos, mas acho que ele não deve precisar de nada.
Sobre usar o Win98 como servidor PostgreSQL, já li em algum lugar que tem como instalar na mão o PostgreSQL em sistema de arquivos FAT. Mas eu não vejo o menor sentindo, DOS/Win9x são lixos, é risco total.
Qto a isso aí, nem é por questao do campo serial, mas o mais correto é usar FieldByName: Result := Query.FieldByName(´ULTIMOCODIGO´).AsInteger;
Sobre estação cliente Win98, é possível sim acessar o servidor PostgreSQL. Por exemplo, pra quem usa ADO deve instalar o driver ODBC ou OLE DB. Nao sei responder sobre Zeos, mas acho que ele não deve precisar de nada.
Sobre usar o Win98 como servidor PostgreSQL, já li em algum lugar que tem como instalar na mão o PostgreSQL em sistema de arquivos FAT. Mas eu não vejo o menor sentindo, DOS/Win9x são lixos, é risco total.
GOSTEI 0
Jpseixas
16/09/2005
A sua solução é válida, mas só contorna o problema, ao invés de resolvê-lo. Tive a mesma dor-de-cabeça, e encontrei a solução definitiva.
Na verdade, o problema está no Zeoslib, que não percebe que um campo ´not null´ que possua um valor default (ou um valor automático, como o serial), deve ser deixado em branco.
Você pode alterar uma pequena parte do código-fonte do Zeoslib para corrigir o problema. A solução está neste tópico:
http://zeos.firmos.at/viewtopic.php?=&p=3758
Espero ter ajudado!
Na verdade, o problema está no Zeoslib, que não percebe que um campo ´not null´ que possua um valor default (ou um valor automático, como o serial), deve ser deixado em branco.
Você pode alterar uma pequena parte do código-fonte do Zeoslib para corrigir o problema. A solução está neste tópico:
http://zeos.firmos.at/viewtopic.php?=&p=3758
Espero ter ajudado!
GOSTEI 0