setNull insere 0 e nao NULL

Ajuda pessoal ja tentei de tudo aqui para inserir um valor NULL em umca mpo NUMBER no oracle através de um preparedStatement porem ele sempre insere o valor 0 (zero), e como esse campo é um FK o oracle me retorna um erro de violação de integridade.

Estou utilizando ojdbc 1.4 e ja tentei das seguintes maneiras abaixo nenhum com sucesso.

psta.setNull(7, java.sql.Types.NUMERIC);
psta.setNull(7, java.sql.Types.INTEGER);
psta.setNull(7, java.sql.Types.NULL);
psta.setNull(7, java.sql.Types.VARCHAR); /*tentei ate assim para ver se consegui burlar mas nada feito*/

Ja nao sei mais o que tentar

eaee pessoallll nao e possivel que ninguem aqui ja passou por esse problemas com o oracle

cara… se vc quer que apareça null no campo é so ir la na sua tabela e deixar como null(tire o not null).
pelo menos com mysql funciona assim.

Certifique-se que o campo da sua tabela aceita nulo.
Se aceitar, esse comportamento é mesmo estranho. Qual é o driver que você está utilizando?

Sim o campo aceita null eu ja ate desativei a constraint para poder ver o que o java esta inserindo na tabela e realmente ele insere 0 ao em vez de null.

Estou utilizando o OJDBC 1.4, voce ja passou por isso ViniGodoy ???

To quase para fazer oq vinha fazendo em sistemas antigos q era montar a sql de acordo se o campo tem ou nao valor para poder driblar esse problema do java.

Nao e possivel que nao tenha correção para esse problema

Estranho, isso sempre funcionou. É até como está na documentação da Oracle:
http://download.oracle.com/docs/cd/B14117_01/java.101/b10979/datacc.htm

Você pode postar sua query?

Connection con = ConexaoDAO.getInstance().getConexao();
PreparedStatement psta = null;

List<ApontamentoFuncionario> listaApontFunc = apontamento.getApontamentoFuncionarios();

sql = " INSERT INTO FORCATRABALHO.APONTAMENTO_FUNCIONARIO"
	+ " ("
	+ "   APO_RECNO,"
	+ "   FUN_RECNO,"
	+ "   SIT_RECNO,"
	+ "   HAB_RECNO,"
	+ "   FUN_SITUACAO,"
	+ "   APF_RESUMO_AREA,"
	+ "   ARE_RECNO"
	+ " )"
	+ " VALUES"
	+ " ("
	+ "   ?,"
	+ "   ?,"
	+ "   ?,"
	+ "   ?,"
	+ "   ?,"
	+ "   ?,"
	+ "   ?"
	+ " )";

psta = con.prepareStatement(sql);

psta.setInt(1, apontamento.getRecno());
psta.setInt(2, apontamentoFuncionario.getFuncionario().getRecno());
psta.setInt(3, apontamentoFuncionario.getSituacao().getRecno());
psta.setInt(4, apontamentoFuncionario.getHabilidade().getRecno());
psta.setString(5, apontamentoFuncionario.getFuncionario().getSituacao());
psta.setString(6, apontamentoFuncionario.getResumoArea());

if (apontamentoFuncionario.getArea() != null) {
	psta.setInt(7, apontamentoFuncionario.getArea().getRecno());
} else {
	psta.setNull(7, java.sql.Types.NUMERIC);
}

psta.execute();
con.commit();

Segue a estrtura da tabela

CREATE TABLE FORCATRABALHO.APONTAMENTO_FUNCIONARIO (
    APO_RECNO       NUMBER,
    FUN_RECNO       NUMBER,
    SIT_RECNO       NUMBER,
    HAB_RECNO       NUMBER,
    FUN_SITUACAO    VARCHAR2(50 BYTE),
    APF_RESUMO_AREA VARCHAR2(2000 BYTE),
    ARE_RECNO       NUMBER,
    CONSTRAINT PK_APONTAMENTO_FUNCIONARIO PRIMARY KEY (FUN_RECNO, APO_RECNO),
    CONSTRAINT FK_APONTFUNC_APONTAMENTO FOREIGN KEY (APO_RECNO) REFERENCES FORCATRABALHO.APONTAMENTO (APO_RECNO) ON DELETE CASCADE ENABLE,
    CONSTRAINT FK_APONTFUNC_FUNCIONARIO FOREIGN KEY (FUN_RECNO) REFERENCES DBT.FUNCIONARIO (FUN_RECNO) ENABLE,
    CONSTRAINT FK_APONTFUNC_SITUACAO FOREIGN KEY (SIT_RECNO) REFERENCES FORCATRABALHO.SITUACAO (SIT_RECNO) ENABLE,
    CONSTRAINT FK_APONTFUNC_HABILIDADE FOREIGN KEY (HAB_RECNO) REFERENCES FORCATRABALHO.HABILIDADE (HAB_RECNO) ENABLE,
    CONSTRAINT FK_APONTFUNC_AREA FOREIGN KEY (ARE_RECNO) REFERENCES FORCATRABALHO.AREA (ARE_RECNO) ENABLE
)

Essa fk quem da erro FK_APONTFUNC_AREA pq insere zero e nao existe registro com o a PK 0

Estou tentando de tudo aqui e não ta indo por nada…

Bom dia a todos.

O que pode estar acontecendo é que o Oracle pode ter uma função interna que insere zeros em campos númericos quando os mesmos não são preenchidos.

Acho estranho colocar “null” em campos numéricos, pois isto pode te dar outra dor de cabeça mais tarde, quando voce quiser fazer qualquer cálculo com os mesmos, e por isso que talvez esta função seja necessária.

Particularmente eu não conheço o Oracle, porém se isto for verdade, voce pode criar uma trigger para colocar o valor “null” caso o campo receba zero, porém continuo achando que isto não seja recomendável, principalmente se este campo númerico for chave estrangeira de outra tabela, então o que voce deve fazer é colocar de novo o “Constraint” e implementar dentro de sua aplicação que este campo seja requerido, ou seja, que o seu preenchimento seja obrigatório e cujo valor seja diferente de zero.

Um abraço.

Obrigado pela ajuda discorpio, estava pensando nessa rotina de trigger ou como havia dito acima colocar um if para manipular a forma de criar sql dinamicamente nao inserindo os campos nulos na construção do insert mas isso me parece tao gambiarra que nao acredito que o nosso amigo java nao tenha uma saida para essa situação.

Com relação ao Oracle deixar inserir null em campos do tipo Number isso é possivel sim e nesse caso eu preciso deixar isso em branco pois é uma aplicação de apontamento diario dos funcionarios então caso o funcionario esteja com situacao igual a folga, atestado, afastado entre outras o supervisor nao precisa apontar a area que o mesmo ira trabalhar no dia seguinte por isso ele precisa ser null.

Estou comecando a achar que pode ser problema com a versao do ojdbc 1.4 sera que isso e bug de versao???

Estranho, esse código está correto.
Provavelmente o problema está em outro lugar.

Olá, sou eu de novo.

Analisando a sua query, pois quando estava escrevendo este post, ainda não a tinha visto, acho que a melhor solução, e você criar um registro com índice 0 (Zero) dentro da sua tabela “Area” cuja descrição seja “Área Inexistente” ou “Sem área” ou como preferir, assim voce mata o problema de vez. Assim sendo, voce só precisaria de escrever o seu código assim:

if (apontamentoFuncionario.getArea() != null) {  
    psta.setInt(7, apontamentoFuncionario.getArea().getRecno());  
}

Faça este teste, e veja se ele continua inserindo zero, em caso positivo, então é porque existe aquela função do oracle que te falei e o melhor mesmo é criar o registro citado acima.

Um abraço.

Consegui contornar o problema de uma maneira nao muito elegante mas a menos pior ate o momento.

Usuei a funcao NVL() do Oracle para caso o parametro for null inserir NULL direto na sql do insert, iss foi bem porquinho mas o java nao ta me dando outra opcao…

Se alguem tiver uma sugestao melhor me ajude pq isso vai acontecer em diversos pontos do sistema

Segue solução temporaria

sql = " INSERT INTO FORCATRABALHO.APONTAMENTO_FUNCIONARIO"
	+ " ("
	+ "   APO_RECNO,"
	+ "   FUN_RECNO,"
	+ "   SIT_RECNO,"
	+ "   HAB_RECNO,"
	+ "   FUN_SITUACAO,"
	+ "   APF_RESUMO_AREA,"
	+ "   ARE_RECNO"
	+ " )"
	+ " VALUES"
	+ " ("
	+ "   ?,"
	+ "   ?,"
	+ "   ?,"
	+ "   ?,"
	+ "   ?,"
	+ "   ?,"
	+ "   NVL(?,NULL)"
	+ " )";

Olá Thianolima.

Fico feliz que tenha encontrado a solução do seu problema, isto no Oracle, porém gostaria que voce não pensasse que isto seja um defeito do nosso amigo Java só porque ele não te deu a solução. Afinal, o que a linguagem JAVA faz e tentar se aproximar o máximo possível de todas as peculiaridades dos diversos bancos de dados existente no mercado, e voce há de convir que isto não é fácil, seria como dizer “Agradar a gregos e troianos”, pois sempre não haverá uma padronização formal.

E por falar em padronização, acredito que o nosso amigo Java, poderia te dar uma solução, através da criação de um método criado por ti, para resolver o problema e não pense também que isto seja uma gambiarra, pois o que voces chamam de “gambiarra”, eu chamo de adaptação da aplicação", pois se foi para isto que as diversas linguagens foram criadas, ou seja, fazer uma aplicação que se adapte as peculiaridades do usuário, então porque não fazer as adaptações (gambiarras) para as peculiaridades do banco de dados.

Um abraço

ehhh realmente ViniGodoy voce estava certo retira essa gambiarra monstra que eu fiz que o problema era a minha validacao do parametro pois o java estava colocando 0 como default para o campo inteiro do objeto e eu estava validando somente com se o objeto era diferente de null, como o usuario tem a possibilidade de carregar os dados do dia anterior para preencher o cadastro entao ele iniciava esse objeto com valor default.

Resumindo mudei meu if para

                    if ((apontamentoFuncionario.getArea() != null) && (apontamentoFuncionario.getArea().getRecno() != 0)) {
                        psta.setInt(7, apontamentoFuncionario.getArea().getRecno());
                    } else {
                        psta.setNull(7, java.sql.Types.NUMERIC);
                    }

Olha eu reclamando do nosso amigo java sem ter culpa…rs…rs

Valeu ae pela ajuda e conselhos de todos que partiparam aqui…

abraço a todos

thianolima, acompanhando a solução que deu para este caso tenho que confessar que não vejo o menor sentido nisso.

A função NVL vai utlizar o segundo valor passado como parâmetro, quando o primeiro for nulo.
Se o primeiro valor fosse nulo (pra estar funcionando a nvl), não seria necessário utilizá-la em primeiro lugar.

Infelizmente também não consigo sugerir nenhuma solução provável para o seu problema, pois parece estar tudo certo.

O que posso sugerir é que faça alguns testes para tentar identificar a origem do problema:

  • Rode essa query diretamente no Sql’plus (ou seu client Oracle) passando null;
  • Rode essa query com o valor null diretamente na query, sem utilizar o ? e setNull;
  • Rode essa query sem incluir o campo ARE_RECNO na query;
  • Crie uma outra tabela a parte do sistema e verifique se ocorre o mesmo problema;

Com esse tipo de testes, eu tentaria determinar exatamente quem está fazendo algo errado na história.
Pode ser a versão de driver jdbc, pode ser alguma trigger do Oracle, alguma constraint de valor default. etc.

De minha parte posso assegurar que tenho sistemas rodando com essa combinação java+oracle+setNull e funciona normalmente.

As vezes as soluções são mais simples do que pensamos.

EDIT: Desculpe, só vi sua resposta depois de ter mandado a minha.
Como eu disse, era mais simples do que pensamos.

Pois e amigo AbelBueno é sempre assim quando o problema ta muito complicado de resolver é porque esse não é o problema …rs