Executar Expressões Matemáticas

bom dia,

Estou precisando montar uma estrutura para resolver a seguinte situação:

O usuário poderá informar uma expressão matemática do tipo: ( a + b ) / c, onde a, b e c serão campos da base de dados. A minha estrutura precisa ser capaz de ler essa expressão (ou outra que o usuário informar) interpretar, validar e executar retornando o resultado do cálculo ao usuário ou algum erro caso ocorra.

Não sei se existe algo que execute esse tipo de operação.

Gostaria que me indicassem qual caminho devo tomar para resolver esse problema, baseado na experiência de cada um, e/ou se existe algo que eu possa usar como referência.

[]s

be happy!

http://www.guj.com.br/posts/preList/102119/551141.java#551141

obrigado daniels, foi bastante esclarecedor… no entanto fiquei com uma dúvida no meu caso o usuário vai informar algo do tipo:

( CAMPO1 + CAMPO2 ) / CAMPO3

onde campo1, 2 e 3 são string’s que representam um campo no banco de dados… então depois de interpretado farei um calculo com algo parecido com isso:

( rs.getDouble( "CAMPO1" ) + rs.getDouble( "CAMPO2" ) ) / rs.getDouble( "CAMPO3" )

será que esse exemplos suportam esse tipo de operação? caso não suportem, tem alguma idéia de como posso fazer?

cheguei a pensar em percorrer a string e retirar dela os parâmetros que me interessam e calcular ou retornar algum erro caso seja inválido; mas não sei se é a melhor opção.

[]s

Faz algo assim:

[code] String campo1 = (rs.getDouble( “CAMPO1” )).toString();
String campo2 = (rs.getDouble( “CAMPO2” )).toString();
String campo3 = (rs.getDouble( “CAMPO3” )).toString();

String formula = “(” + campo1 + “+” + campo2 + “) /” + campo3;[/code]

Ai tens a expressão inteira na string formula. Agora é só usar o GroovyShell.

Obs.: Não testei as conversões pra String ali, mas acho que funciona.

O meu problema está justamente no fato de que o esta rotina vai ser feita para que eu não faca diretamente o acesso ao ResultSet para obter o valor de colunas eu vou passar apenas a expressão e, dentro da rotina vou identificar as variáveis recuperar os dados do banco e efetuar a operação neste momento poderei usar os exemplos que mandou… mas, agora, não sei como resolver a parte em que identifico as variáveis e recupero os dados do resultset…

não sei se fui claro…

tem alguma sugestão?

Esse tópico não é nem um pouco fácil. Dê uma estudada na forma como os compiladores trabalham.

Se você puder implementar um analisador para essa gramática, te ajuda:
Expr1 -> ["-"] Expr2
Expr2 -> Expr3 [("+" | "-") Expr2]
Expr3 -> Expr4 [("*" | "/") Expr3]
Expr4 -> "(" Expr1 ")" | Num | var

[quote=eberson_oliveira]O meu problema está justamente no fato de que o esta rotina vai ser feita para que eu não faca diretamente o acesso ao ResultSet para obter o valor de colunas eu vou passar apenas a expressão e, dentro da rotina vou identificar as variáveis recuperar os dados do banco e efetuar a operação neste momento poderei usar os exemplos que mandou… mas, agora, não sei como resolver a parte em que identifico as variáveis e recupero os dados do resultset…

não sei se fui claro…

tem alguma sugestão?[/quote]

Você não está conseguindo pegar os dados do banco. É isso?

Olá,

use groovyshell. É bem simples de usar.
http://www.guj.com.br/posts/list/102119.java

[]´s

[quote=victorwss]Esse tópico não é nem um pouco fácil. Dê uma estudada na forma como os compiladores trabalham.

Se você puder implementar um analisador para essa gramática, te ajuda:
Expr1 -> ["-"] Expr2
Expr2 -> Expr3 [("+" | "-") Expr2]
Expr3 -> Expr4 [("*" | "/") Expr3]
Expr4 -> "(" Expr1 ")" | Num | var[/quote]

:?:

Desculpe… mas não pude entender a gramatica citada… pode detalhar, por favor ou indicar um local onde possa consultar sobre isso?

[]s

[quote=Daniels][quote=eberson_oliveira]O meu problema está justamente no fato de que o esta rotina vai ser feita para que eu não faca diretamente o acesso ao ResultSet para obter o valor de colunas eu vou passar apenas a expressão e, dentro da rotina vou identificar as variáveis recuperar os dados do banco e efetuar a operação neste momento poderei usar os exemplos que mandou… mas, agora, não sei como resolver a parte em que identifico as variáveis e recupero os dados do resultset…

não sei se fui claro…

tem alguma sugestão?[/quote]

Você não está conseguindo pegar os dados do banco. É isso?[/quote]

entao… o problema não está em obter os valores do banco e sim em identificar na minha expressao (string) os valores que representam os nomes das colunas do banco de dados… o que quero fazer é descobrir na expressao quais sao os campos verificar se eles realmente existem e, caso existam, recuperar seus valores para poder efetuar a expressao

[quote=rodrigo_gomes]Olá,

use groovyshell. É bem simples de usar.
http://www.guj.com.br/posts/list/102119.java

[]´s[/quote]

ola rodrigo,

pelo que pude ver ele é bastante simples… no entanto tenho a dificuldade de possuir na expressão valores que representam colunas do banco… no momento em que eu for ler a expressão deverei localizar os campos buscar seus valores para depois poder continuar com a execução expressão…

Olá,

Você pode ter algo como:

   String expressao = "campo1 ** campo2+ campo3 - (campo4 *campoN)";
   binding = new Binding();
   shell = new GroovyShell(binding);
   binding.setVariable("campo1", VALORDOCAMPO1); //pode ser BigDecimal
   binding.setVariable("campo2", VALORDOCAMPO2); 
             ....

Você pode adicionar a expressão que você quiser, e se não for nenhum problema para você, pode colocar todas as colunas da tabela para não ter que ficar procurando qual campo o usuário digitou. Assim, as que ele não usar simplesmente não vão interferir em nada.

Agora se sua tabela for monstruosa, e se isso for executado alguns centenas de vezes por minuto aí você pode ter problema.

Rodrigo,

A minha tabela é monstruosa… na realidade é um grupo de monstros… :cry:

São por volta de 400 tabelas onde os campos variam de 5 a 30… por isso fica inviável manter todos os nomes…
a expressão não é fixa… quero permitir que qualquer expressão seja informada contendo qualquer campo…

Por isso acho que vou precisar analisar a expressão antes de mandar executar…

O seu exemplo é bastante claro, no entanto eu não vou saber quais colunas foram informadas… portanto terei que descobrir quais colunas foram informadas e seus valores em tempo de execução…

[]

E como fica o relacionamento entre as tabelas? Dá a impressão que é melhor você deixar entrar uma expressão qualquer em SQL.

thingol,

a minha estrutura atual recebe um select e a partir dele monta um resultset… esta instrução select fica armazenada na estrutura… de forma que os relacionamentos ficarão a cargo de quem for fornecer o select… o que eu quero fazer é permitir que cálculos possam ser feitos através de colunas da base de dados com um simples comando, por exemplo:

objeto.getValor( "( campo1 + campo2 ) / campo1 * 100" ); // esse trecho é apenas para exemplificar o quanto eu quero simplificar

assim poderei obter valores calculados sem precisar acessar a base de dados diretamente, nem usar resultset nem nada…

não sei se estou viajando… mas na minha cabeça essa rotina facilitaria muito o meu trabalho

Olá eberson_oliveira,

Cara, não entendi muito o que vc quer, mas vou colocar o que eu interpretei, aí vai:

Supondo que os campos A B e C sejam de tabelas diferentes, e vc quer o calculo ( a + b ) / c, se pode fazer isso no próprio select, segue abaixo um exemplo:

Select a.A, b.B, c.C, ((a=b)/c) as Calculo from A as a, B as b, C as c;

Nesse caso, ele vai voltar como consulta as colunas A, B, C e Calculo, ai basta capturar o resultado da coluna Calculo.

Bom, foi mais ou menos que eu entendi o que vc queria, se não for, tente esclarecer melhor, ficou um pouco confuso, blz …

Generosamente,

Frid

Opa,

Coloquei errado, faltou coisa, substitua esse:

Select a.A, b.B, c.C, ((a=b)/c) as Calculo from A as a, B as b, C as c;

por esse, ficaria com uma melhor sintaxe para vc entender e está corrigido que eu tinha feito errado:

“Select a.campoA, b.campoB, c.campoC, ((a.campoA + b.campoB)/c.campoC) as Calculo from A as a, B as b, C as c;”

A resposta sai como String mas talves algum metodo te ajude.

Ps: De uma olhada em expressao matematica posfixada e infixada. Tentei tratar o maximo de erros.

Copie e cole em uma IDE. Compile e Execute para ver as respostas

http://www.faculdadepuc.xpg.com.br/expressaomatematica

[quote=frid]Olá eberson_oliveira,

Cara, não entendi muito o que vc quer, mas vou colocar o que eu interpretei, aí vai:

Supondo que os campos A B e C sejam de tabelas diferentes, e vc quer o calculo ( a + b ) / c, se pode fazer isso no próprio select, segue abaixo um exemplo:

Select a.A, b.B, c.C, ((a=b)/c) as Calculo from A as a, B as b, C as c;

Nesse caso, ele vai voltar como consulta as colunas A, B, C e Calculo, ai basta capturar o resultado da coluna Calculo.

Bom, foi mais ou menos que eu entendi o que vc queria, se não for, tente esclarecer melhor, ficou um pouco confuso, blz …

Generosamente,

Frid[/quote]

Olá frid,

O problema está no fato de eu ter que efetuar esse select varias vezes por minuto, a estrutura do banco não é a mais adequada e o select “correto”, por causa da estrutura do banco, acaba sendo muito custoso de forma que eu preciso trazer o mínimo de campos possível para não prejudicar a minha rede nem minha base. Estruturar o banco está fora de cogitação aqui na empresa… além disso alguns cálculos só poderiam ser feitos em procedures o que agrava o problema da estrutura do banco… por isso preciso de uma solução que esteja fora do select.
O resultset que eu citei é na realidade um repositório de dados que implementa um resultset (não perguntem pq isso… vocês, com certeza, não vão querer saber a resposta…) mas trabalha desconectado o que acaba pesando um pouco menos na hora de trabalhar com os valores…
Enfim a solução mais correta, no meu ponto de vista, é montar alguma estrutura no padrão da que estou perguntado a vocês… pq eu preciso trabalhar com o select mais simples possível…

Espero que tenha sido claro na minha explicação…

[]

obrigado gpd38, vou dar uma olhada e dou um retorno assim que possível… Pensei em implementar algo como uma estrutura posfixada, no entanto preciso de algo que qualquer um possa entender e que seja bastante intuitivo (até para os mais leigos), já que nem todos conhecem este tipo de expressão.