3

我是 jsqlparser 的新手,并试图解析 sql 语句以获取表名及其查询类型(在 Java 中)。

例如 1。
INSERT INTO Customers (CustomerName, Country) SELECT SupplierName, Country FROM Suppliers WHERE Country='Germany'
从这个查询中,我想得到表名Suppliers和它的查询类型SELECT
同样,表名Suppliers及其查询类型INSERT

例如 2。
UPDATE CUSTOMERS SET SALARY = SALARY * 0.25 WHERE AGE IN (SELECT AGE FROM CUSTOMERS_BKP WHERE AGE >= 27 )
从这个查询中,我想得到表名CUSTOMERS_BKP和它的查询类型SELECT
同样,表名CUSTOMERS及其查询类型UPDATE

例如 3。
UPDATE CUSTOMERS SET SALARY = SALARY * 0.25 WHERE AGE IN (SELECT AGE FROM CUSTOMERS WHERE AGE >= 27 )
(我知道这个查询可以简化,但是例如我在这里粘贴了。)
从这个查询中,我想获取表名CUSTOMERS及其查询类型SELECT
同样,表名CUSTOMERS及其查询类型UPDATE
注意:这里的表名相同但查询类型不同。

同样,我想为任何复杂的 sql 查询获取表名及其查询类型。

你能帮我解决这个问题吗?

如果您希望我提供任何详细信息,请发表评论。

4

2 回答 2

1

您提出的问题是一个棘手的问题,因为 JSqlParsers API 缺少一些扩展点。为了纠正这个问题,我在 github 上创建了一些问题。所以这里有一个小样本来运行它。输出是:

eg1
INSERT - Customers
SELECT - [Suppliers]
eg2
UPDATE - [CUSTOMERS]
SELECT - [CUSTOMERS_BKP]
eg3
UPDATE - [CUSTOMERS]
SELECT - [CUSTOMERS]

您的主要工具是JSqlParserTablesNamesFinder,它获取某些 SQL 的所有表名。现在我们必须修改它,以单独的方式获取所有基于选择语句的表名。这是使用TablesNamesFinderExt完成的,它也可以使用Insert语句纠正子选择问题。

简而言之,finder 识别子选择并设置全局标志inSelect以填充单独的mySelectTableList以供后续调用visit(Table ...)

import java.util.ArrayList;
import java.util.List;
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.schema.Table;
import net.sf.jsqlparser.statement.insert.Insert;
import net.sf.jsqlparser.statement.select.SubSelect;
import net.sf.jsqlparser.statement.update.Update;
import net.sf.jsqlparser.util.TablesNamesFinder;

public class SimpleSqlParserTableNames2 {

    public static void main(String args[]) throws JSQLParserException {
        System.out.println("eg1");
        Insert insert = (Insert)CCJSqlParserUtil.parse("INSERT INTO Customers (CustomerName, Country) SELECT SupplierName, Country FROM Suppliers WHERE Country='Germany'");
        TablesNamesFinderExt finder = new TablesNamesFinderExt();

        System.out.println("INSERT - " + insert.getTable());
        finder.getTableList(insert.getSelect());
        System.out.println("SELECT - " + finder.getSelectTableList());

        System.out.println("eg2");
        Update update = (Update)CCJSqlParserUtil.parse("UPDATE CUSTOMERS SET SALARY = SALARY * 0.25\n" +
                    "  WHERE AGE IN (SELECT AGE FROM CUSTOMERS_BKP WHERE AGE >= 27 )");
        finder = new TablesNamesFinderExt();
        System.out.println("UPDATE - " + update.getTables());
        finder.getTableList(update);
        System.out.println("SELECT - " + finder.getSelectTableList());

        System.out.println("eg3");
        update = (Update)CCJSqlParserUtil.parse("UPDATE CUSTOMERS SET SALARY = SALARY * 0.25\n" +
                    "WHERE AGE IN (SELECT AGE FROM CUSTOMERS WHERE AGE >= 27 )");
        finder = new TablesNamesFinderExt();
        System.out.println("UPDATE - " + update.getTables());
        finder.getTableList(update);
        System.out.println("SELECT - " + finder.getSelectTableList());
    }

    static class TablesNamesFinderExt extends TablesNamesFinder {
        List<String> mySelectTableList = new ArrayList<>();
        boolean inSelect = true;
        /**
         * To solve JSqlParsers Problem in getting tablenames from subselect using an Insert
         * statement.
         *
         * @param insert
         * @return
         */
        @Override
        public List<String> getTableList(Insert insert) {
            List<String> list = super.getTableList(insert);
            if (insert.getSelect() != null) {
                insert.getSelect().getSelectBody().accept(this);
            }
            return list;
        }

        @Override
        public void visit(SubSelect subSelect) {
            inSelect = true;
            super.visit(subSelect);
        }

        @Override
        public void visit(Table tableName) {
            super.visit(tableName); 
            if (inSelect && !mySelectTableList.contains(tableName.getFullyQualifiedName()))
                mySelectTableList.add(tableName.getFullyQualifiedName());
        }

        public List<String> getSelectTableList() {
            return mySelectTableList;
        }

    }
}
于 2015-06-03T07:40:42.993 回答
1

如果您只需要 SQL 中的表名,您需要一个超轻量级、超快速的库(完整的 SQL 解析器会被杀死)

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

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

并使用以下说明

new TableNameParser(sql).tables()

有关详细信息,请参阅项目

免责声明:我是所有者

于 2016-08-27T04:50:27.673 回答