如何在Java中使用Regex提取SQL FROM子句中的表名

  • 本文关键字:子句 SQL FROM 提取 Regex Java java
  • 更新时间 :
  • 英文 :


如何在Java中使用Regex提取SQL FROM子句中的表名?

这是我迄今为止所拥有的。假设目前没有联接或嵌套查询。还假设可能存在断线等

public static String extractTableName(String query) {
Pattern p = Pattern.compile(".* from\S+(?=table)\S+");
Matcher m = p.matcher(query);
return m.group("table");
}
public static void main(String... args) {
System.out.println(extractFromClause("select  from hello where foo=bar")); // expecting to print hello
}

你想要的在数学上是不可能的;SQL不是常规的。"正则表达式"中的"regular"不仅仅是一个随机名称,比如"Joe"、"Jane"甚至"Java",它指的是语法的官方分类。语法可以是规则的。语法也可以是非正则的。

  1. SQL是非规则的
  2. 正则表达式无法解析非正则语言

以下是SQL的一些选择示例,有望从经验上帮助您实现这一点:

SELECT "from" AS 'from' FROM 'from';
SELECT a FROM b UNION SELECT c FROM d;
SELECT 1;
SELECT a, b FROM (SELECT c a, d b FROM foo) x;
SELECT a, b FROM foo.bar;
SELECT a, b FROM c, d;
SELECT x FROM UNNEST(ARRAY['a', 'b', 'c']);
SELECT x, y FROM TABLE(VALUE INT = ARRAY[1, 2]);

情况变得更糟;SQL是一个规范,但没有一个数据库引擎可以100%完全实现它,而且所有的数据库引擎都增加了大量的额外功能。

后退一步;找到另一种方法。也许,如果这些查询是在文本文件中输入的,那么让在这些查询中输入的查询预先列出它们可以获取的查询。也许可以重新设计系统;您似乎错误地认为,一个查询必须恰好命中一个表,或者至少命中一个主表。这不是它的工作方式,所以"简化"被证明是一个过于简单化的过程,你无法做到

我建议使用sql解析器,而不是使用regex,因为您的表可能并不总是包含字符串表。例如,您可以查看JSqlParser。你可以在这里找到wiki和从sql中提取表名的例子sql解析的例子

Statement statement = CCJSqlParserUtil.parse("SELECT * FROM MY_TABLE1");
Select selectStatement = (Select) statement;
TablesNamesFinder tablesNamesFinder = new TablesNamesFinder();
List<String> tableList = tablesNamesFinder.getTableList(selectStatement);

您可以使用正则表达式(?<=from)s+?bw+b,其中

  1. b用于单词边界
  2. CCD_ 3用于正后方查找。在这里,它被用来观察from的背后
  3. CCD_ 5指定可选的一个或多个空白字符,而CCD_

演示:

import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Main {
public static String extractFromClause(String query) {
String table = "";
Pattern p = Pattern.compile("(?<=from)\s+?\b\w+\b");
Matcher m = p.matcher(query);
if (m.find()) {
table = m.group();
}
return table.trim();
}
public static void main(String... args) {
System.out.println(extractFromClause("select from hello where foo=bar"));
}
}

输出:

hello

您的正则表达式需要查找whitespace,然后查找FROM关键字,然后查找任何没有空格的字符:

sFROMs+(S+)s

您不需要.+,因为您不需要将带有^的regex锚定到该行的开头。

import java.util.regex.*;
public class TableName {
public static String extractTableName(String query) {
Pattern p = Pattern.compile("\sfrom\s+(\S+)\s", Pattern.CASE_INSENSITIVE);
Matcher m = p.matcher(query);
m.find();
return m.group(1);
}
public static void main(String... args) {
System.out.println(extractTableName("select  from hello where foo=bar"));
System.out.println(extractTableName("SELECT a, b, c from db.hello where   foo=bar"));
}
}

您还需要调用Matcherfind方法,然后才能访问匹配的组。

请注意,这相当麻烦,从长远来看,您可能会更好地使用像这样的真正解析器https://github.com/JSQLParser/JSqlParser.

最新更新