如何使用数组列表为查询创建动态 WHERE 子句

How to create a dynamic WHERE clause for a query using an array list

我有一个类别列表,对于每个类别,我想通过结合 AND 运算符将它们添加到我的 WHERE 子句中,例如:
SELECT question_id FROM question WHERE category = categ1 AND category = categ2 AND category = ...

由于类别列表的大小正在改变,我不能这样做:

String sql = "SELECT question_id FROM question WHERE category = ? AND category = ?";
jdbcTemplate.query(sql, stringMapper, "categ1", "categ2");

我怎样才能达到我想要的?

要么检查 JDBC 来自 Spring 的模板是否使用类似于(来自 doc 的语法为您处理该模板,我认为它不会)

SELECT question_id FROM question WHERE category in (?...)

或者针对可能出现的问题编写自己的查询:

List<Object> parameters = new ArrayList<>(categories.size());
StringBuilder sb = new StringBuilde("SELECT question_id FROM question WHERE 1=1");
if (!categories.isEmpty()) {
  if (categories.size() == 1) {
    sb.append(" and category = ?");
  } else {
    sb.append(" and category in ");
    sb.append(categories.stream()
                        .map(ignored -> "?")
                        .collect(joining(", ", "(", ")")));                      
    sb.append(")"); 
  }
  parameters.addAll(categories);
}
Object[] paramArray = parameters.toArray();
jdbcTemplate.query(sb.toString(), stringMapper, paramArray);

备注:

  1. 某些 security/quality 工具可能会报告 SQL 问题,因为您正在编写动态 SQL。
  2. Oracle 限制每个 IN 1000 个元素。您必须对每组 1000 个(或更少)类别进行分区。
  3. 我以一种或多或少奇怪的方式使用了 stream() 来生成“?”。如果你使用commons-lang3,你可以将它替换为"(" + StringUtils.repeat("?", ", ", categories.size()) + ")"(javadoc中的示例可能就是这样使用的)。
  4. 如果您只有类别作为单一标准,您可能会删除 1=1 以及 and

我相信这对你有用:

// The SQL Query
String sql = "SELECT question_id FROM question";
    
// Create the WHERE clause based on the number of items in List...
StringBuilder whereClause = new StringBuilder(" WHERE ");
StringBuilder ps = new StringBuilder("");
for (int i = 0; i < categories.size(); i++) {
    if (!ps.toString().isEmpty()) {
        ps.append(" AND ");
    }
    ps.append("category = ?");
}
whereClause.append(ps.toString()).append(";");
    
//Append the WHERE clause string to the SQL query string
sql = sql + whereClause.toString();
//System.out.println(sql);
    
/* Convert the categories List to an Object[] Array so as to
   pass in as varArgs to the jdbcTemplate.query() method. */
Object[] psArgs = categories.toArray(new Object[categories.size()]);
jdbcTemplate.query(sql, stringMapper, psArgs);