我想创建一个 JDBC 准备语句,例如:
SELECT URL,LOCATE ( '?', URL ) pos FROM Links WHERE pageId=? ORDER BY pos ASC
其中第一个
?
是文字,第二个 ?
是参数。我可以使用 CHAR(63)
代替 '?'
但我认为额外的函数调用会减慢 SQL 执行速度。有什么办法可以逃脱第一个?
吗?
编辑:
以下代码测试 dkatzel 的断言,即字符串中的
?
字符不被视为标记:
public class Test {
public static void main(String[] args) throws SQLException {
Connection conn = DriverManager.getConnection("jdbc:h2:mem:test");
Statement stmt = conn.createStatement();
stmt.executeUpdate("CREATE TABLE Links(URL VARCHAR(255) PRIMARY KEY,pageId BIGINT)");
stmt.executeUpdate("INSERT INTO Links(URL,pageId) VALUES('http://foo.bar?baz',1)");
stmt.executeUpdate("INSERT INTO Links(URL,pageId) VALUES('http://foo.bar/baz',1)");
stmt.close();
PreparedStatement ps = conn
.prepareStatement("SELECT URL,LOCATE ( '?', URL ) pos FROM Links WHERE pageId=? ORDER BY pos ASC");
ps.setLong(1, 1);
ResultSet rs = ps.executeQuery();
while (rs.next()) {
System.out.println(rs.getString(1) + ":" + rs.getInt(2));
}
rs.close();
ps.close();
conn.close();
}
}
输出:
http://foo.bar/baz:0
http://foo.bar?baz:15
看来 dkatzel 是正确的。我搜索了 JDBC Spec,但没有找到任何提及如果
?
参数标记在引号内,则该参数标记将被忽略,但我发现了几个PreparedStatement 解析器的实现(MySql、c-JDBC、 H2)似乎都排除了单引号内的文本作为参数标记。
根据您使用的 JDBC 驱动程序,您可能可以通过添加另一个问号来转义,例如如果您使用 PostgreSQL
来自使用Statement或PreparedStatement接口:
在 JDBC 中,问号 (
) 是位置占位符?
的参数。然而,有一些 包含问号的 PostgreSQL® 运算符。为了保持这样的 SQL 语句中的问号被解释为 位置参数,使用两个问号(PreparedStatement
)作为转义 顺序。您还可以在??
中使用此转义序列,但是 这不是必需的。具体来说,仅在Statement
单个 (Statement
) 可用作运算符。?
如果它不适用于您的 JDBC 驱动程序,您可以将其绑定为
String
?
,
ps.setString(1, "?");
?
的含义在SQL规范中指定,对此,JDBC规范遵循SQL规范。
驱动程序不会(也不应该)将文字中的问号解释为参数占位符,因为字符串文字中的问号只是字符串文字中的一个字符。有关详细信息,请参阅 SQL:2011 Foundation (ISO-9075-2:2011) 的第 5 章。
所以逃避是没有必要(也不可能)的。
然而,这只是理论,不幸的是,在实践中它并不像 PostgreSQL JDBC 驱动程序那样工作。为了解决这个问题,最新版本的 PostgreSQL 驱动程序提供了一个选项,可以使用
??
来转义不是参数占位符的问号。
你尝试过吗?我认为引用问号是可以的。在准备好的声明中只有“裸”问号应该被替换
CHR(63)
,这有助于解决我的问题。 (十进制 63 是 ASCII 中的问号。)
以下是我所做的示例:
select q'[<div id=['|"]TRD_%%GEN%%['|"].*]' || chr(63) || q'[</div>]' from dual;
这有助于将字符串获取为:
<div id=['|"]TRD_%%GEN%%['|"].*?</div>
然后我在插入语句中使用了这个查询,并运行了PreparedStatement。工作得很好。
CHR 函数是一个内置函数,可以像其他 Oracle 函数一样使用。如果您知道查询不会重复很多次,则可以使用此功能。