0

我正在尝试使用 JSQLParser 开发一个 SQL 查询评估器,我真的很困惑如何决定评估顺序,比如如果我有以下形式的查询

Select * 
From A,B,C 
Where A.id=B.id 
  And B.id=C.id 
  And A.id=C.id

问题是如何从中构建解析树或表达式树。我需要一些指针来解决这个问题。另外补充一点,我正在考虑使用几个堆栈来解决这个问题,即一个运算符堆栈和一个操作数堆栈。我需要确认这是否是理解这个问题的一种可能方式?

4

2 回答 2

2

这是一个有趣的问题。那么我可以介绍另一个 JSqlParser 的分支(https://github.com/JSQLParser/JSqlParser)。到目前为止,我将它用于 SQL 的元数据分析,直到现在还没有进行评估。

现在在这里我的两分钱。运算符优先级部分是在 JSqlParsers 语法中伪造的。(@jbaliuka:我查看了您的 fork,我认为它基于旧版本的 JSqlParser。sourceforge(2010 年?)的最新发展为加法和乘法引入了运算符优先级。另外,您的分析表达式解析在我的 fork 中触发了一些更改.如果你能试一试就好了。)

这是一个非常简单的表达式求值器,用于使用 JSqlParser V0.8.8 进行加法和乘法运算。首先,JSqlParser 从这个树继承的对象层次结构中传递一个解析树或更精确的 a,我使用 JSqlParser 的访问者结构遍历它。当然,对于一个完整的版本,还有很多工作要做。这更多是概念的证明。对我来说有趣的是,对于我的示例,即使是括号优先级也是正确的。

import java.util.Stack;
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.LongValue;
import net.sf.jsqlparser.expression.operators.arithmetic.Addition;
import net.sf.jsqlparser.expression.operators.arithmetic.Multiplication;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.util.deparser.ExpressionDeParser;

public class SimpleEvaluateExpr {

    public static void main( String[] args ) throws JSQLParserException {
        //examples
        evaluate("4+5*6");
        evaluate("4*5+6");
        evaluate("4*(5+6)");
        evaluate("4*(5+6)*(2+3)");
    }

    static void evaluate(String expr) throws JSQLParserException {
        //here is the stack you mentioned ;)
        final Stack<Long> stack = new Stack<Long>();

        System.out.println("expr=" + expr);
        Expression parseExpression = CCJSqlParserUtil.parseExpression(expr);
        //Deparser traverses the complete expression hierarchy. It was mainly used
        //for SQL output but this is now done using toString but is always a useful
        //traversal tool.
        ExpressionDeParser deparser = new ExpressionDeParser() {
            @Override
            public void visit(Addition addition) {
                super.visit(addition); 

                long sum1 = stack.pop();
                long sum2 = stack.pop();

                stack.push(sum1 + sum2);
            }

            @Override
            public void visit(Multiplication multiplication) {
                super.visit(multiplication); 

                long fac1 = stack.pop();
                long fac2 = stack.pop();

                stack.push(fac1 * fac2);
            }

            @Override
            public void visit(LongValue longValue) {
                super.visit(longValue); 
                stack.push(longValue.getValue());
            }
        };
        StringBuilder b = new StringBuilder();
        deparser.setBuffer(b);
        parseExpression.accept(deparser);

        System.out.println(expr + " = " + stack.pop() );
    }
}

这是输出:

expr=4+5*6
4+5*6 = 34
expr=4*5+6
4*5+6 = 26
expr=4*(5+6)
4*(5+6) = 44
expr=4*(5+6)*(2+3)
4*(5+6)*(2+3) = 220

所以第一个示例表达式的解析树类似于:

  • 添加
    • 长值 (4)
    • 乘法
      • 长值(5)
      • 长值(6)

访问者一阶深度遍历。

于 2014-02-15T14:42:49.687 回答
0

运算符优先级通常由语法定义,访问者应该以定义的顺序递归地访问节点,应该可以使用普通递归来评估访问者实现中的表达式。堆栈方法也是正确的,但没有必要。
我不确定 jsqlparse 语法,它适用于 AST 转换,但我没有测试它进行评估。如果它不起作用,那么你将不得不自己修复它,因为这个库不再维护,我自己也维护了一个jsqlparser 分支,这个分支忽略了运算符优先级。

于 2014-02-14T22:09:03.913 回答