我正在尝试在我的SQL查询中动态绑定变量,我试图通过java执行。
为此,我使用数据绑定成功构建了以下查询:
select HOST,PORT, VIRTUAL_HOST, CLUSTER from XYZ where TYPE='abc' and NAME=?
但对于像以下的查询:
select HOST, PORT, VIRTUAL_HOST, CLUSTER from PQR where TYPE='abc' and NAME IN (?)
如何为IN语句使用动态绑定? 这里我绑定变量的值是一个带有逗号分隔值的字符串,例如NAME IN(I,J,K)
我已经有一个参数: 字符串temp =“I,J,K”。
答案 0 :(得分:5)
每个元素需要一个问号,ad无法绕过它(除非使用像Spring一样的包装API为你做这个):
String sql = "select HOST, PORT, VIRTUAL_HOST, CLUSTER"
+ " from PQR where TYPE='abc' and NAME IN (?, ?, ?)";
PreparedStatement stmt = connection.prepareStatement(sql);
stmt.setString(1, "I");
stmt.setString(2, "J");
stmt.setString(3, "K");
答案 1 :(得分:2)
您也可以编写自己的解决方法来完成与JDBC中的NamedParameterStatement相同的操作:
public class NamedParameterStatement {
// define the parameter format as a colon followed by at least one word letter
private final String PARAMETER_REGEX =":\\w+";
// the parsed sql query string containing question marks,
// not named parameters
private String sql;
// hashtables for parameter mapping
private Hashtable<String, Integer> parameterNameMap;
private Hashtable<Integer, Object> parameterValueMap;
/**
* constructor for named parameter statements
* @param namedParameterSQL the sql query with named parameters
*/
public NamedParameterStatement(String namedParameterSQL) {
// init hashtables
this.parameterNameMap = new Hashtable<String, Integer>();
this.parameterValueMap = new Hashtable<Integer, Object>();
// create a matcher for the named parameter sql query based on
// the pattern specified for the named parameter format
Matcher m = Pattern.compile(
PARAMETER_REGEX,
Pattern.CASE_INSENSITIVE)
.matcher(namedParameterSQL);
int i = 1;
while(m.find()) {
// watch out: this implementation does not check
// for multiple parameters with the same name.
parameterNameMap.put(m.group().replace(":", ""), i++);
}
// replace all named parameters with question marks
this.sql = m.replaceAll("?");
}
/**
* creates a prepared statement for the specified connection,
* based on the parameter mapping
* @param conn the database connection
* @return a prepared statement
* @throws SQLException thrown on error with preparing the statement
* @throws InvalidBindingException thrown on errors with the parameter binding
*/
public PreparedStatement createPreparedStatement(Connection conn)
throws SQLException, InvalidBindingException {
// check if bindings match
if(parameterNameMap.size() == parameterValueMap.size()) {
// create prepared statement
PreparedStatement ps = conn.prepareStatement(this.sql);
// for each parameter binding, set the parameter and its index accordingly
for(Integer i : this.parameterValueMap.keySet()) {
Object value = this.parameterValueMap.get(i);
// map the parameter object types against the different parameter setters
// this mapping is incomplete!!! just a proof of concept.
if(value.getClass() == String.class) {
ps.setString(i, (String) value);
} else if(value.getClass() == Integer.class || value.getClass() == int.class) {
ps.setInt(i, (int) value);
} else if(value.getClass() == Double.class || value.getClass() == double.class) {
ps.setDouble(i, (double) value);
} else if(value.getClass() == Long.class || value.getClass() == long.class) {
ps.setLong(i, (long) value);
}
}
return ps;
}
else throw new InvalidBindingException("Not all parameters were bound.");
}
/**
* returns the converted prepared statement query string
* @return the query string
*/
public String getSQL() {
return this.sql;
}
/**
* binds a parameter value to a parameter name
* @param parameter the parameter name
* @param value the parameter value
*/
public void bindParameter(String parameter, Object value) {
// check if the parameter name existed in the named parameter query string
if(this.parameterNameMap.containsKey(parameter)) {
this.parameterValueMap.put((Integer)this.parameterNameMap.get(parameter), value);
}
else throw new IllegalArgumentException("Parameter '" + parameter + "' does not exist.");
}
}
用法:
NamedParameterStatement nps = new NamedParameterStatement(
"SELECT * FROM table WHERE column1=:param1 AND column2=:param2");
nps.bindParameter("param1", "value1");
nps.bindParameter("param2", 2);
PreparedStatement ps = nps.createPreparedStatement(conn);
ResultSet results = ps.executeQuery();
while(results.next()) {
System.out.println(results.getString("column1"));
}
我知道,这也不理想,但如果您不想使用JDBC或其他框架(Hibernate,...),它就可以解决问题。
答案 2 :(得分:1)
实际上你可以用这种方式动态地做到这一点:
StringBuilder scmd = new StringBuilder (128);
scmd.append ("SELECT HOST, PORT, VIRTUAL_HOST, CLUSTER ");
scmd.append ("FROM PQR ");
scmd.append ("WHERE TYPE='abc' ");
if (names.length > 0) {
scmd.append ("AND NAME IN (");
for (int i = 0; i < names.length; i++) {
if (i > 0)
scmd.append (',');
scmd.append ('?');
}
scmd.append (")");
}
PreparedStatement stmt = connection.prepareStatement(scmd.toString());
其中names
是一个包含可变数量值的String数组。
然后你可以分配值:
if (names.length > 0) {
for (int i = 0; i < names.length; i++) {
stmt.setString (i + 1, names[i]);
}
}