如何使用数组列表为查询创建动态 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);
备注:
- 某些 security/quality 工具可能会报告 SQL 问题,因为您正在编写动态 SQL。
- Oracle 限制每个 IN 1000 个元素。您必须对每组 1000 个(或更少)类别进行分区。
- 我以一种或多或少奇怪的方式使用了
stream()
来生成“?”。如果你使用commons-lang3,你可以将它替换为"(" + StringUtils.repeat("?", ", ", categories.size()) + ")"
(javadoc中的示例可能就是这样使用的)。
- 如果您只有类别作为单一标准,您可能会删除
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);
我有一个类别列表
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);
备注:
- 某些 security/quality 工具可能会报告 SQL 问题,因为您正在编写动态 SQL。
- Oracle 限制每个 IN 1000 个元素。您必须对每组 1000 个(或更少)类别进行分区。
- 我以一种或多或少奇怪的方式使用了
stream()
来生成“?”。如果你使用commons-lang3,你可以将它替换为"(" + StringUtils.repeat("?", ", ", categories.size()) + ")"
(javadoc中的示例可能就是这样使用的)。 - 如果您只有类别作为单一标准,您可能会删除
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);