首页 > 数据库 >Calcite解析Sql中的表名

Calcite解析Sql中的表名

时间:2023-07-20 10:23:23浏览次数:40  
标签:tableNameList String sql List SqlNode 表名 Sql new Calcite

目的是为了解析视图中的表名,构建血缘关系,下面是入门的demo
Calcite解析 有不能解析出来的情况,需要进一步了解javacc,
Jsqparser解析,都能正常解析,然而面对复杂子查询,效率很低

使用Calcite解析

package sqlparser;

import org.apache.calcite.avatica.util.Casing;
import org.apache.calcite.avatica.util.Quoting;
import org.apache.calcite.config.Lex;
import org.apache.calcite.sql.*;
import org.apache.calcite.sql.parser.SqlParseException;
import org.apache.calcite.sql.parser.SqlParser;

import java.util.ArrayList;
import java.util.List;

public class CalctieParserTablesDemo3 {


    public static void main(String[] args) {
//        String sql = "select a.id,b.name,b.label from person a, person b where a.id = b.id";
        String sql =
                "select  t.id,t.name,t.label from " +
                        "(select id,name,label from  person  " +
                        " union all " +
                        "select id,name,label from  person   ) t";





        try {
            List<String> strings = extractTableNameList(sql);
            String tables = String.join(",", strings);
            System.out.println(tables);
        } catch (SqlParseException e) {
            throw new RuntimeException(e);
        }
    }


    public static List<String> extractTableNameList(String sql) throws SqlParseException {
//        SqlParser.Config config = SqlParser.configBuilder().setLex(Lex.MYSQL).build();

        SqlParser.Config config = SqlParser.configBuilder()
                .setQuotedCasing(Casing.UNCHANGED)
                .setUnquotedCasing(Casing.UNCHANGED)
                .setQuoting(Quoting.BACK_TICK)
//                .setParserFactory(QuarkParserImpl.FACTORY)
                .setLex(Lex.MYSQL).build();


        SqlParser parser = SqlParser.create(sql,config);
        SqlNode parsed = parser.parseQuery();
//        SqlNode parsed = parser.parseStmt();
        List<String> tableNameList = new ArrayList<>();

        parseSqlNode(parsed, tableNameList);

        return tableNameList;
    }

    private static void parseFromNode(SqlNode from, List<String> tableNameList){
        SqlKind kind = from.getKind();
        switch (kind) {
            case IDENTIFIER:
                //最终的表名
                SqlIdentifier sqlIdentifier = (SqlIdentifier) from;
                tableNameList.add(sqlIdentifier.toString());
                break;
            case AS:
                SqlBasicCall sqlBasicCall = (SqlBasicCall) from;
                SqlNode selectNode = sqlBasicCall.getOperandList().get(0);
                parseSqlNode(selectNode, tableNameList);
                break;
            case JOIN:
                SqlJoin sqlJoin = (SqlJoin) from;
                SqlNode left = sqlJoin.getLeft();
                parseFromNode(left, tableNameList);
                SqlNode right = sqlJoin.getRight();
                parseFromNode(right, tableNameList);
                break;
            case SELECT:
                parseSqlNode(from, tableNameList);
                break;
        }
    }

    private static void parseSqlNode(SqlNode sqlNode, List<String> tableNameList) {
        SqlKind kind = sqlNode.getKind();
        switch (kind) {
            case IDENTIFIER:
                parseFromNode(sqlNode, tableNameList);
                break;
            case SELECT:
                SqlSelect select = (SqlSelect) sqlNode;
                parseFromNode(select.getFrom(), tableNameList);
                break;
            case UNION:
                ((SqlBasicCall) sqlNode).getOperandList().forEach(node -> {
                    parseSqlNode(node, tableNameList);
                });

                break;
            case ORDER_BY:
                handlerOrderBy(sqlNode, tableNameList);
                break;
        }
    }

    private static void handlerOrderBy(SqlNode node, List<String> tableNameList) {
        SqlOrderBy sqlOrderBy = (SqlOrderBy) node;
        SqlNode query = sqlOrderBy.query;
        parseSqlNode(query, tableNameList);
    }



}


使用jsqlparser的Demo部分代码



public static void sqlParser(String sql, String viewName) {
        Select selectStatement = null;
        CCJSqlParserManager parserManager = null;
        try {
            parserManager = new CCJSqlParserManager();
            selectStatement = (Select) parserManager.parse(new StringReader(sql));
//            new CCJSqlParser();
//            if(sql.contains("union")){
//                parserManager = new CCJSqlParserManager();
//                selectStatement = (Select) parserManager.parse(new StringReader(sql));
//            }else{
//                selectStatement = (Select) CCJSqlParserUtil.parse(sql);
//            }


        } catch (JSQLParserException e) {
            throw new RuntimeException(e);
        }


        TablesNamesFinder tablesNamesFinder = new TablesNamesFinder();
        List<String> tableList = tablesNamesFinder.getTableList(selectStatement);


        for (Iterator iter = tableList.iterator(); iter.hasNext(); ) {
            String tableName = (String) iter.next();
//            如果是包含view的,这种不能让显示,可以让显示,
            System.out.println(viewName + "===========" + tableName.replace("`", ""));
            List<String> tables = tableMapLists.get(tableName.replace("`", ""));
            if (tables == null) {
                List<String> tableLists = new ArrayList<>();
                tableLists.add(viewName);
                tableMapLists.put(tableName.replace("`", ""), tableLists);
            } else {
                if (tables.contains(viewName)) {
                    continue;
                } else {
                    tables.add(viewName);
                }
            }
//            tables.add(tableName.substring(tableName.lastIndexOf(".")+1).replaceAll("`",""));

        }

    }



标签:tableNameList,String,sql,List,SqlNode,表名,Sql,new,Calcite
From: https://www.cnblogs.com/hbym/p/17567611.html

相关文章

  • 2-12 MySQL字段约束-索引-外键
    高版本导出报错问题,是由于高版本对导出文件优化了权限设置,showvariableslike'%secure%';查看权限是NULL就代表禁止导出在配置文件my.cnf[mysqld]下加secure_file_priv=指定导出目录  本节所讲内容:1.  字段修饰符2.  清空表记录3.  索引4.  外键视图......
  • PostgreSQL explain使用
    1.概述PostgreSQL为每个收到的查询产生一个执行计划,这个执行计划是一个非完全的二叉树。通过这个执行计划,DBA或者应用人员可以清晰的了解到某个SQL在数据库中的预估的执行情况以及实际的执行情况,也能根据执行计划中资源的消耗判断性能的瓶颈点,从而对该SQL进行有针对性的优化。下......
  • 2-10-Mysql基本语句和常见数据类型
    1  SQL概述结构化查询语言(StructuredQueryLanguage)简称SQL,是一种特殊目的的编程语言,是一种数据库查询和程序设计语言,用于存取数据以及查询、更新和管理关系数据库系统;同时也是数据库脚本文件的扩展名。从上可以看出我们数据库相关工作职位大概两种:DBD和DBAdba是数据库管......
  • MySql基础学习
     一、基础学习1、打开MySql?2、如何创建数据库、数据表? 3、bug 0、注意事项mysql是不区分大小写的 1、启动MySqlcmd命令行,管理员模式运行,输入命令启动服务-----netstartmysql输入ml(命令)----------mqsql-uroot-p出现如下界面就登录成功了 2、基础sql命......
  • 在 Amazon 上以高可用性模式实现 Microsoft SQL 数据库服务现代化的注意事项
    许多企业都有需要MicrosoftSQLServer来运行关系数据库工作负载的应用程序:一些应用程序可能是专有软件,供应商可使用它强制MicrosoftSQLServer运行数据库服务;其他应用程序可能是长期存在的、自主开发的应用程序,它们在最初开发时便已包含MicrosoftSQLServer。当企业将应用......
  • postgresql-备份恢复
    1、逻辑备份恢复pg_dump/pg_restore命令备份恢复对数据库或表备份恢复##备份指定的数据库test$pg_dump-Upostgres-W-h192.168.3.122-p1921test>/pgdata/dumpbak/test.sql##备份指定库中的某个表t1$pg_dump-Upostgres-W-h192.168.3.122-p1921test......
  • 使用Canal同步mysql数据到es
    一、简介Canal主要用途是基于MySQL数据库增量日志解析,提供增量数据订阅和消费。当前的canal支持源端MySQL版本包括5.1.x,5.5.x,5.6.x,5.7.x,8.0.x二、工作原理MySQL主备复制原理MySQLmaster将数据变更写入二进制日志(binarylog,其中记录叫做二进制日志事件bin......
  • 使用Canal同步mysql数据到es
    一、简介Canal主要用途是基于MySQL数据库增量日志解析,提供增量数据订阅和消费。当前的canal支持源端MySQL版本包括5.1.x,5.5.x,5.6.x,5.7.x,8.0.x二、工作原理MySQL主备复制原理MySQLmaster将数据变更写入二进制日志(binarylog,其中记录叫做二进制日志......
  • 错误连接数据库 [mysql] : org.pentaho.di.core.exception.KettleDatabaseExcepti
    错误连接数据库[mysql]:org.pentaho.di.core.exception.KettleDatabaseException是一种常见的错误,通常在使用PentahoDataIntegration(PDI)工具连接到MySQL数据库时出现。本文将介绍这个错误的原因,以及如何解决它。在使用PDI工具连接到MySQL数据库时,经常会遇到数据库连接失败的......
  • QSqlDatabasePrivate::removeDatabase: connection ‘myConnection’ is still in use
    1.解决QSqlDatabasePrivate::removeDatabase:connection‘myConnection’isstillinuse,allquerieswillceasetowork的问题该问题主要是因为没有关闭之前的数据库连接,然后又需要创建新的数据库连接导致。解决方案:必须释放该连接的所有查询,即删除所有与该连接有关的quer......