SQL解析利器JSqlParser
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语句:
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查询语句
*
* @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
三千骑兵是什么意思 率领三千骑兵的猛将是谁
三千骑兵指的是三千个骑着战马出战的士兵。这在古代是有一些典故的,古代的一些猛将或者是将军,曾经带着少量的骑兵,与敌方的上万人大部队进行过搏斗和厮杀。打赢的战役为千古流传,而打输的战役也让人铭记于心。在历史上这样的战争不在少数。一、唐朝三千骑兵打胜仗我要新鲜事2023-05-12 04:46:410000中子星75年后撞地球,纯属谣言(最近中子星距地球250光年)
关于中子星的恐怖,大家应该有所耳闻,它是黑洞的儿子,与类星体相似,是一种具有毁灭性破坏力的天体。而就是这么恐怖的存在,有人说中子星75年后撞地球!这是真的吗?接下来就跟小编一起去探讨看看。一、中子星75年后撞地球我要新鲜事2023-05-11 04:09:240004空间站的高度在400km 为啥不飞更高一点(空间站)
空间站在400高度有利于空间站的运行以及宇航员的探究。如今人们在研究太空和宇宙的时候,通常都会飞出地球,生活在空间站一段时间,目前整个世界上有的空间站也不过是以美国为首研制出来的。国际空间站和我们中国独自研究出的中国空间站,但我们可以发现这两个空间站作为人类长期驻守在太空的一个重要设施。只是在距离地球400km左右运行着并没有飞的更远。空间站运行我要新鲜事2023-10-27 19:52:040000生黄豆粉的食用方法 生黄豆粉怎么做好吃
生黄豆粉可以直接用开水煮熟成糊状,并且加入调料就可以食用。生黄豆粉是由黄豆而磨成粉,营养价值非常高。生黄豆粉的食用方法非常多,但大多数人还是喜欢以冲泡方式来使用。因为非常的简单快捷,如果作为早餐也是不错,节省时间,还能够吃上营养早餐。一、生黄豆粉怎么做好吃我要新鲜事2023-05-12 00:12:500000为什么说,这个世界被精心调校过的?还有很多谜题我们都解不开
一直以来,我们都在思考世界的真实样子。古代缺乏先进的科技,对世界的认识更多的来源于主观意志,而现在科技有了较大的发展之后,我们对世界的认识也会更加客观。等到我们对身处的宇宙有了一定的认识却发现,人类能够恰好在宇宙中生存,似乎已经经过了某种调效,否则任何一种条件不满足,人类都会因此而被摧毁。因此人类的诞生是极其复杂的,任何一个细小的因素发生变化,都会抹去他们在世界上存在的痕迹。我要新鲜事2023-05-14 11:52:120000