本文共 4545 字,大约阅读时间需要 15 分钟。
问大家一个问题:当拿到一个sql,想要获取其中的select字段,是否首先想到的是手写一个来获取查询字段,可是事实并没有想象的那么简单,设想 select 'a' from xx;select id as user_id from xx;select current_date gmt_create from xx;select case when .. from xx;select count(1) from xx;等等,这些语句该怎么解析呢?
推荐使用JSQLParser。
JSQLParser是一款开源的SQL语句解析器,使用它可以把SQL语句解析成一组层次分明的java类。JSQLParsers所能解释的SQL语句不受具体数据库的限制,在支持标准SQL的同时,也支持一些特定数据库的方法。如支持Oracle关联语法(+),PostgreSQL的方法using::,以及关系运算符!=,等等。
解析之前,先来看看常见的解析器(expression)有哪些,有利于后面对代码的理解。
1、条件表达式
如:AndExpression(and),OrExpression(or)
2、关系表达式
如:EqualsTo(=),MinorThan(<),GreaterThan(>),……
3、算术表达式
如:Addition(+),Subtraction(-),Multiplication(*),Division(/),……
4、列表达式
如:Column
5、case表达式
如:CaseExpression
6、值表达式
如:StringValue,DateValue,LongValue,DoubleValue,……
7、函数表达式
如:Function
8、参数表达式
如:JdbcParameter,JdbcNameParameter,……
实现代码:
com.github.jsqlparser jsqlparser 3.1
MapparamMap = new HashMap<>(queryParamList.size()); for (String queryParam : queryParamList) { paramMap.put(queryParam, "1"); } String parsedSql = generalQueryService.replaceParameterWithValue(querySql, paramMap); try { CCJSqlParserManager parserManager = new CCJSqlParserManager(); Select select = (Select) parserManager.parse(new StringReader(parsedSql)); PlainSelect plain = (PlainSelect) select.getSelectBody(); List selectItems = plain.getSelectItems(); List items = new ArrayList<>(); if (selectItems != null) { for (SelectItem selectItem : selectItems) { if (selectItem instanceof SelectExpressionItem) { SelectExpressionItem selectExpressionItem = (SelectExpressionItem) selectItem; String columnName = ""; Alias alias = selectExpressionItem.getAlias(); Expression expression = selectExpressionItem.getExpression(); if (expression instanceof CaseExpression) { // case表达式 columnName = alias.getName(); } else if (expression instanceof LongValue || expression instanceof StringValue || expression instanceof DateValue || expression instanceof DoubleValue) { // 值表达式 columnName = Objects.nonNull(alias.getName()) ? alias.getName() : expression.getASTNode().jjtGetValue().toString(); } else if (expression instanceof TimeKeyExpression) { // 日期 columnName = alias.getName(); } else { if (alias != null) { columnName = alias.getName(); } else { SimpleNode node = expression.getASTNode(); Object value = node.jjtGetValue(); if (value instanceof Column) { columnName = ((Column) value).getColumnName(); } else if (value instanceof Function) { columnName = value.toString(); }else { // 增加对select 'aaa' from table; 的支持 columnName = String.valueOf(value); columnName = columnName.replace("'", ""); columnName = columnName.replace("\"", ""); columnName = columnName.replace("`", ""); } } } columnName = columnName.replace("'", ""); columnName = columnName.replace("\"", ""); columnName = columnName.replace("`", ""); items.add(columnName); } else if (selectItem instanceof AllTableColumns) { AllTableColumns allTableColumns = (AllTableColumns) selectItem; items.add(allTableColumns.toString()); } else { items.add(selectItem.toString()); } } } return StringUtils.join(items, ","); } catch (JSQLParserException e) { // ignore } return null;
代码可能未包含所有的情况,所以当发现问题时,需要查看 expression 按需解决。
转载地址:http://giqen.baihongyu.com/