0

I have the following PreparedStatement:

  PreparedStatement statement = conn.prepareStatement("Select * from foo 
          where foo.age ? ? AND foo.children ? ?")

Now to explain what I am looking to do, because I am lazy and don't like writing multiple queries. I want the statement to look like the following when finished:

Select * from foo where foo.age >= 42 AND foo.children <= 3

OR

Select * from foo where foo.age = 42 AND foo.children = 3

If it isn't clear I want to be able to substitute multiple tokens in a row, where the first token happens to be a qualifier (equals,greater,less,etc) and the token following it happens to be a literal (3,17,"Steve",etc). My question is is this possible and if so how can this be accomplished?

4

4 回答 4

4

你不能这样做,因为?它不代表一个token,而是一个value。显然,一些标记(即文字)表示值,但即使对于这些,?直接表示值本身,而不是文字也表示值。(这是设计的一个有意元素,因为参数化查询的真正目的是防止参数“泄漏”并被解释为单个值以外的东西。)


编辑补充:在我工作的地方,我们有一个自定义框架,它围绕着 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
}

但是,如果您希望做很多这样的事情,我只会推荐这种事情。我们在这个框架上付出了很多努力,它非常有用,但它也有很多代码。


值得注意的是,尽管文档可能暗示,创建 a 的成本PreparedStatement并不是很高。除非您确实多次运行相同的查询,否则PreparedStatement每次都重新创建它并不是什么大问题。因此,只要您愿意为此编写自己的代码,您实际上并不需要对插入式运算符的内置支持。

于 2012-10-10T19:20:05.910 回答
2

这是无法做到的。a 中的参数PreparedSatement只能是值,不能是运算符、表名等。

现在,对于上面的特定查询,您可以执行以下操作:

select * from foo where age > ? and age < ? 

然后有了42400你得到age>=42了年,有了4242你得到了age = 42

于 2012-10-10T19:19:01.687 回答
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按上述方式使用,请注意您正在分配 valuefrom left to right

于 2012-10-10T19:23:33.830 回答
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);

无论如何,我认为这不是一件非常优雅的事情。“不写多个查询”似乎不是一个明智的设计目标。

于 2012-10-10T19:34:53.593 回答