如何将多个时间戳作为动态参数传递给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"