我有以下PreparedStatement:
PreparedStatement statement = conn.prepareStatement("Select * from foo
where foo.age ? ? AND foo.children ? ?")
现在解释一下我要做什么,因为我很懒,不喜欢写多个查询。我希望语句在完成时看起来如下:
Select * from foo where foo.age >= 42 AND foo.children <= 3
OR
Select * from foo where foo.age = 42 AND foo.children = 3
如果不清楚我希望能够连续替换多个令牌,其中第一个令牌恰好是限定符(等于,更大,更少等),并且后面的令牌恰好是文字(3,17, “史蒂夫”,等等)。我的问题是这是否可能,如果是这样,如何实现呢?
答案 0 :(得分:4)
您无法执行此操作,因为?
不代表令牌,而是值。显然,一些标记(即文字)代表值,但即使对于这些标记,?
也直接表示值本身,而不是文字 - 也 - 代表 - 值。 (这是设计的一个有意的元素,因为参数化查询的目的是防止参数“泄漏”并被解释为单个值以外的其他东西。)
编辑添加:在我工作的地方,我们有一个自定义框架,它包装了JDBC并处理事务等等,所以我们通常不得不处理直接与PreparedStatement
。该框架有一个看起来像这样的方法:
public <T> Iterator<T> executeQuery(ConverterFromResultSetToT<T> converter,
String query, Map<String, Object> params)
{
// . . . modify query, replacing any instances of $!{paramKey} with the
// corresponding value from params -- this allows arbitrary SQL code
// to be injected, in the rare cases that that's necessary
// . . . modify query, replacing any instances of ${paramKey} with '?' and
// adding the corresponding value from params to an array -- we use
// this much more often
// . . . create PreparedStatement with the resulting query
// . . . set parameters of PreparedStatement from aforemented array
// . . . run PreparedStatement; wrap result in an Iterator<T>; and return
}
但是如果你期望做很多这样的话,我只会推荐那种东西。我们在该框架中投入了大量精力,它非常有用,但它也是很多代码。
值得注意的是,尽管文档可能暗示了这一点,但创建PreparedStatement
的成本并不是很高。除非你真的经常运行相同的查询,否则每次重新创建PreparedStatement
都不是什么大问题。因此,只要您愿意为此编写自己的代码,就不需要内置支持drop-in运算符。
答案 1 :(得分:2)
这不可能。 PreparedSatement
中的参数只能是值,而不是运算符,表名等。
现在,对于上面的特定查询,您可以执行以下操作:
select * from foo where age > ? and age < ?
然后使用42
,400
获得age>=42
年,使用42
,42
获得age = 42
答案 2 :(得分:2)
您可以将解决方法设为:
String query = "Select * from foo where foo.age @ @ AND foo.children @ @";
//write code here to manipulate your query string using
query = query.replaceFirst("@", "=");
query = query.replaceFirst("@", "42");
query = query.replaceFirst("@", "=");
query = query.replaceFirst("@", "3");
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(query );
如果您决定使用上述replaceFirst
,请注意您要分配值from left to right
。
答案 3 :(得分:0)
String firstOperator = ">="
String secondOperator = "<="
PreparedStatement statement = conn.prepareStatement("Select * from foo
where foo.age "+firstOperator+" ? AND foo.children "+secondOperator+" ?");
statement.setInt(1,42);
statement.setInt(2,3);
无论如何,我认为这不是一件非常优雅的事情。 “不写多个查询”似乎不是一个明智的设计目标。