【问题标题】:Retrieving arguments from an SQL query从 SQL 查询中检索参数
【发布时间】:2019-06-01 10:41:43
【问题描述】:

我想从 SQL 查询中获取所有参数。在这种情况下,查询是数组中的纯字符串。 我有很多成对的查询,格式如下:

SELECT * FROM my_table t WHERE (t.attr1 = ? AND t.attr2 = ?) OR t.attr3= ?

它的对是(其中包含我要检索的参数):

SELECT * FROM my_table t WHERE (t.attr1 = 3 AND t.attr2 = 'str') OR t.attr3= 4

所以输出将是:

3, 'str' and 4.

如何根据这些对检索这些值?

我尝试在 Java 中使用正则表达式,但它可能很困难,因为 ?可以是一个数字, 一个字符串等等。该字符串可以包含另一个 ?这是字符串的一部分,例如:

UPDATE my_table SET attr2 = ? WHERE attr5 = ?
UPDATE my_table SET attr2 = 'Is it true?' WHERE attr5 = 'What is it?'

【问题讨论】:

  • 如果您的查询格式正确,您可以搜索' ? '——即问号周围的空格。在普通写作中,“?”之前永远不会有空格。
  • 请问您的出发点是什么?你真的有一个绑定参数的字符串吗?或者,你的起点是第一个只有占位符的字符串吗?
  • @TimBiegeleisen:他说他有两个字符串。

标签: java sql regex


【解决方案1】:

您可以使用这种方法来实现,将查询中的每个? 替换为(.*),然后根据它创建一个模式。然后应用另一对具有实际值的字符串,然后打印出将根据查询字符串中的? 动态创建的所有组中的值。

这是一个执行相同操作的 Java 代码。

// This map stores your paired queries where key stores the placeholder query and value stores the query having actual parameters.
Map<String, String> pairMap = new HashMap<>();
pairMap.put("SELECT * FROM my_table t WHERE (t.attr1 = ? AND t.attr2 = ?) OR t.attr3= ?", "SELECT * FROM my_table t WHERE (t.attr1 = 3 AND t.attr2 = 'str') OR t.attr3= 4");
pairMap.put("UPDATE my_table SET attr2 = ? WHERE attr5 = ?", "UPDATE my_table SET attr2 = 'Is it true?' WHERE attr5 = 'What is it?'");

pairMap.forEach((k,v) -> {
    System.out.println("For query: "+k);
    k = k.replaceAll("([*+^$()\\[\\]{}])", "\\\\$1"); // this escapes all the characters that have special meaning in regex so they get treated as literal characters
    k = k.replaceAll("\\?", "(.*)");

    Pattern p = Pattern.compile(k);
    Matcher m = p.matcher(v);
    if (m.matches()) {
        for (int i=0;i<m.groupCount();i++) {
            System.out.println(m.group(i+1));
        }
    } else {
        System.out.println("Didn't match");
    }
    System.out.println();
});

哪些打印,

For query: SELECT * FROM my_table t WHERE (t.attr1 = ? AND t.attr2 = ?) OR t.attr3= ?
3
'str'
4

For query: UPDATE my_table SET attr2 = ? WHERE attr5 = ?
'Is it true?'
'What is it?'

正如您所看到的代码,它适用于查询字符串中占位符 ? 的任何变量值,并打印配对查询中存在的所有值,这些值具有实际值。

【讨论】:

    【解决方案2】:

    这是一个使用基本 Java 正则表达式模式匹配的工作脚本。它通过执行两个匹配来工作。首先,它查找分配给? 位置占位符的每一列/别名。然后,对于每个匹配的列/别名,它使用绑定值对查询字符串进行第二次查找。

    String query1 = "SELECT * FROM my_table t WHERE (t.attr1 = ? AND t.attr2 = ?) OR t.attr3= ?";
    String query2 = "SELECT * FROM my_table t WHERE (t.attr1 = 3 AND t.attr2 = 'str') OR t.attr3= 4";
    
    String p1 = "([\\w.]+)\\s*=\\s*\\?(?=(([^']*'){2})*[^']*$)";
    Pattern r1 = Pattern.compile(p1);
    Matcher m1 = r1.matcher(query1);
    
    // for each matching column/alias with a placeholder
    while (m1.find()) {
        String p2 = m1.group(1) + "\\s*=\\s*([\\w.']+)";
        Pattern r2 = Pattern.compile(p2);
        Matcher m2 = r2.matcher(query2);
    
        // if we find it in the second query string, then print the value
        if (m2.find()) {
            System.out.println("Column: " + m1.group(1) + " has parameter value: " + m2.group(1));
        }
    }
    
    Column: t.attr1 has parameter value: 3
    Column: t.attr2 has parameter value: 'str'
    Column: t.attr3 has parameter value: 4
    

    请注意,我在这里做了一些假设,包括匹配的列只有单词字符 (\w) 加上点,并且匹配的值只涉及单词字符和单引号(对于字符串文字)。上述代码可能会在许多边缘情况下失败,这也取决于您的数据库及其特定语法。我正在为您提出的问题提供一个即时解决方案,并且作为一种可以发挥作用的通用方法。

    【讨论】:

    • 如果其中一个参数中有问号,您的脚本就会中断。 repl.it/@robertwharvey/…
    • @RobertHarvey 我认为您的评论可能是? 可能出现在不同查询的字符串文字中,然后我的脚本会中断。我添加了逻辑,应该防止 ? 作为位置参数。
    • Here is a working demo 表明此边缘情况已得到修复。
    猜你喜欢
    • 1970-01-01
    • 2021-12-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-21
    • 2021-01-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多