通过druid解析sql查询语句的查询字段、过滤条件,并且获取排序

1.获取表名

sql为数据表语句 select id as id2 from testDb.testTable where id = ${id}

          //数据类型可以输入其他的
          DbType dbType = DbType.valueOf("MYSQL".toLowerCase());
           //sql为数据表语句  select id as id2 from testDb.testTable where id = ${id}
            List<SQLStatement> statementList = SQLUtils.parseStatements(sql, "MYSQL".toLowerCase());
            for (SQLStatement statement : statementList) {
                if (statement instanceof SQLSelectStatement) {
                    SchemaStatVisitor visitor = new SchemaStatVisitor(dbType);
                    statement.accept(visitor);
                    //解析表名
                    SQLSelectStatement selectStatement = (SQLSelectStatement) statement;
                    SQLSelectQueryBlock queryBlock = selectStatement.getSelect().getFirstQueryBlock();
                    Map<TableStat.Name, TableStat> tables = visitor.getTables();
            
                    tables.forEach((tableName, tableStat) -> {
                      //判断sql语句
                        if ("Select".equals(tableStat.toString())) {
                            //这里获取表名
                            tableNameList.add(tableName.getName().contains(".") ? tableName.getName().split("\\.")[1] : tableName.getName());
                        }
                    });
                  }
2.获取查询字段
 //查询字段
 List<SQLSelectItem> selectList = queryBlock.getSelectList();
 if (CollectionUtils.isNotEmpty(selectList)) {
                        selectList.stream().forEach(sqlSelectItem -> {
                            String outStr = sqlSelectItem.toString().trim();
                            //去除字段前面的 表的别名
                            if (outStr.contains(".")) {
                                outStr = outStr.split("\\.", -1)[1];
                            }
                            if (outStr.contains("AS")) {
                                outStr = outStr.split("AS", -1)[0].trim();
                                //获取字段名
                                outputParamDto.setEnName(outStr);
                                //获取别名
                                outputParamDto.setAliasName(sqlSelectItem.getAlias());
                            } else {
                                  //获取字段名
                                outputParamDto.setEnName(outStr);
                             }
                            });  
                 }
3.获取过滤条件
 //查询过滤条件
                    List<TableStat.Condition> conditions = visitor.getConditions();
                    if (CollectionUtils.isNotEmpty(conditions)) {
                        conditions.stream().forEach(row -> {
                            //获取过滤条件  id=12  获取 id
                            String columnName = row.getColumn().getName();
                            //获取操作符  id=12  获取 = 号
                            String operator = row.getOperator();
                            });
                    }
  
4.获取排序条件
             //查询order by
              List<TableStat.Column> orderByColumns = visitor.getOrderByColumns();
               if (CollectionUtils.isNotEmpty(orderByColumns)) {
                                orderByColumns.stream().forEach(orderByColumn -> {
                                    if (outputParamDto.getEnName().equals(orderByColumn.getName())) {
                                        if (BizConstants.ASC_PARAM.equals(orderByColumn.getAttributes().get("orderBy.type"))) {
                                            outputParamDto.setSort(BizConstants.ASC_PARAM);
                                        } else {
                                            outputParamDto.setSort(BizConstants.DESC_PARAM);
                                        }
                                    }
                                });
               }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以通过以下步骤实现: 1. 使用 Druid 解析 SQL获取 SQL 中所有的表名和别名; 2. 使用 Feign 调用接口查询每个表的元数据信息,包括表的字段名和类型; 3. 解析 SQL 中的 left join 语句,获取需要替换的表和需要替换的字段; 4. 根据元数据信息替换 left join 语句中的 * 为具体的字段名。 代码示例: ```java import com.alibaba.druid.sql.SQLUtils; import com.alibaba.druid.sql.ast.SQLExpr; import com.alibaba.druid.sql.ast.SQLName; import com.alibaba.druid.sql.ast.SQLObject; import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr; import com.alibaba.druid.sql.ast.statement.*; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlSelectQueryBlock; import com.alibaba.druid.sql.dialect.mysql.parser.MySqlStatementParser; import com.alibaba.druid.sql.parser.ParserException; import com.alibaba.druid.util.JdbcConstants; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @Component public class SqlParser { @Autowired private FeignClient feignClient; public String replaceSelectStar(String sql) throws ParserException, IOException { // 解析 SQL MySqlStatementParser parser = new MySqlStatementParser(sql); SQLStatement stmt = parser.parseStatement(); if (!(stmt instanceof SQLSelectStatement)) { throw new ParserException("only support select statement"); } SQLSelectStatement selectStmt = (SQLSelectStatement) stmt; SQLSelect select = selectStmt.getSelect(); SQLSelectQuery query = select.getQuery(); if (!(query instanceof MySqlSelectQueryBlock)) { throw new ParserException("only support mysql select statement"); } MySqlSelectQueryBlock queryBlock = (MySqlSelectQueryBlock) query; // 获取所有表的名称和别名 List<SQLTableSource> from = queryBlock.getFrom(); Map<String, String> tableAliasMap = new HashMap<>(); for (SQLTableSource tableSource : from) { if (tableSource instanceof SQLJoinTableSource) { SQLJoinTableSource joinTableSource = (SQLJoinTableSource) tableSource; SQLTableSource left = joinTableSource.getLeft(); if (left instanceof SQLExprTableSource) { SQLExprTableSource exprTableSource = (SQLExprTableSource) left; SQLExpr expr = exprTableSource.getExpr(); if (expr instanceof SQLName) { SQLName name = (SQLName) expr; String tableName = name.getSimpleName(); String alias = exprTableSource.getAlias(); tableAliasMap.put(alias, tableName); } } } else if (tableSource instanceof SQLExprTableSource) { SQLExprTableSource exprTableSource = (SQLExprTableSource) tableSource; SQLExpr expr = exprTableSource.getExpr(); if (expr instanceof SQLName) { SQLName name = (SQLName) expr; String tableName = name.getSimpleName(); String alias = exprTableSource.getAlias(); tableAliasMap.put(alias, tableName); } } } // 获取每个表的元数据信息 ObjectMapper objectMapper = new ObjectMapper(); Map<String, List<String>> tableColumnsMap = new HashMap<>(); for (String alias : tableAliasMap.keySet()) { String tableName = tableAliasMap.get(alias); String metadata = feignClient.getTableMetadata(tableName); Map<String, Object> metadataMap = objectMapper.readValue(metadata, Map.class); List<Map<String, String>> columns = (List<Map<String, String>>) metadataMap.get("columns"); List<String> columnList = new ArrayList<>(); for (Map<String, String> column : columns) { columnList.add(column.get("name")); } tableColumnsMap.put(alias, columnList); } // 替换 left join 中的 * List<SQLJoinTableSource> joins = queryBlock.getJoins(); for (SQLJoinTableSource join : joins) { SQLTableSource right = join.getRight(); if (right instanceof SQLExprTableSource) { SQLExprTableSource exprTableSource = (SQLExprTableSource) right; SQLExpr expr = exprTableSource.getExpr(); if (expr instanceof SQLName) { SQLName name = (SQLName) expr; String alias = exprTableSource.getAlias(); List<String> columns = tableColumnsMap.get(alias); if (columns != null) { SQLSelectQueryBlock subQuery = join.getCondition().getRight().getSubQuery().getQueryBlock(); List<SQLSelectItem> selectList = subQuery.getSelectList(); for (int i = 0; i < selectList.size(); i++) { SQLSelectItem selectItem = selectList.get(i); SQLExpr selectExpr = selectItem.getExpr(); if (selectExpr instanceof SQLAllColumnExpr) { selectList.remove(i); for (String column : columns) { SQLSelectItem newItem = new SQLSelectItem(new SQLIdentifierExpr(column)); selectList.add(i, newItem); i++; } } } } } } } // 重新生成 SQL return SQLUtils.toMySqlString(stmt, JdbcConstants.MYSQL); } } ``` 其中,FeignClient 是用来调用元数据查询接口的,需要根据实际情况进行实现。`getTableMetadata` 方法返回的元数据信息应该是一个 JSON 字符串,包含字段名和类型等信息。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值