如何将多个时间戳作为动态参数传递给Derby查询?
我将Java应用程序从PostgreSQL转换为Derby(10.10.1.1)。 PG数据库有许多程序,理想情况下将转移到德比程序。
其中一个PG存储过程传递一个Timestamps数组,类似于这个Procedure / SQL:
CREATE FUNCTION getDownloads(_download_array timestamp without time zone[])
LANGUAGE plpgsql AS $$
DECLARE mycurs refcursor;
BEGIN
SELECT * FROM download_time d
WHERE d.downloadtime = ANY(_download_array);
END
RETURN mycurs;
Derby过程基本上是引用包含公共静态Java方法的过程类的声明。 这些方法通常使用java.SQL PreparedStatement对象,并可能包含动态参数。 该过程通过java.ql CallableStatement对象调用,并设置参数值,并返回ResultSet。
我想将上面的PG过程转换成接受多个时间戳值的Derby过程,可能使用ANY或IN语句。 在有限的搜索中,似乎Derby不支持将数组作为动态参数。
使用Squirrel SQL客户端,该语法证明是可以接受的:
SELECT * FROM download_time d
WHERE d.downloadtime
IN('2011-11-13 13:24:00.0', '2011-11-13 13:28:00.0', '2014-05-06 07:08:09.0')
但实际上,将逗号分隔的时间戳传递给IN或ANY语句不起作用,下面是伪代码:
try {
Connection conn = getConnection();
CallableStatement cstmt = null;
cstmt = conn.prepareCall("{ call getDownloads(?) }");
cstmt.setTimestamp(3, "'2011-11-13 13:24:00.0', '2011-11-13 13:28:00.0'");
//Also tried this:
cstmt.setString(3, "2011-11-13 13:24:00.0, 2011-11-13 13:28:00.0");
cstmt.execute();
rs = cstmt.getResultSet();
while (null != rs && rs.next()) {
...
}
} catch (SQLException sqle) {
...handle errors
}
遵循上述示例,会发生此错误:
值java.sql.SQLException:
日期/时间值的字符串表示形式的语法不正确。
我正在寻找替代方法,并且正在考虑在一篇关于StackOverflow,PreparedStatement IN子句替代方案的优秀文章中找到的解决方案? 我会愿意考虑简单地写动态SQL而不是参数化过程,但真正的查询是相当麻烦的。 :)
由于没有人提供答案,我正在发布我的问题解决方案。 解决方案是传递一个字符串变量,“downloadTimes”包含逗号分隔格式的连接日期/时间。 为简洁起见,排除了NULL检查条件。 如果传递一个NULL,那么该行就被排除了。
程序如下:
public static void getDownloads(int theId, String downloadTimes, ResultSet[] rs)
throws SQLException {
String DML = null;
PreparedStatement ps = null;
DML = "SELECT d.* FROM download_time d WHERE d.id = ? " +
"AND d.downloadtime IN(" + downloadTimes + ") " : "") + //Add chk null condition
"ORDER BY 1, 2 DESC, 3 ";
ps = conn.prepareStatement(DML);
ps.setInt(1, theId);
rs[0] = ps.executeQuery();
}
请注意,“getDownloads”过程在Derby中稍后在同一个类中声明(请参阅我的原始问题中的声明),为简单起见而省略。 该过程由不同类中的方法调用:
public Map<GregorianCalendar, List<Fault>> getDownloadFaultList(
Integer theId, String subsystem, List<GregorianCalendar> downloadTimes) {
CallableStatement cstmt = null;
ResultSet rs = null;
String downloadCalListToCsv = null;
// parseGregorianCalListToCsv() creates a CSV string out of dates.
// I.e., "2011-11-13 13:24:00.0, 2011-11-13 13:28:00.0"
if (false == downloadTimes.isEmpty()) {
downloadCalListToCsv = DataTypeConverter
.parseGregorianCalListToCsv(downloadTimes, timestampFormat);
}
try {
cstmt = getConn().prepareCall("{ call getDownloads(?, ?) }");
// Register the parameters
cstmt.setInt(1, theId);
// Get timezone from first entry, assuming all same timezone
if (! downloadTimes.isEmpty()) {
cal.setTimeZone(downloadTimes.get(0).getTimeZone());
}
cstmt.setString(2, downloadCalListToCsv);
cstmt.execute();
rs = cstmt.getResultSet();
while (null != rs && rs.next()) {
//Use the download timestamps here
}
} catch (SQLException sqle) {
//error handling here
} finally {
//Close resources
close(rs, cstmt);
}
return faultMap;
}
该解决方案不够优雅,但在实践中可行。
链接地址: http://www.djcxy.com/p/74419.html上一篇: How to Pass Multiple Timestamps as Dynamic Parameters into a Derby Query?
下一篇: JDBC, DBCP and SQL Server "Lock request time out period exceeded"