Apache Calcite进行SQL解析(java代码实例)
作者:追求无悔 发布时间:2023-06-26 23:11:59
标签:Apache,Calcite,解析
背景
当一个项目分了很多模块,很多个服务的时候,一些公共的配置就需要统一管理了,于是就有了元数据驱动!
简介
什么是Calcite?
是一款开源SQL解析工具, 可以将各种SQL语句解析成抽象语法树AST(Abstract Syntax Tree), 之后通过操作AST就可以把SQL中所要表达的算法与关系体现在具体代码之中。
Calcite能做啥?
SQL 解析
SQL 校验
查询优化
SQL 生成器
数据连接
实例
今天主要是贴出一个java代码实例,实现了:解析SQL语句中的表名
上代码:
SQL语句转化:
public static SqlNode parseStatement(String sql) {
SqlParser parser = SqlParser.create(sql, config.getParserConfig());
try {
return parser.parseQuery();
} catch (Exception e) {
e.printStackTrace();
throw new UnsupportedOperationException("operation not allowed");
}
}
解析Select中的表名:
private static Set<String> extractSourceTableInSelectSql(SqlNode sqlNode, boolean fromOrJoin) {
if (sqlNode == null) {
return new HashSet<>();
}
final SqlKind sqlKind = sqlNode.getKind();
if (SqlKind.SELECT.equals(sqlKind)) {
SqlSelect selectNode = (SqlSelect) sqlNode;
Set<String> selectList = new HashSet<>(extractSourceTableInSelectSql(selectNode.getFrom(), true));
selectNode.getSelectList().getList().stream().filter(node -> node instanceof SqlCall)
.forEach(node -> selectList.addAll(extractSourceTableInSelectSql(node, false)));
selectList.addAll(extractSourceTableInSelectSql(selectNode.getWhere(), false));
selectList.addAll(extractSourceTableInSelectSql(selectNode.getHaving(), false));
return selectList;
if (SqlKind.JOIN.equals(sqlKind)) {
SqlJoin sqlJoin = (SqlJoin) sqlNode;
Set<String> joinList = new HashSet<>();
joinList.addAll(extractSourceTableInSelectSql(sqlJoin.getLeft(), true));
joinList.addAll(extractSourceTableInSelectSql(sqlJoin.getRight(), true));
return joinList;
if (SqlKind.AS.equals(sqlKind)) {
SqlCall sqlCall = (SqlCall) sqlNode;
return extractSourceTableInSelectSql(sqlCall.getOperandList().get(0), fromOrJoin);
if (SqlKind.IDENTIFIER.equals(sqlKind)) {
Set<String> identifierList = new HashSet<>();
if (fromOrJoin) {
SqlIdentifier sqlIdentifier = (SqlIdentifier) sqlNode;
identifierList.add(sqlIdentifier.toString());
}
return identifierList;
Set<String> defaultList = new HashSet<>();
if (sqlNode instanceof SqlCall) {
SqlCall call = (SqlCall) sqlNode;
call.getOperandList()
.forEach(node -> defaultList.addAll(extractSourceTableInSelectSql(node, false)));
return defaultList;
}
解析Insert语句中的表名:
private static Set<String> extractSourceTableInInsertSql(SqlNode sqlNode, boolean fromOrJoin) {
SqlInsert sqlInsert = (SqlInsert) sqlNode;
Set<String> insertList = new HashSet<>(extractSourceTableInSelectSql(sqlInsert.getSource(), false));
final SqlNode targetTable = sqlInsert.getTargetTable();
if (targetTable instanceof SqlIdentifier) {
insertList.add(((SqlIdentifier) targetTable).toString());
}
return insertList;
}
执行效果
private static final String sql0 = "SELECT MIN(relation_id) FROM tableA JOIN TableB GROUP BY account_instance_id, follow_account_instance_id HAVING COUNT(*)>1";
private static final String sql1 = "SELECT * FROM blog_user_relation a WHERE (a.account_instance_id,a.follow_account_instance_id) IN (SELECT account_instance_id,follow_account_instance_id FROM Blogs_info GROUP BY account_instance_id, follow_account_instance_id HAVING COUNT(*) > 1)";
private static final String sql2 = "select name from (select * from student)";
private static final String sql3 = "SELECT * FROM Student LEFT JOIN Grade ON Student.sID = Grade.gID\n" +
"UNION\n" +
"SELECT * FROM Student RIGHT JOIN Grade ON Student.sID = Grade.gID";
private static final String sql4 = "SELECT *\n" +
"FROM teacher\n" +
"WHERE birth = (SELECT MIN(birth)\n" +
" FROM employee)";
private static final String sql5 = "SELECT sName\n" +
"FROM Student\n" +
"WHERE '450' NOT IN (SELECT courseID\n" +
" FROM Course\n" +
" WHERE sID = Student.sID)";
final SqlNode sqlNode0 = parseStatement(sql0);
System.out.println("sqlNode0: " + extractSourceTableInSelectSql(sqlNode0, false));
结果为:
来源:https://blog.51cto.com/noregrets/4960484
0
投稿
猜你喜欢
- Java 8 中 Function 接口的介绍Java 8 中提供了一个函数式接口 Function,这个接口表示对一个参数做一些
- 我们经常需要对我们的开发的软件做各种测试, 软件对系统资源的使用情况更是不可少, 目前有多个监控工具, 相比JProfiler对系统资源尤其
- 第一步:后端简单建个SpringBoot项目,提供一个 helloWorld接口;版本选用 2.2.6.RELEASEpackage com
- 有时候因为安全问题,需要把配置文件的中数据库用户名密码由明文改成密文,大多数其实是为了应付甲方而已。1.pom.xml引入依赖<dep
- java有两种类型的classload,一种是user-defined的,一种是jvm内置的bootstrap class loader,所
- tokentoken的意思是“令牌”,是用户身份的验证方式,最简单的token组成:uid(用户唯一的身份标识)、time(当前时间的时间戳
- springboot集成开发实现商场秒杀加入主要依赖<dependency> <groupId>org.spring
- 我们深知在操作Java流对象后要将流关闭,但往往事情不尽人意,大致有以下几种不能一定将流关闭的写法:1.在try中关流,而没在finally
- 这篇文章主要介绍了spring cloud gateway请求跨域问题解决方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定
- 先上图下拉刷新跟原生开发一样,下拉刷新在flutter里提供的有组件实现 RefreshIndicator一直不明白为啥组件中都提供下拉刷新
- 开发项目的时候,表很多,是不可能一点点的自己去写xml ,dao文件的,这里就需要用到代码的自动生成工具了。第一步:导入jar包,当然,这之
- 本文实例讲述了java GUI编程之paint绘制操作。分享给大家供大家参考,具体如下:import java.awt.*;public c
- 前言前天工作中遇到了这样一个问题,我在接口的参数封装了一个pojo,这是很常见的,当参数一多,惯性的思维就是封装一个pojo.那么在参数前有
- 介绍什么是ThreadLocal?ThreadLocal叫做线程变量,用于在多线程环境下创建线程本地变量。通俗的讲,ThreadLocal可
- 目录环境准备1.数据库操作1.1获取所有数据库1.2获取指定库的所有集合名1.3.删除数据库2.文档操作2.1插入文档2.2查询文档2.3分
- 一.HashMap 和Hashtable 的区别我们先看2个类的定义 public class Hashtable exten
- java Hibernate多对多映射前言:一、单向多对多 单向多对多的例子用人和职位来举例,一个人可以有多个职位
- 传统的Trie实现简单,但是占用的空间实在是难以接受,特别是当字符集不仅限于英文26个字符的时候, * 起来的空间根本无法接受。双数组Trie
- 开放端口安全组没开放端口是原罪!!!导致好多BUG费时费力。Hbase悄悄 * 的用了好多端口,比如被我抓到的42239,直接搜索报错药不对症
- 树的同构备忘!定义:给定两棵树r1、r2,如果r1可以通过若干次的左子树和右子树互换,使之与r2完全相同,这说明两者同构。举例树的构造树可以