将元组数组发送到预准备语句

时间:2014-11-26 11:29:45

标签: java sql arrays prepared-statement tuples

我想为这样的请求创建PreparedStatement

SELECT * FROM table WHERE (a, b) in ( (a1, b1), (a2, b2), (a3, b3) );

如何从Java发送[(a1, b1), (a2, b2), (a3, b3)]PreparedStatement或从数组(a1, a2, a3)(b1, b2, b3)创建它?

2 个答案:

答案 0 :(得分:0)

假设您有2个阵列。

int[] tuple_left = int[]{1,2,3,4,5,6};
int[] tuple_right = int[]{1,2,3,4,5,6};

然后,您将生成查询:

if(tuple_left.length == tuple_right.length && tuple_left.length >= 1){
    String placeholders = "";
    for(int i=0; i < tuple_left.length; i++){
        if(i == 0){
            placeholders += "(?,?)";
        }else{
            placeholders += ",(?,?)";
        }
    }

    String sql = "SELECT * FROM table WHERE (a,b) in ("+placeholders+")";

然后,您将准备查询并添加值:

    PreparedStatement ps = ....
    for(int i=0; i < tuple_left.length; i++){
        ps.setInt((2*i)+0,tuple_left[i]);
        ps.setInt((2*i)+1,tuple_right[i]);
    }
    ps.execute();

并且当然处理没有参数或不同长度的情况:

}else{
    //Invalid argument count, throw an exception or handle the error otherwise.
}

编辑:

我用postgresql做了一些测试。从表中选择(a,b)时,它会将其作为类型记录返回。此记录无法与阵列进行比较。 绕过此限制的一种方法是从子查询中选择值。 对于2D数组,我们可以将其作为子查询执行:

SELECT 
  arr[i][1],
  arr[i][2] 
FROM 
   (SELECT
     generate_series(1, array_upper(arr, 1)) AS i, 
     arr 
   FROM (SELECT ARRAY[[1,5],[1,10]] arr) t
   ) t

我们可以在java中执行此操作:

Array arr = con.createArrayOf("int", new Object[][]{{1,2},{4,5},{7,8}});

String sql = "SELECT arr[i][1],arr[i][2]"+
             "FROM ("+
             "  SELECT generate_series(1, array_upper(arr, 1)) AS i, arr"+
             "  FROM (SELECT ? AS arr) t"+
             ") t";

PreparedStatement ps = con.prepareStatement(sql);
ps.setArray(1, arr);


//Full prepared statement:
SELECT * FROM table WHERE (a,b) IN 
(SELECT 
  arr[i][1],arr[i][2]
 FROM
   SELECT generate_series(1, array_upper(arr, 1)) AS i, arr
   FROM (SELECT ? AS arr) t
 ) t)

使用2个数组A和B(分别代表(a1,a2,a3)和(b1,b2,b3))我们可以做同样的事情,除了选择A [row],B [row]。 示例代码:

Array arr_a = con.createArrayOf("int", new Object[]{1,4,7});
Array arr_b = con.createArrayOf("int", new Object[]{2,5,9});

String sql =     
    "SELECT A[i],B[i]"+
    "FROM ("+
    "  SELECT generate_series(1, array_upper(A, 1)) AS i, A, B"+
    "  FROM (SELECT ? AS A, ? AS B) t"+
    ") t";

PreparedStatement ps = con.prepareStatement(sql);
ps.setArray(1, arr_a);
ps.setArray(2, arr_b);

ps.execute();
ResultSet rs = ps.getResultSet();
while(rs.next()){
        System.out.println("Row: " + rs.getInt(1) + " - " + rs.getInt(2));
}

这种情况下的输出是:

Row: 1 - 2
Row: 4 - 5
Row: 7 - 9

答案 1 :(得分:0)

试试这个:

select blah from blam where hoot in (?)

然后按如下方式构建一个参数:

int[] leftArray = {1, 2, 3};
int[] rightArray = {7, 9, 11};
StringBuilder buffer = new StringBuilder();
for (int index = 0; index < leftArray.length; ++index)
{
    if (index > 0)
    {
        buffer.append(',');
    }

    buffer.append('(');
    buffer.append(leftArray[index]);
    buffer.append(',');
    buffer.append(rightArray[index]);
    buffer.append(')');
}

最后,使用缓冲区中的值作为预准备语句的参数。