五星杀手 發表於 2025-5-24 15:55:00

SQL解析工具JSQLParser

<h2 id="一引言">一、引言</h2>
<p>JSQLParser(GitHub:https://github.com/JSQLParser/JSqlParser)是一个Java语言的SQL语句解析工具,功能十分强大,它可以将SQL语句解析成为Java类的层次结构,还支持改写SQL,常见的持久层框架MyBatis-Plus就采用它作为SQL解析工具来实现某些功能。</p>
<h2 id="二jsqlparser常见类">二、JSQLParser常见类</h2>
<h3 id="21-class-diagram">2.1 Class Diagram</h3>
<p><img src="https://img2024.cnblogs.com/blog/3570203/202505/3570203-20250523222936149-646803051.png" alt="image" loading="lazy"></p>

<h3 id="22-statement">2.2 Statement</h3>
<p>可以理解为能够表示任意一种SQL语句的对象,Select、Update、Delete、Insert都是它的子类,例如以下用法:</p>
<pre><code class="language-java">Statement statement = JsqlParserGlobal.parse(sql);

if (statement instanceof Insert) {
    this.processInsert((Insert) statement, index, sql, obj);
} else if (statement instanceof Select) {
    this.processSelect((Select) statement, index, sql, obj);
} else if (statement instanceof Update) {
    this.processUpdate((Update) statement, index, sql, obj);
} else if (statement instanceof Delete) {
    this.processDelete((Delete) statement, index, sql, obj);
}
</code></pre>
<h3 id="23-expression">2.3 Expression</h3>
<p>是JSqlParser库中的一个核心接口,是用于表示SQL语句中的各种表达式的基类接口,通过调用对象的<code>.toString()</code>方法,就能看到具体的语句结构。</p>
<p>例如:</p>
<ol>
<li>基本值
<ul>
<li><code>LongValue</code>(整数值)、<code>StringValue</code>(字符串值)、<code>DoubleValue</code>(浮点数值)等。</li>
</ul>
</li>
<li>列引用
<ul>
<li><code>Column</code>(表示列名,如 <code>column_name</code> 或 <code>table.column</code>)。</li>
</ul>
</li>
<li>运算符
<ul>
<li><code>Addition</code>(<code>+</code>)、<code>Subtraction</code>(<code>-</code>)、<code>Multiplication</code>(<code>*</code>)、<code>Division</code>(<code>/</code>)等。</li>
</ul>
</li>
<li>函数调用
<ul>
<li><code>Function</code>(如 <code>COUNT(*)</code>、<code>SUBSTRING(str, 1, 2)</code>)。</li>
</ul>
</li>
<li>条件表达式
<ul>
<li><code>EqualsTo</code>(<code>=</code>)、<code>NotEqualsTo</code>(<code>&lt;&gt;</code> 或 <code>!=</code>)、<code>GreaterThan</code>(<code>&gt;</code>)、<code>LikeExpression</code>(<code>LIKE</code>)等。</li>
</ul>
</li>
<li>逻辑表达式(BinaryExpression)
<ul>
<li><code>AndExpression</code>(<code>AND</code>)、<code>OrExpression</code>(<code>OR</code>)、<code>NotExpression</code>(<code>NOT</code>)。</li>
</ul>
</li>
<li>子查询
<ul>
<li><code>SubSelect</code>(如 <code>(SELECT ...)</code>)。</li>
</ul>
</li>
<li>Case 表达式
<ul>
<li><code>CaseExpression</code>(<code>CASE WHEN ... THEN ... END</code>)。</li>
</ul>
</li>
<li>其他复杂表达式
<ul>
<li><code>CastExpression</code>(<code>CAST(... AS ...)</code>)、<code>IntervalExpression</code>(时间间隔)等。</li>
</ul>
</li>
</ol>
<h3 id="24-select">2.4 Select</h3>
<p>用于表示查询SQL语句,有三个常见子类:PlainSelect,ParenthesedSelect,SetOperationList</p>
<h3 id="25-update">2.5 Update</h3>
<p>用于表示更新的SQL语句</p>
<p>获得对应表</p>
<pre><code class="language-java">Table table = update.getTable();
</code></pre>
<p>获得要更新的值</p>
<pre><code class="language-java">List&lt;UpdateSet&gt; sets = update.getUpdateSets();
</code></pre>
<p>获取where条件</p>
<pre><code class="language-java">Expression expression = update.getWhere()
</code></pre>
<h3 id="26-delete">2.6 Delete</h3>
<p>用于表示删除的SQL语句</p>
<p>获得对应表</p>
<pre><code class="language-java">Table table = delete.getTable();
</code></pre>
<p>获取where条件</p>
<pre><code class="language-java">Expression expression = delete.getWhere()
</code></pre>
<h3 id="27-insert">2.7 Insert</h3>
<p>用于表示添加SQL语句,有以下几种常见方法</p>
<p>获取添加的列</p>
<pre><code class="language-java">List&lt;Column&gt; columns = insert.getColumns();
</code></pre>
<p>获取添加的值</p>
<pre><code class="language-java">Values values = insert.getValues();
</code></pre>
<p>获取添加时冲突进行更新的结构</p>
<pre><code class="language-sql">INSERT INTO ... VALUES ...ON DUPLICATE KEY UPDATE ...
</code></pre>
<pre><code class="language-java">List&lt;UpdateSet&gt; duplicateUpdateColumns = insert.getDuplicateUpdateSets();
</code></pre>
<p>insert select的结构,获取select</p>
<pre><code class="language-sql">INSERT ... SELECT ...
</code></pre>
<pre><code class="language-java">Select select = insert.getSelect();
</code></pre>
<h3 id="28-plainselect">2.8 PlainSelect</h3>
<p>用于表示最常规的那种查询结构,例如:</p>
<pre><code class="language-sql">select...from...join...where...
</code></pre>
<p>获取select后面的结构</p>
<pre><code class="language-java">List&lt;SelectItem&lt;?&gt;&gt; selectItems = plainSelect.getSelectItems();
</code></pre>
<p>获取select语句的where结构</p>
<pre><code class="language-java">Expression where = plainSelect.getWhere();
</code></pre>
<p>获取查询的from后的结构(表,子查询等)</p>
<pre><code class="language-java">FromItem fromItem = plainSelect.getFromItem();
</code></pre>
<p>存在连接查询时,获取连接查询(left/right/inner)join后的结构</p>
<pre><code class="language-java">List&lt;Join&gt; joins = plainSelect.getJoins();
</code></pre>
<h3 id="29-setoperationlist">2.9 SetOperationList</h3>
<p>用于表示多个select语句通过<code>union</code>,<code>union all</code>连接在一起的联合查询SQL对象</p>
<pre><code class="language-sql">select...from...
union all
select...from...
union all
select...from...
</code></pre>
<p>将语句拆分,获取构成它的若干select</p>
<pre><code class="language-java">SetOperationList operationList = (SetOperationList) selectBody;
List&lt;Select&gt; selectBodyList = operationList.getSelects();
</code></pre>
<h3 id="210-parenthesedselect">2.10 ParenthesedSelect</h3>
<p>用于表示子查询,被小括号包裹的一个查询结构,例如:</p>
<pre><code class="language-sql">(select....from...) as t
</code></pre>
<p>“去括号”,得到一个PlainSelect</p>
<pre><code class="language-java">ParenthesedSelect parenthesedSelect = (ParenthesedSelect) selectBody;
Select select = parenthesedSelect.getSelect();
</code></pre>
<h3 id="211-fromitem">2.11 FromItem</h3>
<p>接口,<code>from</code>后面的SQL结构,ParenthesedSelect,ParenthesedFromItem,Table都是它的实现</p>
<pre><code class="language-java">FromItem fromItem = plainSelect.getFromItem();

if (fromItem instanceof Table) {
   
}
else if (fromItem instanceof ParenthesedSelect) {
   
}
else if (fromItem instanceof ParenthesedFromItem) {
   
}
</code></pre>
<h3 id="212-table">2.12 Table</h3>
<p>用于表示SQL中的表</p>
<h3 id="213-parenthesedfromitem">2.13 ParenthesedFromItem</h3>
<p>小括号包裹的可被查询的结构,但不是子查询,不常用,例如小括号包裹的join:</p>
<pre><code class="language-sql">(tab1 join tab2)
</code></pre>
<h3 id="214-selectitem">2.14 SelectItem</h3>
<p>用于表示select语句中,select和from之间的部分,例如:</p>
<pre><code class="language-sql">select
    fun(1, 2) as a,
    (select x from ...) as b,
    name as c,
    exists (...) AS d
from t
</code></pre>
<pre><code class="language-java">List&lt;SelectItem&lt;?&gt;&gt; selectItems = plainSelect.getSelectItems();

selectItems.forEach(selectItem -&gt; {
    Expression expression = selectItem.getExpression();

    if (expression instanceof Select) {
      
    }
    else if (expression instanceof Function) {

    }
    else if (expression instanceof ExistsExpression) {

    }
});
</code></pre>
<h3 id="215-binaryexpression">2.15 BinaryExpression</h3>
<p>泛指比较符号:<code>and</code> <code>or</code> <code>=</code> <code>&gt;=</code> <code>=&lt;</code>,这种结构左右连接着其他结构。EqualsTo,OrExpression,AndExpression都是它的子类。</p>
<p>获取左右两侧的结构:</p>
<pre><code class="language-java">BinaryExpression expression = (BinaryExpression) obj;
Expression left = expression.getLeftExpression();
Expression right = expression.getRightExpression();
</code></pre>
<h3 id="216-inexpression">2.16 InExpression</h3>
<pre><code class="language-sql">x in (...)
</code></pre>
<p>获取右侧的结构,可能是子查询或<code>(*,*,*...)</code>:</p>
<pre><code class="language-java">InExpression expression = (InExpression) obk;
Expression inExpression = expression.getRightExpression();
</code></pre>
<h3 id="217-existsexpression">2.17 ExistsExpression</h3>
<pre><code class="language-sql">exists (...)
</code></pre>
<p>获取右侧结构</p>
<pre><code class="language-java">ExistsExpression expression = (ExistsExpression) obj;
Expression e = expression.getRightExpression() ;
</code></pre>
<h3 id="218-notexpression">2.18 NotExpression</h3>
<p>not,与其他的配合使用,例如:</p>
<pre><code class="language-sql">not in (...)

not exists (...)
</code></pre>
<p>获取<code>not</code>后面的结构,会提取出<code>in</code> <code>exists</code>等结构</p>
<pre><code class="language-java">NotExpression expression = (NotExpression) obj;
Expression e = expression.getExpression();
</code></pre>
<h3 id="219-parenthesis">2.19 Parenthesis</h3>
<p>代表小括号<code>()</code>括起来的结构</p>
<pre><code class="language-sql">(...)
</code></pre>
<p>去括号,拿到括号中的结构:</p>
<pre><code class="language-java">Parenthesis expression = (Parenthesis) obj;
Expression e = expression.getExpression();
</code></pre>
<h3 id="220-function">2.20 Function</h3>
<p>函数结构,通常会获取参数,对参数进行操作</p>
<pre><code class="language-sql">fun()
</code></pre>
<pre><code class="language-java">ExpressionList&lt;?&gt; parameters = function.getParameters();
if (parameters != null) {
    parameters.forEach(expression -&gt; {
      if (expression instanceof Select) {
            
      }
      else if (expression instanceof Function) {
            
      }
    });
}
</code></pre>
<h3 id="221-equalsto">2.21 EqualsTo</h3>
<pre><code class="language-sql">=
</code></pre>
<h3 id="222-orexpression">2.22 OrExpression</h3>
<pre><code class="language-sql">or
</code></pre>
<h3 id="223-andexpression">2.23 AndExpression</h3>
<pre><code class="language-sql">and
</code></pre>
<h3 id="224-join">2.24 Join</h3>
<p>SQL中连接查询的join结构,从Select中获得。</p>
<p>获取join后的结构,一般可能是表也可能是子查询</p>
<pre><code class="language-java">FromItem joinItem = join.getRightItem();
</code></pre>
<p>判断是否为隐式内连接</p>
<pre><code class="language-java">join.isSimple();
</code></pre>
<p>判断是内/左/右连接</p>
<pre><code class="language-java">join.isRight();
join.isInner();
join.isLeft();
</code></pre>
<p>获取join的on条件</p>
<pre><code class="language-java">Collection&lt;Expression&gt; originOnExpressions = join.getOnExpressions();
</code></pre>
<p>改写join的on条件</p>
<pre><code class="language-java">join.setOnExpressions(onExpressions);
</code></pre>
<h3 id="225-column">2.25 Column</h3>
<p>用于表示SQL中的字段对象,例如从一个Insert对象获取SQL要添加的全部字段:name,age,tenant_id</p>
<pre><code class="language-sql">INSERT INTO t_user (name, age, tenant_id) VALUES ('liming', 15), ('zhaoying', 16)
</code></pre>
<pre><code class="language-java">List&lt;Column&gt; columns = insert.getColumns();
</code></pre>
<h3 id="226-updateset">2.26 UpdateSet</h3>
<p>UpdateSet是一种类似<code>xx = xx, ...</code>的结构,出现在update的<code>set</code>后面</p>
<pre><code class="language-sql">update user set username = 5 where id = 1
</code></pre>
<pre><code class="language-java">List&lt;UpdateSet&gt; sets = update.getUpdateSets();
</code></pre>
<p>也能在insert语句处理添加的数据冲突的情况时,出现在<code>ON DUPLICATE KEY UPDATE</code>后面</p>
<pre><code class="language-sql">INSERT INTO table_name (col1, col2) VALUES (val1, val2)
ON DUPLICATE KEY UPDATE col1 = val3, col2 = col4 + 1;
</code></pre>
<pre><code class="language-java">List&lt;UpdateSet&gt; duplicateUpdateColumns = insert.getDuplicateUpdateSets();
</code></pre>
<h3 id="227-expressionlist">2.27 ExpressionList</h3>
<p>Expression列表,本质上是<code>List&lt;Expression&gt;</code>,当insert语句<code>values</code>后面批量跟了多组值,就能得到这种结构。</p>
<pre><code class="language-sql">('liming', 15), ('zhaoying', 16)
</code></pre>
<pre><code class="language-java">Values values = insert.getValues();
ExpressionList&lt;Expression&gt; expressions = (ExpressionList&lt;Expression&gt;) values.getExpressions();
</code></pre>
<h3 id="228-parenthesedexpressionlist">2.28 ParenthesedExpressionList</h3>
<p>继承自ExpressionList,本质上也是<code>List&lt;Expression&gt;</code>,一种带着括号的Expression结构,例如获取insert语句<code>values</code>后面的值就能得到这种结构</p>
<pre><code class="language-sql">('liming', 15)
</code></pre>
<pre><code class="language-java">Values values = insert.getValues();
ExpressionList&lt;Expression&gt; expressions = (ExpressionList&lt;Expression&gt;) values.getExpressions();
if (expressions instanceof ParenthesedExpressionList) {
    // ParenthesedExpressionList
} else {
    // ExpressionList
}
</code></pre>
<blockquote>
<p>本文首发:https://blog.liuzijian.com/post/jsqlparser.html</p>
</blockquote>
<h2 id="附类路径">附:类路径</h2>
<p>net.sf.jsqlparser.statement.Statement<br>
net.sf.jsqlparser.statement.select.Select<br>
net.sf.jsqlparser.statement.update.Update<br>
net.sf.jsqlparser.statement.delete.Delete<br>
net.sf.jsqlparser.statement.insert.Insert<br>
net.sf.jsqlparser.schema.Table<br>
net.sf.jsqlparser.expression.Expression<br>
net.sf.jsqlparser.statement.select.ParenthesedSelect<br>
net.sf.jsqlparser.statement.select.SetOperationList<br>
net.sf.jsqlparser.statement.select.SelectItem<br>
net.sf.jsqlparser.expression.BinaryExpression<br>
net.sf.jsqlparser.expression.operators.relational.InExpression<br>
net.sf.jsqlparser.expression.operators.relational.ExistsExpression<br>
net.sf.jsqlparser.expression.NotExpression<br>
net.sf.jsqlparser.expression.Parenthesis<br>
net.sf.jsqlparser.statement.select.ParenthesedFromItem<br>
net.sf.jsqlparser.statement.select.FromItem<br>
net.sf.jsqlparser.expression.Function<br>
net.sf.jsqlparser.expression.operators.relational.EqualsTo<br>
net.sf.jsqlparser.expression.operators.conditional.OrExpression<br>
net.sf.jsqlparser.expression.operators.conditional.AndExpression<br>
net.sf.jsqlparser.statement.select.Join<br>
net.sf.jsqlparser.schema.Column<br>
net.sf.jsqlparser.expression.operators.relational.ExpressionList<br>
net.sf.jsqlparser.expression.operators.relational.ParenthesedExpressionList</p><br><br>
来源:https://www.cnblogs.com/changelzj/p/18893870
頁: [1]
查看完整版本: SQL解析工具JSQLParser