我正在将一个Java应用程序从PostGresSQL转换为Derby(10.10.1.1)。 PG数据库有许多理想将转移到Derby程序的程序。
其中一个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.SQL CallableStatement对象调用,并使用set param值执行以返回ResultSet。
我想将上面的PG过程转换为接受多个Timestamp值的Derby过程,可能使用ANY或IN语句。在有限的搜索中,似乎Derby不支持arrays as dynamic parameters。
使用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 clause alternatives? 我愿意考虑简单地编写动态SQL而不是参数化过程,但真正的查询是相当野蛮的。 :)
答案 0 :(得分:0)
由于没有人提供答案,我发布了解决问题的方法。解决方案是传递一个String变量," 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;
}
解决方案不优雅,但在实践中有效。