【问题标题】:SQL parser to alter table name用于更改表名的 SQL 解析器
【发布时间】:2015-08-17 09:30:14
【问题描述】:

我有一个 SQL 查询:

select 
    t1.name, t2.address 
from 
    Table1 t1 
inner join 
    Table2 t2 on t1.id = t2.id;

还有一张地图:

Map<String,String> map = new HashMap<String,String>();
map.put("testTable", "hive.DB1");
map.put("testTable", "mongo.DB2");

我只想使用这张地图将上述查询转换为:

select 
    t1.name, t2.address 
from 
    hive.DB1.`Table1` t1 
inner join 
    mongo.DB2.`Table2` t2 on t1.id = t2.id;

哪种开源 SQL 解析器适合此目的。

【问题讨论】:

  • 我猜(希望)您使用on 而不是where,不是吗?
  • 顺便问一下,你从哪里得到你的字段(在选择中:t1.namet2.address)从你的地图?
  • @RaphaëlAlthaus 我更新了我的问题。这只是一个例子。
  • 我不需要从地图中获取这些字段。这些字段保持原样。我只想更改表名。
  • 你需要指定SQL的方言。那里有许多解析器,都针对不同供应商的方言。然后你会发现你正在使用的那个是否真的适合这个任务。

标签: sql parsing sql-parser


【解决方案1】:

您真的需要 SQL 解析器吗? 为什么不直接使用 sed?

例如一张桌子:

sed -e "s/Table1/hive.DB1.TABLE1/g" C:\test.sql > C:\new.sql

【讨论】:

  • 某些数据库不支持表达式中的完全限定名称。因此: select table1.col1 from table1 会 select hive.db1.table1.col1 from hive.db1.table1 是不正确的。应该是从 hive.db1.table1 中选择 table1.col1。这就是需要解析器的原因。
【解决方案2】:

我用JSqlParser

我从 SQL 查询中提取了表名:

Statement statement = CCJSqlParserUtil.parse("select t1.name, t2.address from Table1 t1 inner join Table2 t2 on t1.id = t2.id;");
Select selectStatement = (Select) statement;
TablesNamesFinder tablesNamesFinder = new TablesNamesFinder();
List<String> tableList = tablesNamesFinder.getTableList(selectStatement); 

然后我根据地图修改了Table Names。

【讨论】:

    【解决方案3】:

    需要一个解析器来仅更改“来自”部分的表引用。某些数据库不接受表达式中的完全限定名称。

    这段代码使用JSqlParser 0.9.5-SNAPSHOT并打印出修改后的SQL:

    public class SimpleTableReplacer {
        public static void main(String args[]) throws JSQLParserException {
            String sql = "select t1.name, t2.address from Table1 t1 inner join Table2 t2 on t1.id = t2.id";
            Select select = (Select)CCJSqlParserUtil.parse(sql);
    
            //Replace Table1 with hive.DB1.Table1 and Table2 with mongo.DB2.Table2
            StringBuilder buffer = new StringBuilder();
            ExpressionDeParser expressionDeParser = new ExpressionDeParser();
            SelectDeParser deparser = new SelectDeParser(expressionDeParser,buffer ) {
                @Override
                public void visit(Table tableName) {
                    switch (tableName.getName()) {
                        case "Table1": getBuffer().append("hive.DB1.Table1").append(' ').append(tableName.getAlias().getName());break;
                        case "Table2": getBuffer().append("mongo.DB2.Table2").append(' ').append(tableName.getAlias().getName());break;
                        default:
                            super.visit(tableName);
                    }
                }
            };
            expressionDeParser.setSelectVisitor(deparser);
            expressionDeParser.setBuffer(buffer);
            select.getSelectBody().accept(deparser);
            //End of value modification
    
            System.out.println(buffer.toString());
        }
    }
    

    结果:SELECT t1.name, t2.address FROM hive.DB1.Table1 t1 INNER JOIN mongo.DB2.Table2 t2 ON t1.id = t2.id

    当然,您可以使用此代码来修改类层次结构本身,这意味着更改表 - 对象名称。

    此外,您可以使用 JSqlParser 的新功能为 SQL 的某些部分提供 AST 节点。您可以提取 SQL 中表名的确切位置并在那里进行文本替换。可以这样编码:

    SimpleNode node = (SimpleNode) CCJSqlParserUtil.parseAST(sql);
        node.childrenAccept(new CCJSqlParserDefaultVisitor() {
            @Override
            public Object visit(SimpleNode node, Object data) {
                if (node.getId() == CCJSqlParserTreeConstants.JJTTABLE) {
                    System.out.println("table name '" + node.jjtGetValue() + "' found at " + node.jjtGetFirstToken().beginColumn + "-" + node.jjtGetLastToken().endColumn);
                }
                return super.visit(node, data); 
            }
        }, null);
    

    【讨论】:

      【解决方案4】:

      如果您只需要从 SQL 中提取表名并执行一些逻辑,则需要超轻、超快速的库来执行此操作

      只需在你的 pom 中添加以下内容

      <dependency>
          <groupId>com.github.mnadeem</groupId>
          <artifactId>sql-table-name-parser</artifactId>
          <version>0.0.1</version>
      </dependency>
      

      并使用以下指令

      new TableNameParser(sql).tables()
      

      更多详情请参考project

      免责声明:我是所有者

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-11-15
        • 1970-01-01
        • 2015-01-12
        • 1970-01-01
        相关资源
        最近更新 更多