如何在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",它指的是语法的官方分类。语法可以是规则的。语法也可以是非正则的。
- SQL是非规则的
- 正则表达式无法解析非正则语言
以下是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
,其中
b
用于单词边界- CCD_ 3用于正后方查找。在这里,它被用来观察
from
的背后 - 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"));
}
}
您还需要调用Matcher
的find
方法,然后才能访问匹配的组。
请注意,这相当麻烦,从长远来看,您可能会更好地使用像这样的真正解析器https://github.com/JSQLParser/JSqlParser.