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 ResultSet
s after I execute each individually.
答案 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数据库类型混淆。