您当前的位置:首页 > 电脑百科 > 数据库 > 百科

SQL解析利器JSqlParser

时间:2023-04-21 13:56:01  来源:今日头条  作者:Esgoon

JSqlParser是一个与RDBMS无关的SQL语句解析器,支持多种方言,例如Oracle、SQL Server、MySQL、MariaDB、PostgreSQL、H2等。

JSqlParser将SQL语句转换为JAVA类的可遍历层次结构,还可以用于通过API从Java代码创建SQL语句。现在普遍使用的MyBatis-plus以及分页插件PageHelper都是借助JSqlParser实现SQL解析的。

JSqlParser源码主要包括以下几类对象:

  • expression:SQL构建相关类,比如Function、EqualsTo、AndExpression、InExpression等表达式用于构建SQL。
  • parser:SQL解析相关类,比如CCJSqlParserUtil、CCJSqlParserManager、抽象语法树对象等。
  • schema:主要存放数据库schema相关的类 ,比如Database、Table、Column等。
  • statement:封装了数据库操作对象,create、insert、delete、select、drop、alter、truncate等。
  • util:各种工具类、不同DB版本、SQL标准等处理类,如SelectUtils、DatabaseType等。

 

解析SQL

对于下列SQL语句:

SELECT name, age, score FROM user WHERE id=1;

转换为Java对象层次结构为:

 

解析SQL代码实例:

public static void parseSQL() {
    //Select语句样本
    String sql1 = "select t1.f1,t1.f2,t2.id,count(*) from table1 t1 left join table2 t2 right join (select * from table3) t3 where t1.id='10' or (t1.id between 1 and 3 and t1.id>'12') group by t.f1 order by t.f1 desc,tf2 asc limit 1,20";
    //Insert语句样本
    String sql2 = "insert into table(f1,f2) values (1,2)";
    //Create语句样本
    String sql3 = "CREATE TABLE `sys_user` (n" +
        "  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '编号',n" +
        "  `name` varchar(200) DEFAULT '' COMMENT '名称',n" +
        "  `age` tinyint(4) DEFAULT NULL COMMENT '年龄',n" +
        "  `create_by` varchar(64) DEFAULT '' COMMENT '创建者',n" +
        "  `create_time` datetime DEFAULT NULL COMMENT '创建时间',n" +
        "  `update_by` varchar(64) DEFAULT '' COMMENT '更新者',n" +
        "  `update_time` datetime DEFAULT NULL COMMENT '更新时间',n" +
        "  `remark` varchar(500) DEFAULT NULL COMMENT '备注',n" +
        "  PRIMARY KEY (`id`)n" +
        ") ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户表';";
    try {
        //处理Select语句
        Select select = (Select) CCJSqlParserUtil.parse(sql1);
        TablesNamesFinder tablesNamesFinder = new TablesNamesFinder();
        List<String> tableList = tablesNamesFinder.getTableList(select);
        // 获取到查询sql中的所有表名
        System.out.println("表名:" + tableList);
           
        //处理Insert语句
        Insert insert = (Insert) CCJSqlParserUtil.parse(sql2);
        System.out.println("插入的表" + insert.getTable());
        System.out.println("插入的列" + insert.getColumns());
        System.out.println("插入的值" + insert.getItemsList());
           
        //处理Create Table语句
        Statement statement = CCJSqlParserUtil.parse(sql3);
        if (statement instanceof CreateTable) {
            CreateTable createTable = ((CreateTable) statement);
            Table table = createTable.getTable();
            //通过columnDefinition进而可以获取列名、数据类型等
            List<ColumnDefinition> columnDefinitions = createTable.getColumnDefinitions();
            System.out.println(table);
            System.out.println(columnDefinitions);
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

输出如下:

表名:[table1, table2, table3]
插入的表table
插入的列[f1, f2]
插入的值(1, 2)
`sys_user`
[`id` bigint (20) NOT NULL AUTO_INCREMENT COMMENT '编号', `username` varchar (200) DEFAULT '' COMMENT '名称', `age` tinyint (4) DEFAULT NULL COMMENT '年龄', `create_by` varchar (64) DEFAULT '' COMMENT '创建者', `create_time` datetime DEFAULT NULL COMMENT '创建时间', `update_by` varchar (64) DEFAULT '' COMMENT '更新者', `update_time` datetime DEFAULT NULL COMMENT '更新时间', `remark` varchar (500) DEFAULT NULL COMMENT '备注']

 

创建SQL

/**
 * 创建SQL查询语句
 *
 * @throws JSQLParserException
 */
public static void createSQL() throws JSQLParserException {
  // 单表全量
  Table table = new Table("sys_user");
  //查询所有列
  Select select = SelectUtils.buildSelectFromTable(table);
  // SELECT * FROM sys_user
  System.out.println(select);

    // 指定列查询
    Select buildSelectFromTableAndExpressions = SelectUtils.buildSelectFromTableAndExpressions(new Table("test"), new Column("col1"), new Column("col2"));
    // SELECT col1, col2 FROM sys_user
    System.out.println(buildSelectFromTableAndExpressions);

    // WHERE =
    EqualsTo equalsTo = new EqualsTo(); // 等于表达式
    // 设置表达式左边值
    equalsTo.setLeftExpression(new Column(table, "user_id")); 
    // 设置表达式右边值
    equalsTo.setRightExpression(new StringValue("123456"));
    // 转换为更细化的Select对象
    PlAInSelect plainSelect = (PlainSelect) select.getSelectBody();
    plainSelect.setWhere(equalsTo);
    // SELECT * FROM sys_user WHERE sys_user.user_id = '123456'
    System.out.println(plainSelect);

    // WHERE  != <>
    NotEqualsTo notEqualsTo = new NotEqualsTo();
    notEqualsTo.setLeftExpression(new Column(table, "user_id")); // 设置表达式左边值
    notEqualsTo.setRightExpression(new StringValue("123456"));// 设置表达式右边值
    PlainSelect plainSelectNot = (PlainSelect) select.getSelectBody();
    plainSelectNot.setWhere(notEqualsTo);
    System.out.println(plainSelectNot);//  SELECT * FROM sys_user WHERE sys_user.user_id <> '123456'

    // 其他运算符, 参考上面代码添加表达式即可
    GreaterThan gt = new GreaterThan(); // ">"
    GreaterThanEquals geq = new GreaterThanEquals(); // ">="
    MinorThan mt = new MinorThan(); // "<"
    MinorThanEquals leq = new MinorThanEquals();// "<="
    IsNullExpression isNull = new IsNullExpression(); // "is null"
    isNull.setNot(true);// "is not null"
    LikeExpression nlike = new LikeExpression();
    nlike.setNot(true); // "not like"
    Between bt = new Between();
    bt.setNot(true);// "not between"

    // WHERE LIKE
    LikeExpression likeExpression = new LikeExpression(); // 创建Like表达式对象
    likeExpression.setLeftExpression(new Column("username")); // 表达式左边
    likeExpression.setRightExpression(new StringValue("张%")); // 右边表达式
    PlainSelect plainSelectLike = (PlainSelect) select.getSelectBody();
    plainSelectLike.setWhere(likeExpression);
    System.out.println(plainSelectLike); // SELECT * FROM sys_user WHERE username LIKE '张%'

    // WHERE IN
    Set<String> deptIds = Sets.newLinkedHashSet(); // 创建IN范围的元素集合
    deptIds.add("0001");
    deptIds.add("0002");
    ItemsList itemsList = new ExpressionList(deptIds.stream().map(StringValue::new).collect(Collectors.toList())); // 把集合转变为JSQLParser需要的元素列表
    InExpression inExpression = new InExpression(new Column("dept_id "), itemsList); // 创建IN表达式对象,传入列名及IN范围列表
    PlainSelect plainSelectIn = (PlainSelect) select.getSelectBody();
    plainSelectIn.setWhere(inExpression);
    System.out.println(plainSelectIn); // SELECT * FROM sys_user WHERE dept_id  IN ('0001', '0002')

    // WHERE BETWEEN AND
    Between between = new Between();
    between.setBetweenExpressionStart(new LongValue(18)); // 设置起点值
    between.setBetweenExpressionEnd(new LongValue(30)); // 设置终点值
    between.setLeftExpression(new Column("age")); // 设置左边的表达式,一般为列
    PlainSelect plainSelectBetween = (PlainSelect) select.getSelectBody();
    plainSelectBetween.setWhere(between);
    System.out.println(plainSelectBetween); // SELECT * FROM sys_user WHERE age BETWEEN 18 AND 30

    //  WHERE AND 多个条件结合,都需要成立
    AndExpression andExpression = new AndExpression(); // AND 表达式
    andExpression.setLeftExpression(equalsTo); // AND 左边表达式
    andExpression.setRightExpression(between);  // AND 右边表达式
    PlainSelect plainSelectAnd = (PlainSelect) select.getSelectBody();
    plainSelectAnd.setWhere(andExpression);
    System.out.println(plainSelectAnd); //  SELECT * FROM sys_user WHERE sys_user.user_id = '123456' AND age BETWEEN 18 AND 30

    //  WHERE OR 多个条件满足一个条件成立返回
    OrExpression orExpression = new OrExpression();// OR 表达式
    orExpression.setLeftExpression(equalsTo); // OR 左边表达式
    orExpression.setRightExpression(between);  // OR 右边表达式
    PlainSelect plainSelectOr = (PlainSelect) select.getSelectBody();
    plainSelectOr.setWhere(orExpression);
    System.out.println(plainSelectOr); // SELECT * FROM sys_user WHERE sys_user.user_id = '123456' OR age BETWEEN 18 AND 30

    // ORDER BY 排序
    OrderByElement orderByElement = new OrderByElement(); // 创建排序对象
    orderByElement.isAsc(); //  设置升序排列 从小到大
    orderByElement.setExpression(new Column("col01")); // 设置排序字段
    PlainSelect plainSelectOrderBy = (PlainSelect) select.getSelectBody();
    plainSelectOrderBy.addOrderByElements(orderByElement);
    // SELECT * FROM sys_user WHERE sys_user.user_id = '123456' OR age BETWEEN 18 AND 30 ORDER BY col01
    System.out.println(plainSelectOrderBy); 
}

输出如下:

SELECT * FROM sys_user
SELECT col1, col2 FROM sys_user
SELECT * FROM sys_user WHERE sys_user.user_id = '123456'
SELECT * FROM sys_user WHERE sys_user.user_id <> '123456'
SELECT * FROM sys_user WHERE username LIKE '张%'
SELECT * FROM sys_user WHERE dept_id  IN ('0001', '0002')
SELECT * FROM sys_user WHERE age BETWEEN 18 AND 30
SELECT * FROM sys_user WHERE sys_user.user_id = '123456' AND age BETWEEN 18 AND 30
SELECT * FROM sys_user WHERE sys_user.user_id = '123456' OR age BETWEEN 18 AND 30
SELECT * FROM sys_user WHERE sys_user.user_id = '123456' OR age BETWEEN 18 AND 30 ORDER BY col01


Tags:SQL   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,不构成投资建议。投资者据此操作,风险自担。如有任何标注错误或版权侵犯请与我们联系,我们将及时更正、删除。
▌相关推荐
MySQL 核心模块揭秘
server 层会创建一个 SAVEPOINT 对象,用于存放 savepoint 信息。binlog 会把 binlog offset 写入 server 层为它分配的一块 8 字节的内存里。 InnoDB 会维护自己的 savepoint...【详细内容】
2024-04-03  Search: SQL  点击:(6)  评论:(0)  加入收藏
原来 SQL 函数是可以内联的!
介绍在某些情况下,SQL 函数(即指定LANGUAGE SQL)会将其函数体内联到调用它的查询中,而不是直接调用。这可以带来显著的性能提升,因为函数体可以暴露给调用查询的规划器,从而规划器...【详细内容】
2024-04-03  Search: SQL  点击:(4)  评论:(0)  加入收藏
如何正确选择NoSQL数据库
译者 | 陈峻审校 | 重楼Allied Market Research最近发布的一份报告指出,业界对于NoSQL数据库的需求正在持续上升。2022年,全球NoSQL市场的销售额已达73亿美元,预计到2032年将达...【详细内容】
2024-03-28  Search: SQL  点击:(14)  评论:(0)  加入收藏
MySQL 核心模块揭秘,你看明白了吗?
为了提升分配 undo 段的效率,事务提交过程中,InnoDB 会缓存一些 undo 段。只要同时满足两个条件,insert undo 段或 update undo 段就能被缓存。1. 关于缓存 undo 段为了提升分...【详细内容】
2024-03-27  Search: SQL  点击:(11)  评论:(0)  加入收藏
MySQL:BUG导致DDL语句无谓的索引重建
对于5.7.23之前的版本在评估类似DDL操作的时候需要谨慎,可能评估为瞬间操作,但是实际上线的时候跑了很久,这个就容易导致超过维护窗口,甚至更大的故障。一、问题模拟使用5.7.22...【详细内容】
2024-03-26  Search: SQL  点击:(10)  评论:(0)  加入收藏
从 MySQL 到 ByteHouse,抖音精准推荐存储架构重构解读
ByteHouse是一款OLAP引擎,具备查询效率高的特点,在硬件需求上相对较低,且具有良好的水平扩展性,如果数据量进一步增长,可以通过增加服务器数量来提升处理能力。本文将从兴趣圈层...【详细内容】
2024-03-22  Search: SQL  点击:(24)  评论:(0)  加入收藏
在 SQL 中写了 in 和 not in,技术总监说要炒了我……
WHY?IN 和 NOT IN 是比较常用的关键字,为什么要尽量避免呢?1、效率低项目中遇到这么个情况:t1表 和 t2表 都是150w条数据,600M的样子,都不算大。但是这样一句查询 &darr;select *...【详细内容】
2024-03-18  Search: SQL  点击:(6)  评论:(0)  加入收藏
应对慢SQL的致胜法宝:7大实例剖析+优化原则
大促备战,最大的隐患项之一就是慢SQL,对于服务平稳运行带来的破坏性最大,也是日常工作中经常带来整个应用抖动的最大隐患,在日常开发中如何避免出现慢SQL,出现了慢SQL应该按照什...【详细内容】
2024-03-14  Search: SQL  点击:(5)  评论:(0)  加入收藏
MySQL自增主键一定是连续的吗?
测试环境:MySQL版本:8.0数据库表:T (主键id,唯一索引c,普通字段d)如果你的业务设计依赖于自增主键的连续性,这个设计假设自增主键是连续的。但实际上,这样的假设是错的,因为自增主键不...【详细内容】
2024-03-10  Search: SQL  点击:(6)  评论:(0)  加入收藏
准线上事故之MySQL优化器索引选错
1 背景最近组里来了许多新的小伙伴,大家在一起聊聊技术,有小兄弟提到了MySQL的优化器的内部策略,想起了之前在公司出现的一个线上问题,今天借着这个机会,在这里分享下过程和结论...【详细内容】
2024-03-07  Search: SQL  点击:(28)  评论:(0)  加入收藏
▌简易百科推荐
向量数据库落地实践
本文基于京东内部向量数据库vearch进行实践。Vearch 是对大规模深度学习向量进行高性能相似搜索的弹性分布式系统。详见: https://github.com/vearch/zh_docs/blob/v3.3.X/do...【详细内容】
2024-04-03  京东云开发者    Tags:向量数据库   点击:(5)  评论:(0)  加入收藏
原来 SQL 函数是可以内联的!
介绍在某些情况下,SQL 函数(即指定LANGUAGE SQL)会将其函数体内联到调用它的查询中,而不是直接调用。这可以带来显著的性能提升,因为函数体可以暴露给调用查询的规划器,从而规划器...【详细内容】
2024-04-03  红石PG  微信公众号  Tags:SQL 函数   点击:(4)  评论:(0)  加入收藏
如何正确选择NoSQL数据库
译者 | 陈峻审校 | 重楼Allied Market Research最近发布的一份报告指出,业界对于NoSQL数据库的需求正在持续上升。2022年,全球NoSQL市场的销售额已达73亿美元,预计到2032年将达...【详细内容】
2024-03-28    51CTO  Tags:NoSQL   点击:(14)  评论:(0)  加入收藏
为什么数据库连接池不采用 IO 多路复用?
这是一个非常好的问题。IO多路复用被视为是非常好的性能助力器。但是一般我们在使用DB时,还是经常性采用c3p0,tomcat connection pool等技术来与DB连接,哪怕整个程序已经变成以...【详细内容】
2024-03-27  dbaplus社群    Tags:数据库连接池   点击:(13)  评论:(0)  加入收藏
八个常见的数据可视化错误以及如何避免它们
在当今以数据驱动为主导的世界里,清晰且具有洞察力的数据可视化至关重要。然而,在创建数据可视化时很容易犯错误,这可能导致对数据的错误解读。本文将探讨一些常见的糟糕数据可...【详细内容】
2024-03-26  DeepHub IMBA  微信公众号  Tags:数据可视化   点击:(7)  评论:(0)  加入收藏
到底有没有必要分库分表,如何考量的
关于是否需要进行分库分表,可以根据以下考量因素来决定: 数据量和负载:如果数据量巨大且负载压力较大,单一库单一表可能无法满足性能需求,考虑分库分表。 数据增长:预估数据增长...【详细内容】
2024-03-20  码上遇见你  微信公众号  Tags:分库分表   点击:(15)  评论:(0)  加入收藏
在 SQL 中写了 in 和 not in,技术总监说要炒了我……
WHY?IN 和 NOT IN 是比较常用的关键字,为什么要尽量避免呢?1、效率低项目中遇到这么个情况:t1表 和 t2表 都是150w条数据,600M的样子,都不算大。但是这样一句查询 &darr;select *...【详细内容】
2024-03-18  dbaplus社群    Tags:SQL   点击:(6)  评论:(0)  加入收藏
应对慢SQL的致胜法宝:7大实例剖析+优化原则
大促备战,最大的隐患项之一就是慢SQL,对于服务平稳运行带来的破坏性最大,也是日常工作中经常带来整个应用抖动的最大隐患,在日常开发中如何避免出现慢SQL,出现了慢SQL应该按照什...【详细内容】
2024-03-14  京东云开发者    Tags:慢SQL   点击:(5)  评论:(0)  加入收藏
过去一年,我看到了数据库领域的十大发展趋势
作者 | 朱洁策划 | 李冬梅过去一年,行业信心跌至冰点2022 年中,红衫的一篇《适应与忍耐》的报告,对公司经营提出了预警,让各个公司保持现金流,重整团队,想办法增加盈利。这篇报告...【详细内容】
2024-03-12    InfoQ  Tags:数据库   点击:(27)  评论:(0)  加入收藏
SQL优化的七个方法,你会哪个?
一、插入数据优化 普通插入:在平时我们执行insert语句的时候,可能都是一条一条数据插入进去的,就像下面这样。INSERT INTO `department` VALUES(1, &#39;研发部(RD)&#39;, &#39...【详细内容】
2024-03-07  程序员恰恰  微信公众号  Tags:SQL优化   点击:(20)  评论:(0)  加入收藏
站内最新
站内热门
站内头条