我正在使用Java预处理语句从Oracle数据库获取数据。由于某些性能问题,查询使用“虚拟列”作为索引。
查询如下所示:
String status = "processed";
String customerId = 123;
String query = "SELECT DISTINCT trans_id FROM trans WHERE status = " + status + " AND FN_GET_CUST_ID(trans.trans_id) = " + customerId;
Connection conn = getConnection();
PreparedStatement ps = null;
ResultSet rs = null;
try {
ps = conn.prepareStatement(query);
ps.execute();
...
} catch (...)
这不起作用。将该函数作为where子句的一部分会导致SQLException。我知道CallableStatement,并知道我可以先使用它然后连接结果。但是,此表使用FN_GET_CUST_ID(trans_id)作为其索引的一部分。有没有办法使用带有数据库函数的预准备语句作为查询参数?
答案 0 :(得分:6)
永远不要将SQL的参数连接到String中。始终使用占位符(?
)和setXxx(column, value);
。
如果您在自己喜欢的数据库工具中运行SQL,则会收到相同的错误。问题是Oracle出于某种原因无法使用该功能。你得到什么错误代码?
答案 1 :(得分:1)
如果客户ID是数字,请保留int而不是String。然后尝试执行以下操作:
String query = "SELECT DISTINCT trans_id FROM trans WHERE status = ? AND FN_GET_CUST_ID(trans.trans_id) = ?";
ps = conn.prepareStatement(query);
ps.setString(1, status);
ps.setInt(2, customerId);
ps.execute();
除了预处理语句的其他好处之外,您不必记住字符串引用(这最有可能导致错误)并转义特殊字符。
答案 2 :(得分:0)
乍一看,查询似乎不正确。在使用status
变量之前和之后,您缺少一个撇号(假设状态是varchar列)。
String query = "SELECT DISTINCT trans_id FROM trans
WHERE status = '" + status + "' AND FN_GET_CUST_ID(trans.trans_id) = " + customerId;
编辑:我不是来自java背景。但是,正如@Aron所说,最好使用占位符&然后使用某种方法设置参数值以避免SQL Injection。