Efficient way to select data with a single condition

时间:2015-06-30 19:22:09

标签: java sql arrays database select

Is there an efficient way to obtain a list (preferably an array, a ResultSet will do) to SELECT a lot of rows.

For example:

Connection con = DriverManager.getConnection(host,username,password);
String sql = "SELECT * FROM table_name WHERE food = ? AND expiration > ?";
PreparedStatement stmt = con.prepareStatement(sql);

Using the above code, I want to get all the food from a given array that isn't expired.

String[] foodList  = {"banana","apple","orange",...}

where the expiration date is a constant date (lets say 3 days ago). However, the way I have it is that the String and PreparedStatement are in a for loop that loop the number of foods in the array to individually check the expiration date. This creates a lot of ResultSets after I execute each individually.

2 个答案:

答案 0 :(得分:2)

可能不是最优雅的解决方案,并且您不会从准备好的语句中获得任何性能优势(但您将获得参数绑定):

StringBuilder sql = new StringBuilder("SELECT * FROM table_name WHERE expiration > ? AND food IN (");

for (int i = 0; i < foodList.length; i++) {
    if (i > 0) {
        sql.append(',');
    }
    sql.append('?');
}

sql.append(")");

Connection con = DriverManager.getConnection(host, username, password);
PreparedStatement stmt = con.prepareStatement(sql.toString());

stmt.setDate(1, expirationDate);
for (int i = 0; i < foodList.length; i++) {
    stmt.setString(i + 2, foodList[i]);
}

ResultSet rs = stmt.executeQuery();

/* ... Do Stuff ... */

答案 1 :(得分:2)

大多数SQL数据库都支持IN (list)表达式。这大致相当于提供一个或表达式:

SELECT id FROM table WHERE food IN ('Apple', 'Banana')  AND exp < ?

类似于

SELECT id FROM table WHERE (food = 'Apple' or food = 'Banana') AND exp < ?

在这两种情况下,一些RDBMS都可以对其进行优化。

但是,首先,您可以在IN中指定的列表项数量或您可以在语句中使用的字符数限制。因此,如果您的列表可以变长,则需要准备好运行多个语句。

其次,您不能将数组设置为PreparedStatement的参数,并期望它与IN一起使用。

不幸的是,在纯JDBC中,你所能做的就是连接一个String。这是不赞成的,但是没有好的选择(除非你想做一些事情,比如将食物列表作为单个列表并使用&#34; instring&#34;表达式)。

确保添加尽可能多的?(但不要太多)您期望的参数,然后在IN中设置它们:

String[] foods = ...;
int remain = foods.length;
int start = 0;
while(remain > 0)
{  if (remain >= 100)
     executeBatch(foods, start, 100); start+=100; remain-=100;
   else if (remain >= 30)
     executeBatch(foods, start, 30); start+=30; remain-=30;
   else {
     executeBatch(foods, start, 1); start+=1; remain-=1;
   }
}


void executeBatch(String[] f, int off, int len)
{
    StringBuilder sqlBuf = StringBuilder("... IN(");
    for(int i=0;i<len;i++) {
        sqlBuf.append((i!=0)?",?":"?");
    }
    String sql = sqlBuf.append(") AND exp < ?").toString();
    PreparedStatement ps = c.prepareStatement(sql);
    for(int i=0;i<foods.length;i++)
        ps.setString(i+1, foods[i+off]);
    ps.setTimestamp(foods.length+1, now);
    ....
}

这样可以避免生成大量不同的SQL语句进行编译。 (只有100,30或1?))。您可以对OR案例使用相同的逻辑。

*不要与ARRAY数据库类型混淆。