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 のメタデータ分析に使用していましたが、今まで評価を行う必要はありませんでした。

ここに私の2セントがあります。演算子の優先順位は、部分的に JSqlParsers グラマー内で偽造されます。(@jbaliuka: あなたのフォークを調べたところ、古いバージョンの JSqlParser に基づいていたと思います。sourceforge での最新の開発 (2010?) では、加算と乗算に演算子の優先順位が導入されました。追加の分析式の解析により、私のフォークでいくつかの変更がトリガーされました。 . 試してみていただければ幸いです。)

これは、JSqlParser V0.8.8 を使用した加算と乗算の非常に単純な式評価器です。最初の JSqlParser は、JSqlParser のビジター構造を使用してトラバースする、このツリーから継承されたオブジェクト階層から、解析ツリーまたはより正確には a を提供します。確かに、完全なバージョンを作成するには、まだ多くの作業を行う必要があります。これは概念の証明です。私の例では、括弧の優先順位さえも正しく行われていることを知るのは興味深いことでした。

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 フォークの 1 つも自分でメンテナンスしています。このフォークは演算子の優先順位を無視します。

于 2014-02-14T22:09:03.913 に答える