Postgres SQL in子句和setArray()

时间:2013-05-21 03:13:04

标签: java postgresql jdbc

我正在使用Java 1.7和JDBC 4以及Postgres。我试图使用带有数组的PreparedStatement来填充SQL in子句。但是,生成的SQL似乎有“{”和“}”。这是代码:

PreparedStatement ptmt = 
      connection.prepareStatement("select * from foo where id in (?)");
String[] values = new String[3];
values[0] = "a";
values[1] = "b";
values[2] = "c";
ptmt.setArray(1, connection.createArrayOf("text", values));

生成的SQL如下所示:

select * from foo where id in ('{"a","b","c"}')
其中,无法正常工作。这应该是它的样子:

select * from foo where id in ("a","b","c")

select * from foo where id in ('a','b','c')

我在这里缺少什么?

4 个答案:

答案 0 :(得分:4)

当您的数据库字段的类型为array时,您可以使用PreparedStatement.setArray()将数组发送到查询。但是,在你的情况下,它不是一个真正的数组,而是一个变量no参数,你不能这样做。即。

PreparedStatement ptmt =  connection.prepareStatement("select * from foo where id in (?)");

只能使用一个参数。如果要传递3个参数,则必须执行

PreparedStatement ptmt =  connection.prepareStatement("select * from foo where id in (?, ?, ?)");

ptmt.setString(n, "String")三次。

如果你的参数不是常数,那么动态构造查询,但是你失去了效率。

答案 1 :(得分:3)

PostgreSQL有几个array capabilities可以处理这种情况。

首先是自8.4以来可用的不需要的功能。有点笨拙,但有效。

select * from foo where id in (SELECT * FROM unnest(?));

接下来是数组交集运算符。

select * from foo where ARRAY[id] && ?;

将列值转换为具有单个元素的数组,然后检查与您设置为参数的数组的交集。

据我所知,这些在功能上是等价的,但我没有检查哪些可能更高效。

答案 2 :(得分:1)

我认为这是PgJDBC问题。它应该是使用显式强制转换编写数组构造函数或数组文字,例如:

select * from foo where id in (ARRAY['a','b','c'])

select * from foo where id in ('{"a","b","c"}'::text[])

作为一种解决方法,您应该能够写下:

"select * from foo where id in ( (?)::text[] )"

..虽然我没有测试过验证。

请考虑将此作为PgJDBC的单元测试,并通过github将其作为错误报告提交给PgJDBC项目。看看现有的单元测试是如何工作的,只需添加另一个。这都是非常简单的JUnit。

答案 3 :(得分:0)

使用= ANY子查询表达式。

PreparedStatement ptmt = connection.prepareStatement("select * from foo where id = ANY(?)");
String[] values = new String[]{"a","b","c"};
ptmt.setArray(1, connection.createArrayOf("text", values));

如果您需要在查询中强制使用类型,可以执行以下操作。

select * from foo where id = ANY(?::text[])

PostgreSQL documentation有更多详细信息。此代码段值得注意:

  

SOME是ANY的同义词。 IN等于= ANY。