Pessoal acesso o banco Oracle com Java tranquilo. Tem como eu utilizar um função do banco Oracle. O DBA criou uma função e eu preciso acessa-la via o meu app em Java.
"Puxar" uma função do banco Oracle
25 Respostas
Você diz uma stored procedure? Dá sim. Veja aquele método prepareCall de java.sql.Connection e a classe CallableStatement.
Fora as procedures (“Procedimentos Armazenados”) existem também funções no Oracle.
Leia este artigo
http://www.samspublishing.com/articles/article.asp?p=26251&seqNum=6&rl=1
basicamente é questão de dar o nome certo. Veja o item “Packaged Procedures and Functions” do tal artigo.
No link que vc postou só achei sobre
Calling Stored Procedures in JDBC Programs
Eu disse para você ler a partir do item “Packaged Procedures and Functions”.
Leia o artigo até o fim.
Cara vi o artigo e estou tentando implementar a solução porém quando executo dá o erro:
PLS-00201: o identificador 'GERA_LOTE' deve ser declarado
ORA-06550: linha1, coluna7
Procurei mas não consegui localizar a origem disso. O meu código que implemento:
public void chamarfuncao(String DataVencimento, String Material,
String Peso){
//Conversão de variáveis para o padrão da função do Oracle
int MaterialInt = Integer.parseInt(Material);
int PesoInt = Integer.parseInt(Peso.substring(0, 2) + Peso.substring(4, 6));
try {
CallableStatement chamaFuncao = conexao.prepareCall("{call GERA_LOTE (?, ?, ?, ?)}");
chamaFuncao.setString(1, DataVencimento.substring(6, 9) + "/" +
DataVencimento.substring(3, 4) + "/" +
DataVencimento.substring(0, 1));
chamaFuncao.setInt(2, MaterialInt);
chamaFuncao.setInt(3, PesoInt);
chamaFuncao.registerOutParameter(4, Types.INTEGER);
chamaFuncao.executeUpdate();
//Resgata o valor de retorno da função e converte para String para setar o jTextField
int lote = chamaFuncao.getInt(4);
Main.jTextFieldLote.setText(String.valueOf(lote));
chamaFuncao.close();
conexao.close();
}catch(SQLException sqle){
JOptionPane.showMessageDialog(null,
"Impossível conectar com o Banco de Dados! Código do erro: " + sqle.toString(),
"Erro!",
JOptionPane.ERROR_MESSAGE);
}
}
Já chequei e todos os campos está sendo passados, será que pode ser algum detalhe na Função no Oracle?
Acredito que você tenha de declarar sua função em um package, e passar o nome do package.
Misteriosamente alterei o nome (no banco) e agora parece que enxerga.
Mas começou a dar um erro de número incorreto de tipos. To ferrado.
Lista o erro aí pra galera dar uma olhada.
Não se esqueça que a conta que acessa essa store procedure deve ter permissão de execução senão nada feito. Taí a explicação do erro:
PLS-00201 identifier 'string' must be declared
Cause: An attempt was made to reference either an undeclared variable, exception, procedure, or other item, or an item to which no privilege was granted or an item to which privilege was granted only through a role.
Action:
Check your spelling and declaration of the referenced name.
Verify that the declaration for the referenced item is placed correctly in the block structure.
If the referenced item is indeed declared but you do not have privileges to refer to that item, for security reasons, you will be notified only that the item is not declared.
If the referenced item is indeed declared and you believe that you have privileges to refer to that item, check the privileges; if the privileges were granted only via a role, then this is expected and documented behavior.
Stored objects (packages, procedures, functions, triggers, views) run in the security domain of the object owner with no roles enabled except PUBLIC. Again, you will be notified only that the item was not declared.
Olha tava chamando uma função, agora alteramos tudo e estou chamando um procedure. Como em um exemplo que vi.
O erro que dá é o seguinte:
ORA-01861: o literal não corresponde a String de formato
ORA-06512: em line 1
Só para ajudar os parametros estão dessa forma:
Minha procedure:
procedure P_GERA_LOTE(P_LOTE out number, P_VENC date, P_MAT number, P_QTD number)
is
cursor C_ULTIMO is
select LTO_NUMERO from LOTES
where LTO_NUMERO in(SELECT nvl(MAX(LTO_NUMERO),0) from LOTES)
for update of LTO_NUMERO;
V_ANO varchar2(4);
V_NUM number;
begin
V_ANO := TO_CHAR(SYSDATE,'RRRR');
open C_ULTIMO;
fetch C_ULTIMO into V_NUM;
if V_NUM is null then
V_NUM := 0;
end if;
V_NUM := TO_NUMBER(REPLACE(V_ANO || TO_CHAR(V_NUM+1,'00000000'),' ',''));
close C_ULTIMO;
insert into LOTES(LTO_NUMERO,LTO_DATA,LTO_DATA_VENC,COD_MAT,LTO_QTD_PESO)
values(V_NUM,TRUNC(SYSDATE),P_VENC, P_MAT, P_QTD);
P_LOTE := V_NUM;
end;
Meu código Java:
public void chamarfuncao(String DataVencimento, String Material,
String Peso){
//Conversão de variáveis para o padrão da função do Oracle
int MaterialInt = Integer.parseInt(Material);
String PesoFormat = Peso.substring(0, 2) + "." + Peso.substring(4, 6);
double PesoDouble = Double.parseDouble(PesoFormat);
try {
CallableStatement chamaFuncao = conexao.prepareCall("{call RASTREABILIDADE.P_GERA_LOTE (?, ?, ?, ?)}");
chamaFuncao.registerOutParameter(1, Types.DOUBLE);
chamaFuncao.setString(2, DataVencimento.substring(0, 1) +
DataVencimento.substring(3, 4) +
DataVencimento.substring(8, 9));
chamaFuncao.setInt(3, MaterialInt);
chamaFuncao.setDouble(4, PesoDouble);
chamaFuncao.executeUpdate();
//Resgata o valor de retorno da função e converte para String para setar o jTextField
double lote = chamaFuncao.getDouble(1);
Main.jTextFieldLote.setText(String.valueOf(lote));
// chamaFuncao.close();
// conexao.close();
}catch(SQLException sqle){
JOptionPane.showMessageDialog(null,
"Impossível conectar com o Banco de Dados! Código do erro: " + sqle.toString(),
"Erro!",
JOptionPane.ERROR_MESSAGE);
}
}
Já me virei de todo jeito e nada desse negócio funcionar. E para ajudar preciso entregar o projeto hoje até as 16:00 hrs e só falta isso.
O cara, o primeiro parâmetro da procedure não é uma data? E você tá tentando passar como uma string concatenada com barras?
Você não tem como dar um desc nessa procedure? Você tem o sql/plus instalado?
Se tiver digita lá
desc GERA_LOTE e veja os tipos dos parâmetros.
Haaaaaaaaaaaaaaaaaaaaa vou comer teu fígado !!!
Olhe só:
procedure P_GERA_LOTE(P_LOTE out number, P_VENC date, P_MAT number, P_QTD number)
O segundo parâmetro é uma data, então você deverá utilizar um chamaFuncao.setDate(), captou??
Tipos iguais senão vai dar crépe.
Olha eu fiz um teste no banco e quando eu passo o parametro data como ddmmaa tudo sem barra funciona então eu tentei passar igual via Java.
Tentei usar simpledateformat para formatar a data pro Oracle mas dá erro também. Vc sabe alguma forma de formatar o campo para transformar em data no formato que o Oracle aceite?
Eu recebo a data de um jTextField digitado pelo usuário.
Já havia tentado utilizar o setDate() e dá um erro de
Cannot find symbol
Se você não alterar o formato do banco oracle, o formato default é dd-mon-yy mas você não precisa mandar assim pra procedure.
É só você formatar antes de mandar.
SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yy");
Timestamp ts = new Timestamp(sdf.parse(<campo da tela no formato dd/MM/yy>).getTime());
Use o setTimestamp:
chamaFuncao.setTimestamp(ts);
Tente isso…
Ops, tem outro exemplo também:
chamaFuncao.setDate(<indice>, new Date(new SimpleDateFormat("dd/MM/yyyy").parse(<campo da tela no formato dd/mm/yyyy>).getTime()));
Não se esqueça que a classe Date, nesse caso, é a java.sql.Date.
Cara implementei o seu exemplo da seguinte forma:
public void chamarfuncao(String DataVencimento, String Material,
String Peso){
//Conversão de variáveis para o padrão da função do Oracle
int MaterialInt = Integer.parseInt(Material);
String PesoFormat = Peso.substring(0, 2) + "." + Peso.substring(4, 6);
double PesoDouble = Double.parseDouble(PesoFormat);
SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yy");
try {
setTs(new Timestamp(sdf.parse(Main.jTextFieldDataVencimento.getText()).getTime()));
} catch (java.text.ParseException pe) {
JOptionPane.showMessageDialog(null,
"Erro de conversão de datas! Erro: " + pe.toString(),
"Erro!",
JOptionPane.ERROR_MESSAGE);
}
try {
CallableStatement chamaFuncao = conexao.prepareCall(
"{call RASTREABILIDADE.P_GERA_LOTE (?, ?, ?, ?)}");
chamaFuncao.registerOutParameter(1, Types.DOUBLE);
chamaFuncao.setTimestamp(2, getTs());
chamaFuncao.setInt(3, MaterialInt);
chamaFuncao.setDouble(4, PesoDouble);
chamaFuncao.executeUpdate();
//Resgata o valor de retorno da função e converte para String para setar o jTextField
double lote = chamaFuncao.getDouble(1);
Main.jTextFieldLote.setText(String.valueOf(lote));
// chamaFuncao.close();
// conexao.close();
}catch(SQLException sqle){
JOptionPane.showMessageDialog(null,
"Impossível conectar com o Banco de Dados! Código do erro: " + sqle.toString(),
"Erro!",
JOptionPane.ERROR_MESSAGE);
}
}
Agora que fiz o teste da o erro de:
ORA-06502: erro de conversão de caractere em número numérico ou de valor
ORA-6512: em line 1
Tentei também implementar conforme o segundo exemplo e dá o mesmo erro.
O que lhe posso dizer agora é sobre o erro:
ORA-06502 PL/SQL: numeric or value errorstringCause: An arithmetic, numeric, string, conversion, or constraint error occurred. For example, this error occurs if an attempt is made to assign the value NULL to a variable declared NOT NULL, or if an attempt is made to assign an integer larger than 99 to a variable declared NUMBER(2).
Action: Change the data, how it is manipulated, or how it is declared so that values do not violate constraints
Para tirar uma dúvida, coloque valores fixos pra ver se realmente é esse parâmetro data que está causando erro.
Cara resolvi o problema, só que agora aconteceu outro. Recebo uma String no formato “nnn,nnn”, tento converter para float (tentei double também) e dá o seguinte erro:
Exception in thread "AWT-EventQueue-0" java.lang.NumberFormatException: For input string: "003,841"
at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1224)
Minha dúvida é se eu posso fazer esse tipo de conversão, pois no Oracle ele recebe esse campo como Number.
Faço a conversão dessa forma:
float PesoDouble = Float.parseFloat(Peso);
Valeu, cara a string vinha com uma “,” foi só trocar por “.” que resolveu.
Obrigado a todos pela ajuda. Valeu mesmo.
Você só vai conseguir formatar se for 003.841 ao invés de 003,841.
Cara mais uma dúvida:
No código abaixo:
int lote = chamaFuncao.getInt(1);
Main.jTextFieldLote.setText(String.valueOf(lote));
Eu pego o retorno como Int, isso dá erro de iverflown numérico. Se eu coloco float vem um número em notação cientifica. Como eu faço para retornar sem ser em notação científica?
No banco direto retorna: 200600000004
No meu app Java retorna: 2.00599994E11.
Não to entendendo o porque disso tudo.
Você tem que ver que existem tipos numéricos em java que são limitados no tamanho. Esse valor gigantesco aí é demais para um int.
Tente usar o BigDecimal.
Valeu cara, muito 10 a dica. Agora tá funcionando direito.